recursion - F#:互递归数据结构的变态

标签 recursion f# tail-recursion mutual-recursion catamorphism

假设以下相互递归结构:

type Tree<'a> = 
    | Empty 
    | Node of 'a * 'a Forest
and Forest<'a> = 
    | Nil 
    | Cons of 'a Tree * 'a Forest

目标:为这个结构生成常见的变形:foldl、foldr、foldk。

我已经生成了如下的 naive-catamorphism:
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')

我如何“机械地”生成尾递归折叠(使用累加器)和尾递归折叠(使用延续)?

我经历过Scott's Recursive Types and Folds series并且我了解如何“机械地”为递归结构生成折叠。但是我在谷歌上找不到任何东西来为递归数据结构做“机械”的事情。

PS:可以通过内联来摆脱上面的相互递归,但让我们保留它,因为它代表了 tpetricek's Markdown parser 中相互递归的简化版本。 .

最佳答案

我完全不确定这是否是您要找的东西,但这似乎提供了您想要的东西(有点)。
关键点是只处理类型“内部”的内容,而让“外部”的内容由其他东西处理(一些抽象)

//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

关于recursion - F#:互递归数据结构的变态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40254697/

相关文章:

list - 将现有列表写入 Prolog 中的新列表

Java递归-从数组中逆序整数,它是如何工作的?

f# - 获取数组、列表或序列的第 N 个元素的不同参数顺序

asynchronous - 条件为 async 的异步计算表达式中的 'while'

c - 为什么 int main() { return main();导致堆栈溢出而不是尾递归?

recursion - Fortran 递归树实现中的段错误

java - 递归地找到一个集合中最强大的

f# - 涉及静态类型转换的 f# 方法的泛型类型约束

javascript - javascript中的尾递归

functional-programming - Kotlin中如何用动态编程实现纯函数?