根据this paper对数据结构的区分工作。
根据this answer:
区分,数据类型D的导数(给定为D')是具有单个“洞”的D结构的类型,即,不包含任何数据的区别位置。这令人惊讶地满足了与微积分差异相同的规则。
规则是:
1 = 0
X′ = 1
(F + G)′ = F' + G′
(F • G)′ = F • G′ + F′ • G
(F ◦ G)′ = (F′ ◦ G) • G′
引用的论文对我来说有点过于复杂,无法获得直觉。 这在实践中意味着什么?一个具体的例子太棒了。
答案 0 :(得分:20)
X中X的单孔上下文是什么?没有选择:它是( - ),可以用单位类型表示。
X * X中X的单孔上下文是什么?它类似于( - ,x2)或(x1, - ),所以它可以用X + X表示(如果你愿意的话可以用2 * X表示)。
X * X * X中X的单孔上下文是什么?它类似于( - ,x2,x3)或(x1, - ,x3)或(x1,x2, - ),可由X * X + X * X + X * X表示,或(3 * X ^ 2,如果你喜欢)。
更一般地说,带有孔的F * G要么是带有孔的F和完整的G,要么是完整的F和带孔的G。
递归数据类型通常被定义为多项式的固定点。
data Tree = Leaf | Node Tree Tree
真的是说Tree = 1 + Tree * Tree。区分多项式会告诉您立即子树的上下文:Leaf中没有子树;在节点中,它左边是洞,右边是树,左边是树,右边是洞。
data Tree' = NodeLeft () Tree | NodeRight Tree ()
这是多项式的区分并呈现为一种类型。因此,树中子树的上下文是这些树的步骤的列表。
type TreeCtxt = [Tree']
type TreeZipper = (Tree, TreeCtxt)
例如,这是一个函数(未尝试的代码),它在树中搜索通过给定测试子树的子树。
search :: (Tree -> Bool) -> Tree -> [TreeZipper]
search p t = go (t, []) where
go :: TreeZipper -> [TreeZipper]
go z = here z ++ below z
here :: TreeZipper -> [TreeZipper]
here z@(t, _) | p t = [z]
| otherwise = []
below (Leaf, _) = []
below (Node l r, cs) = go (l, NodeLeft () r : cs) ++ go (r, NodeRight l () : cs)
“下面”的作用是生成与给定树相关的树的居民。
区分数据类型是使“搜索”泛型等程序的好方法。
答案 1 :(得分:11)
我的解释是,T的派生(拉链)是类似于T的“形状”的所有实例的类型,但正好用1个元素替换为“洞”。
例如,列表是
List t = 1 []
+ t [a]
+ t^2 [a,b]
+ t^3 [a,b,c]
+ t^4 [a,b,c,d]
+ ... [a,b,c,d,...]
如果我们用孔替换任何'a','b','c'等(表示为@
),我们就会得到
List' t = 0 empty list doesn't have hole
+ 1 [@]
+ 2*t [@,b] or [a,@]
+ 3*t^2 [@,b,c] or [a,@,c] or [a,b,@]
+ 4*t^3 [@,b,c,d] or [a,@,c,d] or [a,b,@,d] or [a,b,c,@]
+ ...
另一个例子,二叉树是
data Tree t = TEmpty | TNode t (Tree t) (Tree t)
-- Tree t = 1 + t (Tree t)^2
因此添加一个洞会生成类型:
{-
Tree' t = 0 empty tree doesn't have hole
+ (Tree X)^2 the root is a hole, followed by 2 normal trees
+ t*(Tree' t)*(Tree t) the left tree has a hole, the right is normal
+ t*(Tree t)*(Tree' t) the left tree is normal, the right has a hole
@ or x or x
/ \ / \ / \
a b @? b a @?
/\ /\ / \ /\ /\ /\
c d e f @? @? e f c d @? @?
-}
data Tree' t = THit (Tree t) (Tree t)
| TLeft t (Tree' t) (Tree t)
| TRight t (Tree t) (Tree' t)
说明链规则的第三个例子是玫瑰树(可变树):
data Rose t = RNode t [Rose t]
-- R t = t*List(R t)
衍生物说R' t = List(R t) + t * List'(R t) * R' t
,这意味着
{-
R' t = List (R t) the root is a hole
+ t we have a normal root node,
* List' (R t) and a list that has a hole,
* R' t and we put a holed rose tree at the list's hole
x
|
[a,b,c,...,p,@?,r,...]
|
[@?,...]
-}
data Rose' t = RHit [Rose t] | RChild t (List' (Rose t)) (Rose' t)
请注意data List' t = LHit [t] | LTail t (List' t)
。
(这些可能与拉链是“方向”列表的传统类型不同,但它们是同构的。)
衍生物是记录如何编码结构中位置的系统方法,例如,我们可以搜索:(未完全优化)
locateL :: (t -> Bool) -> [t] -> Maybe (t, List' t)
locateL _ [] = Nothing
locateL f (x:xs) | f x = Just (x, LHit xs)
| otherwise = do
(el, ctx) <- locateL f xs
return (el, LTail x ctx)
locateR :: (t -> Bool) -> Rose t -> Maybe (t, Rose' t)
locateR f (RNode a child)
| f a = Just (a, RHit child)
| otherwise = do
(whichChild, listCtx) <- locateL (isJust . locateR f) child
(el, ctx) <- locateR f whichChild
return (el, RChild a listCtx ctx)
使用上下文信息和mutate(插入漏洞):
updateL :: t -> List' t -> [t]
updateL x (LHit xs) = x:xs
updateL x (LTail a ctx) = a : updateL x ctx
updateR :: t -> Rose' t -> Rose t
updateR x (RHit child) = RNode x child
updateR x (RChild a listCtx ctx) = RNode a (updateL (updateR x ctx) listCtx)