【问题标题】:How does Rose Tree unfold work (from Origami Programming)玫瑰树如何展开工作(来自 Origami Programming)
【发布时间】:2015-08-03 23:18:55
【问题描述】:

我一直在阅读文章 Origami Programming by Jeremy Gibbons 并且无法弄清楚 unfoldRunfoldF 函数如何为 Rose Trees 工作。

在论文中Rose Tree类型定义为:

data Rose α = Node α (Forest α)
type Forest α = List (Rose α)

unfoldRunfoldF 函数是相互递归的,定义为:

unfoldR :: (β → α) → (β → List β) → β → Rose α
unfoldR f g x = Node (f x) (unfoldF f g x)

unfoldF :: (β → α) → (β → List β) → β → Forest α
unfoldF f g x = mapL (unfoldR f g) (g x)

看起来,除了一些小的边缘情况外,这些函数将无限递归。这两个相互递归的函数如何终止?

【问题讨论】:

  • unfoldF返回一个空列表时终止,即当g x返回一个空列表时。
  • 没有理由终止它们。重要的是它们富有成效。它们支持玫瑰树上的模式匹配,因为只要需要节点结构,它就会被交付。在通过树的每条路径上,最终都找到具有空子树列表的节点可能并非如此。无限增长是可能的。 Haskell 识别归纳(所有路径必然有限)和互归纳(某些路径可能无限)结构:展开是生成互归纳结构的方式。它是如何工作的?而是问它什么时候起作用?按需提供。
  • 将一个替换为另一个得到unfoldR f g x = Node (f x) (mapL (unfoldR f g) (g x)),这将unfoldR 简化为常规递归函数,而不是与unfoldF 相互递归。正如@user5402 所说,当g x 返回一个空列表时,unfoldF 被映射到一个空列表中,从而导致零递归调用。

标签: haskell functional-programming


【解决方案1】:

它们不一定会终止!

unfoldRunfoldF 的定义分别在 RoseForest 类型上形成了 co-inductive 函数。共诱导是结构诱导的对偶。共归纳函数旨在创建无限的数据结构,稍后将通过递归函数使用这些数据结构。

由于 Haskell 的惰性求值,我们可以通过将函数 f :: (β → α)g :: (β → List β) 以及初始“种子值”x :: β 应用到任一函数来定义和创建无限相互递归的 RoseForest 数据结构unfoldRunfoldF

然后我们将使用另一个递归函数 h :: Rose -> γ 来使用无限数据结构

把一个未定义的例子放在一起:

f :: (β → α)
f = undefined
g :: (β → List β) 
g = undefined
x :: β
x = undefined
h :: Rose -> γ
h = undefined

result :: γ
result = h $ unfoldR f g x

这里的result 将是对无限结构计算的评估。但如果是无限数据结构,h 怎么终止呢? 如何 result 曾经被评估过?

虽然unfoldR f g x 会产生无限结构,但h 只会搜索搜索空间的有限子集,因此可以评估result

注意: 我们也可以定义f, g & x 来创建一个有限结构,它不必是无限的

【讨论】:

  • 谢谢,这是有道理的。这个函数几乎总是无限的,并且可以与 Haskell 一起使用,因为它将以惰性方式进行评估,而不是锁定或堆栈溢出程序。出于好奇,您知道展开R 是否可以生成任何可能的玫瑰树,还是只能生成可能的玫瑰树的子集?
  • @egerhard 对于给定的参数类型α,根据fhx 的定义,玫瑰树可能unfoldR f h x 生成的分支中包含所有可能的玫瑰树作为子树。为了确定这一点,需要一个数学证明。
  • @recursion.ninja 你能详细说明数学证明吗? (你自己和/或有参考)
猜你喜欢
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多