【发布时间】:2014-05-09 06:45:01
【问题描述】:
注意下面fold函数的定义:
data T = A | B T | C T T
fold up2 up1 up0 down accum x = dig x accum where
dig (C a b) accum = up2 C a b accum (dig a (down (C a b) accum)) (dig b (down (C a b) accum))
dig (B a) accum = up1 B a accum (dig a (down (B a) accum))
dig A accum = up0 A accum
这个函数是一种非常常规的定义方式,但它取决于该类型的数据构造函数具有的最大递归分支数。也就是说,T 有一个带有 2 个递归点 C T T 的构造函数,因此“fold”接收三个“up”参数。如果C T T 不是类型的一部分,那么 fold 的定义将少一个参数:
data T = A | B T
fold up1 up0 down accum x = dig x accum where
dig (B a) accum = up1 B a accum (dig a (down (B a) accum))
dig A accum = up0 A accum
我的问题是是否可以使用deriving 自动创建fold 的定义。
【问题讨论】:
-
非常规律?老实说,这对我来说看起来很疯狂。请签名!天啊。
fold :: ... -> ((T->...->T)->a->...->q-> z->...-> z) -> ... -> ((T->T->T->T)->a->b->c->q->z->z->z->z) -> ((T->T->T)->a->b->q->z->z->z) -> ((T->T)->a->q->z->z) -> (T->q->z) -> T -> z,对吗? -
deriving可能不够,因为它仅适用于少数选定的类。也许模板 Haskell 可以在这里提供帮助? -
@leftaroundabout 是的,函数本身很复杂,但在某种意义上它是常规的,有一种算法可以在给定数据结构的情况下定义它。此外,尽管函数看起来很疯狂,但它概括了数据类型上所有可能的递归算法,因此定义递归函数变得更加清晰,因为现在导航和数据处理分离了。
-
这不是真的,它只需要3个up函数,只要你没有超过2个递归点的数据构造函数。因此,例如,当您的类型类似于
data T = A | B T | C T T | D | E T | F T T | G T T | H T | I | J | K | L T T(例如,具有复杂语法的 DSL)等等时,您仍然可以拥有一个针对特定构造函数的短递归函数。所以这就是问题的重点,你能把它通用吗? -
你的数据结构没有数据,只有形状。这里没有什么可折叠的。添加数据,您的第二个示例
data T = A | B T变为data T a = A | B a (T a),这只是一个伪装的列表。 (没有数据,它只是一个自然数)。但是你的“折叠”函数看起来不像我们都知道和喜欢的列表折叠。而且您的主要示例看起来不像来自Data.Foldable或Data.Functor.Foldable的东西。你能举一个真实的例子来证明你的折叠风格的必要性吗?
标签: haskell