假设以下相互递归结构:
type Tree<'a> =
| Empty
| Node of 'a * 'a Forest
and Forest<'a> =
| Nil
| Cons of 'a Tree * 'a Forest
目标:为此结构生成常见的catamorphisms: foldl , foldr , foldk 。
我已经产生了如下的天真 - 变形:
let rec foldTree fEmpty fNode fNil fCons =
function
| Empty -> fEmpty
| Node (a, f) -> fNode a (foldForest fEmpty fNode fNil fCons f)
and foldForest fEmpty fNode fNil fCons =
function
| Nil -> fNil
| Cons (t, f') -> fCons (foldTree fEmpty fNode fNil fCons t) (foldForest fEmpty fNode fNil fCons f')
如何“机械地”生成尾递归foldl(使用累加器)和尾递归foldr(使用continuation)?
我已经通过Scott's Recursive Types and Folds series,我理解如何“机械地”生成递归结构的折叠。但是我在谷歌上找不到任何关于递归数据结构的“机械”的东西。
PS:可以通过in-lining去除上面的相互递归但是保留它,因为它代表了tpetricek's Markdown parser中相互递归的简化版本。
答案 0 :(得分:0)
我完全不确定这是否是您正在寻找的东西,但这似乎给了您想要的东西(排序)。
关键点是只处理&#34;内部&#34;什么是&#34;外面&#34;由其他东西处理(一些抽象)
//val foldTree : 'a -> ('b -> 'c -> 'a) -> ('b Forest -> 'c) -> 'b Tree -> 'a
let foldTree fEmpty fNode fForest = function
Empty -> fEmpty
| Node (a, f) -> fNode a (fForest f)
// val foldForest : 'a -> ('b -> 'a -> 'a) -> ('c Tree -> 'b) -> 'c Forest -> 'a
let rec foldForest fNil fCons fTree =
let recurse = foldForest fNil fCons fTree
function
Nil -> fNil
| Cons (t, f) -> fCons (fTree t) (recurse f)
let foldForestAcc fNil fCons fTree =
let rec aux acc = function
Nil -> acc
| Cons (t, f) -> aux (fCons (fTree t) acc) f
aux fNil
let foldForestCont fNil fCons fTree =
let rec aux cont = function
Nil -> cont fNil
| Cons (t, f) -> aux (fCons (fTree t) >> cont) f
aux id
如果它更适合您所寻求的内容,也可以选择其他方式:
let fold fEmpty fNode fNil fCons =
let rec auxT = function
Empty -> fEmpty
| Node (a, f) -> fNode a (auxF f)
and auxF = function
Nil -> fNil
| Cons (t, f) -> fCons (auxT t) (auxF f)
auxT
let foldAcc fEmpty fNode fNil fCons =
let rec auxT acc = function
Empty -> acc
| Node (a, f) -> fNode a (auxF fNil f)
and auxF acc = function
Nil -> acc
| Cons (t, f) -> auxF (fCons (auxT fEmpty t) acc) f
auxT fEmpty
let foldCont fEmpty fNode fNil fCons =
let rec auxT cont = function
Empty -> cont fEmpty
| Node (a, f) -> cont (fNode a (auxF id f))
and auxF cont = function
Nil -> cont fNil
| Cons (t, f) -> auxF (cont >> fCons (auxT id t)) f
auxT id