2013-05-14 169 views
0

我正在嘗試做一些編程,我無法進入單子。我已經提前了一點IO功能,但現在我肯定輸了...哈斯克爾monad返回類型

我有一個從網絡加載的XML字符串(所以它「存儲」在IO String)。因此,我需要一個do塊來加載到普通字符串。

foo :: IO String -> Nothing 
foo xmlio = do 
    xmlio <- xml 
    -- do some magic 

我已經實現了另一個接受純字符串並返回純XML元素的函數。它做得更多一些,但讓我們簡化一下,因爲這個問題並不重要。

import Text.XML.Light 
import Text.XML.Light.Input 

toxml :: String -> Maybe Element 
toxml s = parseXMLDoc s 

現在,我想這兩個結合起來,接受一個I​​O String,並返回一個「IO元素」。

toxmlio :: IO String -> ??? Maybe Element 
toxmlio s = do 
    pures <- s 
    let toReturn = parseXMLDoc s 
    return s 

返回函數的類型是(根據ghci中):

let foo = "<foo>bar</foo>" 
:t return (parseXMLDoc foo) 
    >> return (parseXMLDoc foo) :: Monad m => m (Maybe Element) 

但是,如果我改變我的函數的頭

toxmlio :: IO String -> Monad (Maybe Element) 
toxmlio s = do 
    pures <- s 
    let toReturn = parseXMLDoc s 
    return s 

我得到一個編譯錯誤

Kind mis-match 
The first argument of `Monad' should have kind `* -> *', 
but `Maybe Element' has kind `*' 
In the type signature for `xmlio': 
    xmlio :: String -> Monad (Maybe Element) 

有沒有人有任何想法如何解決這個問題?或者我完全失去了,哈斯克爾以另一種方式做到了這一點?謝謝您的回答。

+1

定義一個採用'IO String'參數的函數是錯誤的事情這裏。一個'IO字符串'不是一個包含在某些東西中的字符串,它是一個返回一個字符串的_procedure_。例如,綁定兩次將從網絡加載兩次。除非你正在編寫某種控制結構,否則通常不會編寫以'IO something'作爲參數的函數。我認爲如果你需要幫助編寫你想要調用的代碼,那就更好了。 – hammar

+0

我真的只是哈斯克爾的初學者,說實話,我不喜歡它的懶惰。 我知道類似功能的行爲。我不喜歡對這個主題進行非常具體的描述,基本上我需要從Internet加載一個XML,對它進行處理並根據結果加載另一個XML。 但是,我確實想將任務分解爲更多的功能,因此我想使用IO輸入來實現這些方法(因爲大多數內部函數返回IO而我無法擺脫它)。那麼,最好有一個處理輸入的'do',包裝IO並正常調用其他函數? – Danstahr

+0

是的。保持儘可能多的純代碼。這與工作和理解相比更容易,而且它還使得在解釋器中測試你的函數變得更加容易。 – hammar

回答

3

它看起來像你想:

toxmlio :: IO String -> IO (Maybe Element) 
toxmlio s = do 
    pures <- s 
    let toReturn = parseXMLDoc pures 
    return toReturn 

但是你可以使用liftM

toxmlio :: IO String -> IO (Maybe Element) 
toxmlio = liftM parseXMLDoc 

你可以使其更加普遍,因爲liftM不依賴於特定的單子類型:

toxmlio :: Monad m => m String -> m (Maybe Element) 
toxmlio = liftM parseXMLDoc 
+0

謝謝你的回答,這個解決方案很有用,但我寧願遵循哈馬爾的建議。無論如何,我接受這個答案。 – Danstahr