Можно ли отключить анализатор строгости на GHC?

Это показывает ghci внизу ленится,

ghci > let x = trace "1" 1 in x + x

1
1
2

Запуск кода ниже после компиляции показывает по умолчанию ghc усиливается анализатором строгости.

main = do print $ let x = trace "1" 1 in x + x

1
2

Но почему результат остается таким же, даже если варианты -O0 -fno-strictness передаются ghc?

1 ответ

Решение

Это не имеет ничего общего со строгостью. Поведение GHCi на самом деле просто глупо, если подумать: оно "вычисляет" x дважды. Ленивый или нет, константу не нужно вычислять дважды!

В чем дело: x имеет общий тип номера Num a => a, Это означает, что его реализация на самом деле является не просто константой, а функцией с аргументом "тип" - (фактически, словарь -). Функции, как правило, невозможно запомнить, поэтому такое полиморфное значение пересчитывается всякий раз, когда вам нужно его значение. Это раздражает, поэтому стандарт Haskell позволяет избежать этого, несколько спорной меры, на ограничении мономорфизма. Это в основном устраняет полиморфизм, если он может таким образом превращать значения в постоянные аппликативные формы. Так x выводится с более простым типом Integer, который затем является константой, которая только запускает trace один раз это вычисляется, тогда как вторая оценка просто повторно использует уже известное значение. (Что такое "правильное ленивое" поведение!)

Причина, по которой вы не видите этого в GHCi, заключается в том, что начиная с версии 7.8 ограничение мономорфизма по умолчанию отключено! Вы можете включить его, чтобы увидеть, что это делает:

GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :m +Debug.Trace
Prelude Debug.Trace> let x = trace "1" 1 in x + x
1
1
2
Prelude Debug.Trace> :set -XMonomorphismRestriction 
Prelude Debug.Trace> let x = trace "1" 1 in x + x
1
2

К счастью, в реальной программе двойная оценка не произойдет даже при отключенном ограничении мономорфизма, потому что когда x определяется в теле функции, компилятор может видеть, что в области действия функции она не полиморфна. Следовательно, ваш второй код никогда не должен отслеживать 1 дважды. (Хотя всегда имейте в виду, trace это просто грубый инструмент отладки, который действительно работает против структуры языка - как правило, не ожидайте от него никакого воспроизводимого поведения.)

Другие вопросы по тегам