Почему Haskell не может быть обманут в выполнении операций ввода-вывода, используя строгую оценку?
Я просто изучаю монады Haskell и IO. Мне интересно, почему бы это не заставить программу выводить "привет", а также "пока":
second a b = b
main = print ((second $! ((print "hi") >>= (\r -> return ()))) "bye")
Насколько я понимаю, оператор $!
заставил бы первый аргумент second
быть оценен, а оператору >>=
нужно было бы запустить print "hi"
, чтобы получить от него значение и передайте его на \r -> return ()
, который напечатает "hi" на экране.
Что не так с моими рассуждениями?
А также, есть ли способ пропустить Haskell нельзя обмануть (кроме использования небезопасных функций) в выполнение операций ввода-вывода внутри "безопасного" кода?
Ответы
Ответ 1
Выставляемое выражение ((print "hi") >>= (\r -> return ()))
, которое имеет тип IO ()
. Таким образом, он представляет собой операцию ввода-вывода. Но оценка такой вещи совсем не похожа на ее работу!
Оценка значения означает выполнение достаточно простых шагов, чтобы превратить его в так называемую слабую головную нормальную форму. Поскольку IO
является абстрактным, немного сложно понять, что это значит в этом случае, но можно думать о IO a
как RealWorld -> (a, RealWorld)
, а затем нормальная форма слабой головки - это, ну, функция, ожидающая с учетом RealWorld
.
Выполнение подразумевает оценку, но также передает RealWorld
в качестве аргумента, тем самым вызывая эффект IO
.
Все это не очень специфично для IO
; ваше замешательство и концепции в равной степени относятся к a -> b
. Если вы понимаете, что делает $!
, когда второй аргумент является функцией, вы поймете, что происходит, когда это действие IO.
Ответ 2
Вы путаете оценку с исполнением. Когда вы вызываете выражение типа print "hi"
, это ничего не выводит. Он просто производит значение (в данном случае значение типа IO()
), представляющее действие печати чего-либо. Вы можете придумать значение print "hi"
в качестве рецепта для печати "привет".