【发布时间】:2013-05-09 08:09:07
【问题描述】:
我正在尝试做一些编程,但我无法进入 monad。我在 IO 功能方面进步了一点,但现在我肯定迷路了……
我有一个从网络加载的 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
现在我尝试将这两者结合起来接受一个 IO 字符串并返回一个“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)
有人知道如何解决这个问题吗?还是我完全迷路了,haskell 以另一种方式做到了这一点?谢谢你的回答。
【问题讨论】:
-
在这里定义一个带有
IO String参数的函数是错误的。IO String不是包裹在某些东西中的字符串,它是一个返回字符串的 procedure。例如,绑定它两次会从网络加载它两次。您通常不会编写将IO something作为参数的函数,除非您正在编写某种控制结构。我认为如果你寻求帮助来编写你想要调用它的代码会更好。 -
我真的只是 Haskell 的初学者,老实说,我不喜欢它的懒惰。我知道类似函数的行为。我不喜欢非常具体的主题,基本上我需要从 Internet 加载一个 XML,对其进行处理,然后根据结果我将加载另一个 XML。但是,我确实想将任务拆分为更多函数,因此我想使用 IO 输入来实现这些方法(因为最内部函数返回 IO,我无法摆脱它)。那么,有一个单独的
do来处理输入、包装 IO 并正常调用其他函数会更好吗? -
是的。保持尽可能多的代码纯净。它既更易于使用和理解,也更易于在解释器中测试您的函数。
-
非常感谢您的提示。