我在Haskell中编写了一堆代码来创建文本索引。 top函数如下所示:
index :: String -> [(String, [Integer])]
index a = [...]
现在我想给这个函数一个从文件读取的字符串:
index readFile "input.txt"
这不起作用,因为readFile的类型为FilePath - > IO字符串。
无法匹配预期类型'String' 反对推断类型'IO String'
我看到了错误,但我找不到任何类型的函数:
IO String -> String
我认为成功的关键在某些Monads下,但我找不到解决问题的方法。
答案 0 :(得分:40)
您可以轻松编写一个调用readFile操作的函数,并将结果传递给索引函数。
readAndIndex fileName = do
text <- readFile fileName
return $ index text
但是,IO monad会污染使用它的所有内容,因此该函数的类型为:
readAndIndex :: FilePath -> IO [(String, [Integer])]
答案 1 :(得分:27)
有一个很好的理由说明没有这样的功能。
Haskell具有功能纯度的概念。这意味着当使用相同的参数调用时,函数将始终返回相同的结果。允许IO的唯一位置在IO monad内。
如果有*功能
index :: IO String -> String
然后我们可以通过调用突然在任何地方执行IO动作,例如:
index (launchMissiles >> deleteRoot >> return "PWNd!")
功能纯度是一个非常有用的功能,我们不想丢失,因为它允许编译器更自由地重新排序和内联函数,它们可以在不改变语义的情况下引发到不同的核心,并且它还给出了程序员有一种安全感,因为如果你能知道一个函数可以做什么,也不能从它的类型中做到。
*实际上是这样的功能。它被称为unsafePerformIO
,它被称为非常非常的好理由。 除非你100%确定自己在做什么,否则不要使用它!
答案 2 :(得分:15)
嗯,你无法摆脱IO
的{{1}} monad部分。这意味着您必须让函数返回IO String
。
我建议您详细了解monad,但现在您可以使用IO [(String, [Integer])]
函数:
liftM
liftM index (readFile "input.txt")
有这个签名:
liftM
它需要一个非monadic函数并将其转换为monadic函数。
答案 3 :(得分:8)
fmap index $ readFile "input.txt"
或
readFile "input.txt" >>= return . index
您可能需要查看monad和functors