是否可以将递归TH函数转换为将编译的等效形式?以下定义不起作用,因为要编译fact
,您必须首先编译fact
。编写递归模板haskell函数
fact :: ExpQ -> ExpQ
fact n = [|
case $n of
1 -> 1
_ -> $n * $(fact [| $n - 1 |]) |]
这个简单的例子很容易解决(fact n = [| product [ 1.. $n] |]
),但在一般情况下,如果它是不可能改写的给定功能作为一个循环,可以递归TH函数来定义?这是否有一个可行的例子?为了澄清未来的读者:这个问题是专门写关于递归 TH函数 - 而不是'如何拼接factorial函数'。
的回答我的问题竟然是非常简单的:
{-# 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
可以被编译,因为它不再是递归的,[| fix $fact |]
在后时间被编译,所以没有更多的无限递归定义。
这的fact
版本看起来比原来的略有不同,但可以准确地写入新fact
如旧,后来改造它:
fact' recurse n = [|
case $n of
1 -> 1
_ -> $n * $(recurse [| $n - 1 |]) |]
fact = [| \x -> $((\f -> [| \x -> $(fact (\x -> [| $f $x |]) [| x |]) |]) [| x |]) |]
您只拼接整个'fact'函数。如果这是目标,那么我可以在不使用任何TH的情况下编写我的代码。通过这种方法,我不能在函数中使用TH来执行任何操作,因为内部'n'不能逃避它的范围。 – user2407038
虽然这一点通常适用 - 您需要转换您的代码,以便递归在运行时使用这样的技巧。如果您的递归在编译时不会达到最低水平,那么您的代码将无法工作。 –
我添加了一个做递归的例子,它在TH表达式上终止,以说明你的问题是非终止的,而不是递归本身。 –