Is it possible to transform a recursive TH function into an equivalent form which will compile? The following definition doesn't work, because in order to compile fact
you must first compile fact
.
fact :: ExpQ -> ExpQ
fact n = [|
case $n of
1 -> 1
_ -> $n * $(fact [| $n - 1 |]) |]
This simple example is easily solved (fact n = [| product [ 1.. $n] |]
) but in the general case, if it is not possible to rewrite a given function as a loop, can a recursive TH function be defined? Is there even a single example for which this doable?
To clarify for future readers: this question is specifically about writing recursive TH functions - not about 'how do I splice the factorial function'.
The answer to my question turned out to be remarkably simple:
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Fix (fix)
import Language.Haskell.TH
fact = [| \f x -> $([|
case x of
1 -> 1
_ -> f $([| x - 1 |]) * x |]) |]
factorial = [| fix $fact |]
fact
can be compiled because it is no longer recursive, and [| fix $fact |]
is compiled at a later time, so no more infinite recursive definitions.
This version of fact
looks slightly different than the original, but you can write the new fact
exactly as the old one and transform it later:
fact' recurse n = [|
case $n of
1 -> 1
_ -> $n * $(recurse [| $n - 1 |]) |]
fact = [| \x -> $((\f -> [| \x -> $(fact (\x -> [| $f $x |]) [| x |]) |]) [| x |]) |]