繁体   English   中英

一个 Haskell 函数类型:IO String-> String

[英]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 StringIO 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM