Ответ 1
Во-первых, обратите внимание, что модуль GHC.Word
включает в себя следующие RULE
прагма:
"truncate/Double->Word16"
forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)
Это простое правило перезаписи, которое позволяет точно оптимизировать ваш truncate1
. Поэтому у нас есть несколько вопросов, которые следует учитывать:
Почему это вообще оптимизация?
Поскольку стандартная реализация truncate
является общей, для поддержки любого экземпляра Integral
. Разница в скорости, которую вы видите, - это стоимость этой общности; в конкретном случае усечения одного примитивного типа в другой существует гораздо более быстрый метод.
Итак, кажется, что truncate1
извлекается из специализированной формы, а truncate2
- нет.
Почему truncate1
быстрее?
В GHC.Float
, где указан экземпляр RealFrac
для Double
, мы имеем следующую RULE
прагму:
"truncate/Double->Int" truncate = double2Int
Где double2Int
- оптимизированная форма, которую мы хотим. Сравните это с ранее упомянутым RULE
- по-видимому, нет такой примитивной операции, специально для преобразования Double
в Word16
.
Почему не перезаписывается truncate2
?
Цитата Руководство пользователя GHC:
В настоящее время GHC использует очень простой синтаксический алгоритм для сопоставления правила LHS с выражением. Он ищет замену, которая делает LHS и выражение синтаксически равномерным альфа-преобразованием. Шаблон (правило), но не выражение, является, если необходимо, расширением eta.
Согласованные выражения не являются eta-расширенными, то есть соответствие правил на forall x. foo x
будет соответствовать в bar y = foo y
, но не в bar = foo
.
Так как ваши определения записаны без точек, соответствует RULE
для Double -> Int
, но RULE
для Double -> Word16
не работает.