在模板Haskell中定义递归函数

在模板Haskell中定义递归函数,haskell,recursion,template-haskell,Haskell,Recursion,Template Haskell,我想为(首先是简单的)ADT实现一个通用递归操作符。 (Simple意味着只有参数类型为已定义类型的构造函数才可以使用。)总体思路是能够使用像$(recop''Alg)这样简单的东西。 手动编写给定类型的递归运算符很容易 data D=E | cd 记录:t->((D,t)->(D,t)->t)->D->t recD rE rC=让r=recD rE rC在\case中 E->rE C pC0 pC1->rC(pC0,r pC0)(pC1,r pC1) 我想使用模板。我的问题是递归调用,例如r

我想为(首先是简单的)ADT实现一个通用递归操作符。 (Simple意味着只有参数类型为已定义类型的构造函数才可以使用。)总体思路是能够使用像
$(recop''Alg)
这样简单的东西。 手动编写给定类型的递归运算符很容易

data D=E | cd
记录:t->((D,t)->(D,t)->t)->D->t
recD rE rC=让r=recD rE rC在\case中
E->rE
C pC0 pC1->rC(pC0,r pC0)(pC1,r pC1)
我想使用模板。我的问题是递归调用,例如
rpc0
。我没有递归调用就让它工作了

newNames :: String -> Int -> Q [Name]
newNames stem n = sequence [ newName (stem ++ show i) | i <- [1::Int .. n] ]
match' :: PatQ -> ExpQ -> MatchQ
match' pat exp = match pat (normalB exp) []

recop :: Name -> ExpQ
recop name = do
    TyConI (DataD _ algName [] {-_-} ctors _) <- reify name
    let ctorNames = [ ctorName | NormalC ctorName _ <- ctors ] :: [Name]
    let ctorTypes = [ [ typ | (_, typ) <- bts ] | NormalC _ bts <- ctors ] 
    rs <- newNames ("r" ++ nameBase algName) (length ctorNames)
    pss <- sequence [ newNames ("p" ++ nameBase algName ++ nameBase ctorName) (length ctorTypes) | (ctorName, ctorTypes) <- zip ctorNames ctorTypes ]
    let pats = zipWith conP ctorNames (map varP <$> pss) :: [PatQ]
    let prs = zipWith (\p r -> tupE [varE p, r]) ps "recursive calls"
    lamE (varP <$> rs) $ lamCaseE [ match' pat $ foldl appE (varE r) prs | (r, pat, ps) <- zip3 rs pats pss ]
newNames::String->Int->Q[Name]
newNames stem n=序列[newName(stem++show i)| i ExpQ
recop name=do

TyConI(DataD_u-algName[]{-{-}ctors}您在具体代码中的实现方式完全相同;您生成
让r=..in..
并引用该
r
来构造递归调用。现在,您正在构造
\case{..}
部分。请记住,您可以将
记录改写为

recD =
  let
    recD_ = \rE rC ->
      let r = recD_ rE rC
      in ...
  in recD_
用户2407038在评论中回答了这个问题

一般模式是使用附加的
let
构造:

recursive = let recursive_ = expression in recursive_

因此,您可以在
expression
中引用
recursive.
,方法与在具体代码中的方法完全相同;您生成
让r=..in..
并引用该
r
来构造递归调用。现在,您正在构造
\case{..}
部分。请记住,您可以将
记录改写为

recD =
  let
    recD_ = \rE rC ->
      let r = recD_ rE rC
      in ...
  in recD_
用户2407038在评论中回答了这个问题

一般模式是使用附加的
let
构造:

recursive = let recursive_ = expression in recursive_

因此,您可以在
expression

中引用
recursive.
,方法与在具体代码中完全相同;您生成
let r=..
并引用该
r
来构造递归调用。现在,您正在构造
\case{..}
部分。请记住,您可以将
recD
重写为
recD=let recD\ure-rC->let r=recD\uure-rC in…in recD\uu
。您可以完全按照在具体代码中执行的方式来执行此操作;您可以生成
let r=…in.
并引用该
r
来构造递归调用。现在,您只是c正在构造
\case{..}
部分。请记住,您可以将
recD
重写为
recD=let recD=\rE rC->let r=recD\rE rC in…in recD