【发布时间】:2018-03-10 17:24:17
【问题描述】:
GHC 允许以下内容永久阻塞是否有任何有用的理由:
list = 1 : tail list
似乎在列表迭代器/生成器中稍微复杂一点,我们应该能够做一些更有用的事情:
- 返回
error "Infinitely blocking list" - 返回
[1,1]
解释2:当进入生成器获取元素N时,我们可以将生成器内的所有自引用限制在列表中,但以N-1结尾(我们注意到read N在范围generate N 并返回列表末尾)。这是一种使用范围的简单死锁检测。
显然,这对于上面的玩具示例没有那么有用,但它可能允许更有用/优雅的有限、自引用列表定义,例如:
primes = filter (\x -> none ((==0).mod x) primes) [2..]
请注意,任何一种更改都应该只影响当前会导致无限块的列表生成器,因此它们似乎是向后兼容的语言更改。
暂时忽略进行此类更改所需的 GHC 复杂性,这种行为会破坏我遗漏的任何现有语言行为吗?对这种变化的“优雅”有何其他想法?
另请参阅下面可能受益的另一个 BFS 示例。对我来说,这似乎比其他一些解决方案更实用/更优雅,因为我只需要定义 bfsList 是,而不是 如何 来生成它(即指定终止条件):
bfs :: (a -> Bool) -> (a -> [a]) -> [a] -> Maybe a
bfs predf expandf xs = find predf bfsList
where bfsList = xs ++ concatMap expandf bfsList
【问题讨论】:
-
虽然在这种情况下这可能很简单,但通常您要求编译器解决停止问题。但无论如何,为什么编译器不代表代码描述的列表呢?在该示例中返回
[1,1]完全是虚假的,因为例如[1,32132132]也同样有效。 -
给定
list = 1 : tail list,即list = 1 : t where t = tail list,什么是t?这是t = tail list = tail (1 : t) = t。即使从等式推理t = t对t的任何值都是微不足道的,所以它实际上根本没有说明t,所以没有理由给它任何特定值。尝试打印list可能会导致[1,***ERROR: black hole detected***或[1,并陷入无限循环。将列表关闭为[1]将意味着t = [],这也是不合理的(因此,从等式推理的角度来看,这是错误的做法)。 -
list = 1 : tail list不会阻止 haskell 中的任何内容,也不会阻止 ghc haskell..它是一个完全有效的值定义,其上有明确定义的操作,可以工作并且有用。 -
求解递归方程意味着在某个域中为合适的函数取最小不动点。在这里,“最少”的意思是“最少定义”:任何比这更定义的东西本质上都涉及从这种空气中创造价值。例如。解决
let (a,b,c,d) = (b,1,d,c)必须选择a=b=1,但c,d有无限多的选择。由于我们通常无法解决停机问题,因此唯一明智的选择是c=d=bottom,其中bottom是非终止/无限递归/无限循环。
标签: list haskell recursion deadlock self-reference