Прежде всего, нотация 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-обозначения.