edit: Daniel Fisher points out that you can raise a regular expression in Template Haskell and evaluate the result at compile time taking into account certain restrictions on the type of output using the regular fib function, and then splicing
$(let x = fib 1000 in [|x|])
The following is the original answer.
As pointed out in the comments, Template Haskell is the way to go about it. For inductive functions such as fibonacci, it is quite simple. You write code similar to the standard definition, but returning an ExpQ value. Due to splicing restrictions, you will need to use 2 modules.
{-# 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)) |]
and
{-# LANGUAGE TemplateHaskell #-} module Main where import TH y :: Int y = $(fibTH 10) main = print y
To confirm that the work is done at compile time, we can compile with -ddump-simpl to see the kernel that confirms it.
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
source share