Этот код (взят из Learn You A Haskell ):
main = do putStr "Hey, "
putStr "I'm "
putStrLn "Andy!"
очевидно desugars to
main = putStr "Hey, " >>=
(\_ -> putStr "I'm " >>=
(\_ -> putStrLn "Andy!"))
Который, как я понимаю его можно интерпретировать как высказывание «Чтобы поставитьStrLn« Энди! », мне сначала нужно поставитьStr« Я », а для этого мне сначала нужно поставитьStr« Эй »;
Я не согласен с этой интерпретацией , что раздражает, потому что компилятор явно этого не делает и оставляет меня в замешательстве.У меня проблема в том, что лямбды игнорируют свои аргументы, во время ленивых вычислений разве такие вещи не должны распознаваться и закрываться?
Также, конечно, привязка возвращает действие ввода-вывода, и когда это действие ввода-вывода попадает в главное, оно выполняется. Но что помешает ему напечатать «Эй, Энди! Я»? Я подозреваю, что это то, что делает привязка .
Кроме того, как действие ввода-вывода типа «IO ()» несет достаточно информации, чтобы позволить системе времени выполнения напечатать «Эй, я Энди!»? Чем этот IO () отличается от IO (), чем вывод «Hello World!» или записывает в файл?
Рассмотрим другую монаду со страницы википедии:
Sugared version:
do
putStrLn "What is your name?"
name <- getLine
putStrLn ("Nice to meet you, " ++ name ++ "!")
Desugared version:
putStrLn "What is your name?" >>=
(\_ ->
getLine >>=
(\name ->
putStrLn ("Nice to meet you, " ++ name ++ "!")))
Аналогичная история здесь.
Думаю, мне просто нужно увидеть определение связывания для ввода-вывода, и тогда все будет ясно. Еще кое-что, что могло бы сильно помочь, - это, если бы кто-то мог помочь мне пройти через то, как на самом деле оценивается программа, и определить точные моменты, когда возникают побочные эффекты.