是否可以將遞歸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表達式上終止,以說明你的問題是非終止的,而不是遞歸本身。 –