无法将类型IO与Map匹配,并且无法匹配类型Map与[Char]

时间:2017-02-26 21:37:07

标签: haskell types

我是Haskell的新手,下面的代码给了我两个错误:

import Control.Monad
import Control.Applicative
import System.IO
import qualified Data.Map as Map
import Data.Maybe

main = do
    return ()

getPhonebook :: Int -> (Map.Map String String)
getPhonebook n
    | n == 0 = Map.empty
    | otherwise = do
        line <- getLine
        let split = words line
        return (Map.insert (split !! 0) (split !! 1) (getPhonebook (n-1)))

第一个错误出现在line <- getLine行上。错误说Couldn't match type ‘IO’ with ‘Map.Map String’。我不明白这个错误,可能是一个愚蠢的错误。

第二个错误发生在返回行。它显示Couldn't match type ‘Map.Map String String’ with ‘[Char]’,预期类型为[Char]。我不明白这个,因为该函数应该返回一个Map,但它要求[Char]

任何帮助将不胜感激:D

1 个答案:

答案 0 :(得分:5)

你正在混合纯粹的不纯的代码 - 这可能在不太严格的编程语言中有效但是haskell让你“标记”IO的每一次使用 - 通过把你放在IO monad中(有不安全的方法) - 所以,让我们不要关注那些)。

你向GHC承诺 - getPhonebook :: Int -> (Map.Map String String) 这意味着对于getPhonebook域中的每个Int,您将返回(Map String String) - pureley而无需任何用户输入。

现在在函数体中,您不能使用getLine等来实现此承诺。

因此,让我们更改类型并确认使用IO。

getPhonebook :: Int -> IO (Map.Map String String)

现在您的基本情况与IO操作不匹配,但可以使用return ...轻松修复此问题。

但是GHC仍然存在一个问题 - Map.insert是纯粹的,并且不会接受getPhonebook (n-1),因为这是一个IO动作。如何解决此问题 - 将此操作绑定到名称previousPB <- getPhonebook (n-1)

将这些放在一起我们得到以下代码:

getPhonebook :: Int -> IO (Map.Map String String)
getPhonebook n
  | n == 0 = return Map.empty
  | otherwise = do
        line <- getLine
        let split = words line
        previousPB <- getPhonebook (n-1)
        return $ Map.insert (split !! 0) (split !! 1) previousPB

现在问题是这样做了什么 - 它通过向你询问n条目来填写电话簿并将其归还给你 - 这是你想要的吗? - 我不知道!