«Не удалось сопоставить тип« [] »с ошибкой« IO »в Haskell - PullRequest
0 голосов
/ 24 сентября 2019

Я пытаюсь создать список с точками (тип данных, который я создал), идея заключается в добавлении элемента в каждую итерацию.Что-то не так.

Я пытался выставить p из myLoop, но, похоже, он тоже не работает.

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 Ответ

5 голосов
/ 24 сентября 2019

Прежде всего, нотация do является синтаксическим сахаром со следующими правилами:

do x <- mA
   mB

примерно * десугар до mA >>= \x -> do mB, где mA имеет тип Monad m => m a, а do mB имеет типMonad m => m b для некоторых типов m, a и b.

do mA
   mB

десугары в mA >> do mB, где mA имеет тип Monad m => m a, а do mB имеет тип Monad m => m b для некоторых типов m, a и b.

do a

desugars к 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.++ делает не мутировать p;он создает новый список! Idiomatic Haskell использует рекурсию для достижения того, что вы хотите.Самый прямой способ исправить ваш код - это сделать следующее:

main = 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 принимает p в качестве параметра и рекурсивно передает обновленный p себе после чтения ввода.main вызывает myLoop с аргументом [], который является начальным значением p.

В Haskell Wikibook есть хорошее объяснение нотации .В общем, я бы рекомендовал прочитать Haskell Wikibook, чтобы лучше понять Haskell.

* Я говорю «грубо», потому что это не точные правила.Статья Wikibook подробно объясняет do-обозначения.

...