一个Haskelltypes的函数:IO String-> String

我在Haskell中编写了一堆代码来创build一个文本索引。 顶层函数如下所示:

index :: String -> [(String, [Integer])] index a = [...] 

现在我想给这个函数从文件中读取一个string:

 index readFile "input.txt" 

这将不起作用,因为readFile的types是FilePath – > IO String。

无法匹配预期types“string”对推断types“IOstring”

我看到错误,但我找不到任何types的函数:

 IO String -> String 

我想成功的关键在于某些Monad下的某个地方,但是我找不到解决问题的办法。

你可以很容易地编写一个调用readFile动作的函数,并将结果传递给你的索引函数。

 readAndIndex fileName = do text <- readFile fileName return $ index text 

但是,IO monad会污染使用它的所有东西,所以这个函数的types是:

 readAndIndex :: FilePath -> IO [(String, [Integer])] 

为什么没有这样的function有一个很好的理由。

Haskell具有function纯度的概念。 这意味着一个函数在调用相同的参数时总是返回相同的结果。 IO的唯一允许位置是IO monad。

如果有*function

 index :: IO String -> String 

那么我们可以通过调用突然间在任何地方执行IO操作,例如:

 index (launchMissiles >> deleteRoot >> return "PWNd!") 

function纯度是一个非常有用的function,我们不想丢失,因为它允许编译器更自由地对函数进行重新sorting和内联,可以在不改变语义的情况下将它们引发到不同的内核,同时也给程序员一个感觉因为如果你可以知道一个函数可以做什么,不能从它的types。

*其实有这样的function。 这就是所谓的unsafePerformIO ,这是非常非常好的原因。 除非你100%确定自己在做什么,否则不要使用它!

那么你不能摆脱IO StringIO monad部分。 这意味着你将不得不让你的函数返回IO [(String, [Integer])]

我build议学习更多单子,但是现在你可以用liftM函数去掉:

 liftM index (readFile "input.txt") 

liftM有这个签名:

 liftM :: Monad m => (a -> b) -> ma -> mb 

它采用非一元函数并将其转换为一元函数。

 fmap index $ readFile "input.txt" 

要么

 readFile "input.txt" >>= return . index 

你可能想看看monad和函子