我正在尝试对受歧视的工会实施折叠。DU 称为 Expr,表示程序表达式,通常是递归的。我正在尝试编写一个折叠,以递归方式累积对 Expr 的操作结果。下面是我写折叠的尝试。
let rec foldProceduralExpr (folder : 's -> Expr list -> 's) (state : 's) (expr : Expr) : 's =
let children =
match expr with
| Series s -> s.SerExprs
| Lambda l -> [l.LamBody; l.LamPre; l.LamPost]
| Attempt a -> a.AttemptBody :: List.map (fun ab -> ab.ABBody) a.AttemptBranches
| Let l -> l.LetBody :: List.concat (List.map (fun lb -> match lb with LetVariable (_, expr) -> [expr] | LetFunction (_, _, body, _, pre, post, _) -> [body; pre; post]) l.LetBindings)
| Case c -> c.CaseTarget :: List.concat (List.map (fun branch -> [branch.TBBody; branch.TBTest]) c.CaseBranches)
| Condition c -> List.concat (List.map (fun branch -> [branch.TBBody; branch.TBTest]) c.CondBranches)
| List l -> l.ListElements
| Array a -> Array.toList a.ArrElements
| Composite c -> LunTrie.toValueList (LunTrie.map (fun _ mem -> mem.MemExpr) c.CompMembers)
| _ -> []
let listFolder = fun state expr -> foldProceduralExpr folder state expr
let listFolded = List.fold listFolder state children
folder state (expr :: listFolded)
问题是代码不起作用,这是众所周知的,因为我在最后一行得到了the construct causes code to be less generic than indicated by the type annotations. The type variable 's has been constrained to be type 'Expr list'
错误listFolded
。这是因为 的定义foldProceduralExpr
几乎肯定是错误的。
现在,我很想修复代码并因此修复类型错误,但我根本不知道如何。我想我缺乏的是对非列表或递归数据结构的折叠如何工作的理解。我最近将一个 trie 的折叠从 OCaml 翻译成 F#,并且在理解该折叠如何工作时遇到了很多麻烦。
问题 1:此代码是否有我可以理解的可见修复?
问题 2:是否有资源来获得理解如何编写这些类型的折叠所需的背景?
如果您需要更多信息,请告诉我。我没有将 DU 包括在内,因为它太大且太复杂,无法清楚地说明问题。希望可以说,这是典型的 Lisp 风格的 AST 数据结构。
后续问题:一旦它起作用,我也想用那个折叠写一张地图。这看起来像一张典型的地图,还是需要一些额外的脑力才能弄清楚?
编辑:关于 Tomas 的帮助,我已将最后三行变成 -
let exprs = expr :: children
let listFolder = fun state expr -> foldProceduralExpr folder state expr
let listFolded = List.fold listFolder state exprs
folder listFolded exprs
我希望这仍然有意义。
编辑:这是我的最终解决方案。它概括了得到孩子 -
let rec foldRdu (getChildren : 't -> 't list) (folder : 's -> 't -> 't list -> 's) (state : 's) (parent : 't) : 's =
let children = getChildren parent
let listFolder = fun state child -> foldRdu getChildren folder state child
let listFolded = List.fold listFolder state children
folder listFolded parent children
我将 Expr 和 Expr 列表作为折叠值的原因是我想保留父/子关系的结构以供以后使用。这是一个非常特定于领域的折叠,在某种程度上我想。