[英]A Haskell function of type: IO String-> String
我在 Haskell 中编写了一堆代码来创建文本索引。 顶部函数如下所示:
index :: String -> [(String, [Integer])]
index a = [...]
现在我想给这个函数一个从文件中读取的字符串:
index readFile "input.txt"
这是行不通的,因为 readFile 的类型是 FilePath -> IO String。
无法将预期类型“字符串”与推断类型“IO 字符串”匹配
我看到错误,但我找不到任何类型的函数:
IO String -> String
我想成功的关键在于一些 Monads 下的某个地方,但我找不到解决问题的方法。
您可以轻松编写一个调用 readFile 操作的函数,并将结果传递给您的索引函数。
readAndIndex fileName = do
text <- readFile fileName
return $ index text
但是,IO monad 会污染使用它的所有内容,因此该函数具有以下类型:
readAndIndex :: FilePath -> IO [(String, [Integer])]
没有这样的功能是有充分理由的。
Haskell 有函数纯度的概念。 这意味着当使用相同的参数调用时,函数将始终返回相同的结果。 唯一允许 IO 的地方是在 IO monad 内部。
如果有*一个函数
index :: IO String -> String
然后我们可以通过调用突然在任何地方执行 IO 操作,例如:
index (launchMissiles >> deleteRoot >> return "PWNd!")
函数纯度是我们不想失去的一个非常有用的特性,因为它允许编译器更自由地重新排序和内联函数,它们可以在不改变语义的情况下被触发到不同的内核,它也给了程序员一种感觉安全性,因为如果你能从它的类型中知道一个函数可以做什么和不能做什么。
*其实有这样的功能。 它被称为unsafePerformIO
并且有非常非常好的理由。 除非您 100% 确定自己在做什么,否则不要使用它!
好吧,您无法摆脱IO String
的IO
monad 部分。 这意味着你必须让你的函数返回IO [(String, [Integer])]
。
我建议学习更多关于 monad 的知识,但现在你可以使用liftM
函数:
liftM index (readFile "input.txt")
liftM
有这个签名:
liftM :: Monad m => (a -> b) -> m a -> m b
它接受一个非一元函数并将其转换为一元函数。
fmap index $ readFile "input.txt"
或者
readFile "input.txt" >>= return . index
你可能想研究 monad 和 functors
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.