Я новичок в Хаскеле. Учитывая, что вся предпосылка Haskell заключается в том, что функция всегда будет возвращать одно и то же значение, я ожидаю, что будет какой-то способ, например. вычисление значений Фибоначчи констант во время компиляции, как я могу сделать в C++ с метапрограммированием шаблона, но я не понимаю, как это сделать. Есть ли способ?
Вариант метапрограммирования шаблонов на Haskell
Ответы (2)
редактировать: Даниэль Фишер указывает, что вы можете перенести обычное выражение в Template Haskell и оценить результат во время компиляции, с учетом определенных ограничений на тип вывода, используя обычную функцию fib
, а затем соединив
$(let x = fib 1000 in [|x|])
Оригинальный ответ следует.
Как указано в комментариях, для этого подходит Template Haskell. Для индуктивных функций, таких как Фибоначчи, это довольно просто. Вы пишете код, аналогичный стандартному определению, но возвращающий значение ExpQ. Из-за ограничений по соединению вам нужно будет использовать 2 модуля.
{-# LANGUAGE TemplateHaskell #-}
module TH where
import Language.Haskell.TH
fibTH :: Int -> ExpQ
fibTH 0 = [| 0 |]
fibTH 1 = [| 1 |]
fibTH n = [| $(fibTH (n-1)) + $(fibTH (n-2)) |]
а также
{-# LANGUAGE TemplateHaskell #-}
module Main where
import TH
y :: Int
y = $(fibTH 10)
main = print y
Чтобы убедиться, что работа выполняется во время компиляции, мы можем скомпилировать с помощью -ddump-simpl
, чтобы увидеть ядро, что подтверждает это.
Main.y :: GHC.Types.Int
[GblId,
Caf=NoCafRefs,
Str=DmdType m,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=True,
ConLike=True, WorkFree=False, Expandable=True,
Guidance=IF_ARGS [] 10 20}]
Main.y = GHC.Types.I# 55
fib
в другом модуле, а затем соединить y = $(let x = fib 1000 in [|x|])
?
- person Daniel Fischer; 29.12.2012
Есть отличная статья Доном Стюартом, где он показывает, что использование бэкенда LLVM с правильным выбором флагов предварительно вычислит определенные функции во время компиляции и заменит их константами.