Haskell中的“无法将类型[[]”与“ IO”匹配”错误

时间:2019-09-23 23:59:47

标签: list haskell type-mismatch io-monad do-notation

我正在尝试用Points(我创建的数据类型)列出一个列表,这个想法是在每次迭代中添加一个元素。出了点问题。

我尝试将pmyLoop中剔除,但这似乎也不起作用。

main = myLoop 
myLoop  = do 
            let p = []
            done <- isEOF
            if done
              then putStrLn ""
              else do inp <- getLine
                      let (label:coord) = words inp
                      p ++  [Point label (map getFloat coord)]
                      -- print (pointerList)
                      myLoop 

我得到了这个输出

trabalho.hs:30:23: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected type: IO Point
        Actual type: [Point]
    • In a stmt of a 'do' block:
        p ++ [Point label (map getFloat coord)]
      In the expression:
        do inp <- getLine
           let (label : coord) = words inp
           p ++ [Point label (map getFloat coord)]
           myLoop
      In a stmt of a 'do' block:
        if done then
            putStrLn ""
        else
            do inp <- getLine
               let (label : coord) = ...
               p ++ [Point label (map getFloat coord)]
               ....
   |
30 |                       p ++  [Point label (map getFloat coord)]
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 个答案:

答案 0 :(得分:5)

首先,do表示法是具有以下规则的语法糖:

do x <- mA
   mB

大约*减少到mA >>= \x -> do mB,其中mA的类型为Monad m => m a,而do mB的类型为Monad m => m b,某些类型的m,{{ 1}}和a

b

do mA mB 的贬低,其中对于某些类型mA >> do mB,{{1},mA的类型为Monad m => m ado mB的类型为Monad m => m b。 }和m

a

b不满意。

do a 是一个特殊名称,代表程序的入口点,对于某些类型a,它的类型为main。因为您定义了IO a,所以a也必须具有类型main = myLoop

因此,在您的myLoop函数中:

IO a

myLoop块正在使用myLoop = do let p = [] done <- isEOF if done then putStrLn "" else do inp <- getLine let (label:coord) = words inp p ++ [Point label (map getFloat coord)] -- print (pointerList) myLoop = do类型。因此,当您编写m时,对于某些类型IO,类型检查器需要类型为p ++ [Point label (map getFloat coord)]的值。

但是,IO c的类型为c,导致类型错误为p ++ [Point label (map getFloat coord)]

如类型不匹配所指示,您的代码没有意义。我假设您要将[Point]附加到Cannot match type '[]' with 'IO'Point label (map getFloat coord)不会 突变p;它会创建一个新列表! Idiomatic Haskell使用递归来实现所需的功能。修改代码最直接的方法是执行以下操作:

++

在这里,pmain = myLoop [] myLoop p = do done <- isEOF if done then putStrLn "" else do inp <- getLine let (label:coord) = words inp let p' = p ++ [Point label (map getFloat coord)] myLoop p' 作为参数,并在读取输入后将更新的myLoop递归传递给它自己。 pp的参数main的初始值来调用myLoop

Haskell Wikibook具有a good explanation of do-notation。通常,我建议阅读Haskell Wikibook,以更好地了解Haskell。

*我之所以说“大致”,是因为这不是确切的规则。 Wikibook文章深入解释了do-notation。