Является ли `оценка` безопасной по сравнению с` seq`?

Как показанный в этом ответе, seq в сочетании с undefined делает очень странные вещи, когда дело доходит до эквациональных рассуждений, например, оно может сделать любую монаду неудачной, Другой пример - этот вопрос.

Недавно я наткнулся на evaluate :: a -> IO a, который делает аналогичную вещь - он оценивает свой аргумент WHNF, но только когда действие IO оценивается. Это кажется гораздо более безопасным, так как мы ожидаем, что "в IO мы сможем сделать все". Конечно, его нельзя использовать повсеместно, но часто необходимость оценивать выражение каким-то образом связана с операцией IO (например, заставить рабочий поток оценивать вычисление вместо потребляющего потока при работе с MVar s).

Итак, я хотел бы спросить, насколько безопасно evaluate? Можно ли создавать примеры (конечно, IO), где он нарушает рассуждения о коде вроде seq? Или я могу считать его безопасной заменой seq (если это возможно для конкретной программы)?

Ответ 1

Нет, вы по-прежнему получаете те же проблемы, вызванные командой seq, поскольку любая монада, используемая в первом аргументе evaluate, будет иметь свои правила монады. Исходя из этого правила в ertes ответ:

В категории Клейсли монада порождает return - это морфизм идентичности и (<=<) - это композиция. Итак, return должно быть для (<=<):

return <=< x = x

Это означает, что вы можете заменить return <=< x на x на любую действительную монаду, не изменяя работу программы.

Используя это с помощью функции evaluate...

evaluate (return <=< undefined :: a -> Identity b) >> putStrLn "hello"

выводит привет. Используя то, что должно быть эквивалентным выражением, заменив return <=< undefined на undefined:

evaluate (undefined :: a -> Identity b) >> putStrLn "hello"

вместо этого вызывает исключение Prelude.undefined.

Это происходит только с функцией оценки. Обратите внимание, что return имеет точно такую ​​же подпись типа evaluate. Если вы замените evaluate на return в приведенных выше командах, результирующее действие для обеих команд будет одинаковым (они выводят hello).