数据结构差异化,直觉构建

发布于 2024-11-05 10:57:09 字数 512 浏览 1 评论 0原文

根据本文,微分适用于数据结构。

根据这个答案

微分,数据类型 D 的导数(给出为 D')是具有单个“洞”的 D 结构类型,即不包含任何数据的可区分位置。令人惊讶的是,这满足了与微积分微分相同的规则。

规则是:

 1 = 0
 X′ = 1
 (F + G)′ = F' + G′
 (F • G)′ = F • G′ + F′ • G
 (F ◦ G)′ = (F′ ◦ G) • G′

参考论文有点太复杂,我无法获得直觉。 这在实践中意味着什么?一个具体的例子就太好了。

According to this paper differentiation works on data structures.

According to this answer:

Differentiation, the derivative of a data type D (given as D') is the type of D-structures with a single “hole”, that is, a distinguished location not containing any data. That amazingly satisfy the same rules as for differentiation in calculus.

The rules are:

 1 = 0
 X′ = 1
 (F + G)′ = F' + G′
 (F • G)′ = F • G′ + F′ • G
 (F ◦ G)′ = (F′ ◦ G) • G′

The referenced paper is a bit too complex for me to get an intuition.
What does this this mean in practice? A concrete example would be fantastic.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

简单气质女生网名 2024-11-12 10:57:09

X in an 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。对多项式进行微分可以告诉您直接子树的上下文:叶子中没有子树;在节点中,它要么是左边的洞,右边的树,或者是左边的树,右边的洞。

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)

“下面”的作用是生成与给定树相关的树的居民。

区分数据类型是使“搜索”等程序变得通用的好方法。

What's a one hole context for an X in an X? There's no choice: it's (-), representable by the unit type.

What's a one hole context for an X in an X*X? It's something like (-,x2) or (x1,-), so it's representable by X+X (or 2*X, if you like).

What's a one hole context for an X in an X*X*X? It's something like (-,x2,x3) or (x1,-,x3) or (x1,x2,-), representable by X*X + X*X + X*X, or (3*X^2, if you like).

More generally, an F*G with a hole is either an F with a hole and a G intact, or an F intact and a G with a hole.

Recursive datatypes are often defined as fixpoints of polynomials.

data Tree = Leaf | Node Tree Tree

is really saying Tree = 1 + Tree*Tree. Differentiating the polynomial tells you the contexts for immediate subtrees: no subtrees in a Leaf; in a Node, it's either hole on the left, tree on the right, or tree on the left, hole on the right.

data Tree' = NodeLeft () Tree | NodeRight Tree ()

That's the polynomial differentiated and rendered as a type. A context for a subtree in a tree is thus a list of those Tree' steps.

type TreeCtxt = [Tree']
type TreeZipper = (Tree, TreeCtxt)

Here, for example, is a function (untried code) which searches a tree for subtrees passing a given test subtree.

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)

The role of "below" is to generate the inhabitants of Tree' relevant to the given Tree.

Differentiation of datatypes is a good way make programs like "search" generic.

七色彩虹 2024-11-12 10:57:09

我的解释是,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 = 列表(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(列表)

(这些可能与传统类型不同,其中拉链是“方向”列表,但它们是同构的。)


导数是记录如何对结构中的位置进行编码的系统方法,例如我们可以使用以下命令进行搜索:(没有完全优化)

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)

并使用上下文信息进行变异(插入漏洞):

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)

My interpretation is that, the derivative (zipper) of T is the type of all instances that resembles the "shape" of T, but with exactly 1 element replaced by a "hole".

For instance, a list is

List t = 1     []
       + t     [a]
       + t^2   [a,b]
       + t^3   [a,b,c]
       + t^4   [a,b,c,d]
       + ...   [a,b,c,d,...]

if we replace any of those 'a', 'b', 'c' etc by a hole (represented as @), we'll get

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,@]
        + ...

Another example, a binary tree is

data Tree t = TEmpty | TNode t (Tree t) (Tree t)
-- Tree t = 1 + t (Tree t)^2

so adding a hole generates the type:

{-

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)

A third example which illustrates the chain rule is the rose tree (variadic tree):

data Rose t = RNode t [Rose t]
-- R t = t*List(R t)

the derivative says R' t = List(R t) + t * List'(R t) * R' t, which means

{-

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)

Note that data List' t = LHit [t] | LTail t (List' t).

(These may be different from the conventional types where a zipper is a list of "directions", but they are isomorphic.)


The derivative is a systematic way to record how to encode a location in a structure, e.g. we can search with: (not quite optimized)

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)

and mutate (plug in the hole) using the context info:

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文