В чем разница между "оценить" и "вернуть $!"?

Вот выдержка из документации evaluate:

Control.Exception.Base.evaluate :: a -> IO a
evaluate x

не совпадает с

return $! x

Правильное определение

evaluate x = (return $! x) >>= return

(источник)

Кажется, они имеют одинаковое значение. В чем разница между этими двумя определениями?

Ответ 1

Быстрая ссылка:

Тип evaluate:

evaluate :: a -> IO a

seq имеет тип a -> b -> b. Сначала он оценивает первый аргумент, затем возвращает второй аргумент.

Вычислить следующие три правила:

evaluate x `seq` y    ==>  y
evaluate x `catch` f  ==>  (return $! x) `catch` f
evaluate x >>= f      ==>  (return $! x) >>= f

Различие между return $! x и (return $! x) >>= return становится очевидным с помощью этого выражения:

evaluate undefined `seq` 42

По первому правилу, которое должно оцениваться до 42.

С помощью определения return $! x приведенное выше выражение вызовет исключение undefined. Это имеет значение ⊥, которое не равно 42.

При определении (return $! x) >>= return оно равно 42.

В принципе, форма return $! x является строгой, когда вычисляется значение ввода-вывода. Другая форма является строгой только при выполнении значения ввода-вывода и используемого значения (используя >>=).

Подробнее см. этот список рассылки.