- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使二叉树 zipper 成为comonad的实例,但我不知道如何正确实现duplicate
。
这是我的尝试:
{-# LANGUAGE DeriveFunctor #-}
import Data.Function
import Control.Arrow
import Control.Comonad
data BinTree a
= Leaf a
| Branch a (BinTree a) (BinTree a)
deriving (Functor, Show, Eq)
data Dir = L | R
deriving (Show, Eq)
-- an incomplete binary tree, aka data context
data Partial a = Missing Dir (BinTree a) a
deriving (Show, Eq, Functor)
-- BTZ for BinTree Zipper
newtype BTZ a = BTZ { getBTZ :: ([Partial a], BinTree a) }
deriving (Show, Eq)
instance Functor BTZ where
fmap f (BTZ (cs,t)) = BTZ (map (fmap f) cs, fmap f t)
-- | replace every node label with the zipper focusing on that node
dup :: BinTree a -> BinTree (BTZ a)
dup (Leaf v) = Leaf (BTZ ([], Leaf v))
dup t@(Branch v tl tr) = Branch (BTZ ([],t)) tlZ trZ
where
tlZ = fmap (BTZ . first (++ [Missing L tr v]) . getBTZ) (dup tl)
trZ = fmap (BTZ . first (++ [Missing R tl v]) . getBTZ) (dup tr)
-- | extract root label
rootVal :: BinTree a -> a
rootVal (Leaf v) = v
rootVal (Branch v _ _) = v
-- | move zipper focus around
goUp, goLeft, goRight :: BTZ a -> BTZ a
goUp (BTZ ([], _)) = error "already at root"
goUp (BTZ (Missing wt t2 v:xs, t1)) = case wt of
L -> BTZ (xs, Branch v t1 t2)
R -> BTZ (xs, Branch v t2 t1)
goLeft z = let (cs,t) = getBTZ z in
case t of
Leaf _ -> error "already at leaf"
Branch v t1 t2 -> BTZ (Missing L t2 v:cs, t1)
goRight z = let (cs,t) = getBTZ z in
case t of
Leaf _ -> error "already at leaf"
Branch v t1 t2 -> BTZ (Missing R t1 v:cs, t2)
instance Comonad BTZ where
extract (BTZ (_,t)) =
case t of
Leaf v -> v
Branch v _ _ -> v
duplicate z@(BTZ (cs, bt)) = case bt of
Leaf _ -> BTZ (csZ, Leaf z) -- extract . duplicate = id
Branch v tl tr ->
-- for each subtree, use "dup" to build zippers,
-- and attach the current focusing root(bt) and rest of the data context to it
let tlZ = fmap (BTZ . first (++Missing L tr v :cs) . getBTZ) (dup tl)
trZ = fmap (BTZ . first (++Missing R tl v :cs) . getBTZ) (dup tr)
in BTZ (csZ, Branch z tlZ trZ)
where
-- go up and duplicate, we'll have a "BTZ (BTZ a)"
-- from which we can grab "[Partial (BTZ a)]" out
-- TODO: not sure if it works
upZippers = take (length cs-1) . tail $ iterate goUp z
csZ = fmap (head . fst . getBTZ . duplicate) upZippers
main :: IO ()
main = do
let tr :: BTZ Int
tr = rootVal $ dup (Branch 1 (Leaf 2) (Branch 3 (Leaf 4) (Leaf 5)))
equalOnTr :: Eq a => (BTZ Int -> a) -> (BTZ Int -> a) -> Bool
equalOnTr = (==) `on` ($ tr)
print $ (extract . duplicate) `equalOnTr` id
print $ (fmap extract . duplicate) `equalOnTr` id
print $ (duplicate . duplicate) `equalOnTr` (fmap duplicate . duplicate)
BinTree a
是二叉树数据类型,每个树节点都包含一个标签。 Partial a
是带有左或右子树的二叉树。一堆Partial a
在我的代码中扮演数据上下文的角色。 BTZ
代表BinTree
zipper ,我要创建Comonad
的实例,它由数据上下文和焦点子树组成。 Comonad
的实例,我的计划是实现
extract
和
duplicate
,并通过采用一些随机的二叉树来验证comonad属性是否成立。
extract
很简单,只需取出聚焦子树即可。
dup
用作替换每个节点标签的辅助函数
duplicate z
,节点标签本身必须是
z
,以便
extract . duplicate == id
成立。对于非叶节点,我使用
dup
来处理它们的子树,就好像它们没有父级一样,并且
z
当前的关注点和其余数据上下文随后将附加到这些 zipper 中。
extract . duplicate = id
和
fmap extract . duplicate
),但是我不知道该如何处理数据上下文。我目前正在做的是 zipper
z
并保持增长。在此过程中,我们以每个数据上下文堆栈的顶部为基础来构建新的数据上下文堆栈,这听起来很正确,并且类型正确(
[Partial (BTZ a)]
。)但是我的方法不能满足第三定律。
最佳答案
在微积分中,莱布尼兹的概念引起的混淆比牛顿的引起的少,这是因为它清楚地表明了我们要区分的变量。事物中的上下文是通过差异给出的,因此我们必须注意上下文中的内容。这里,有两个“子结构”概念在起作用:子树和元素。它们各自具有“上下文”和“ zipper ”的不同(但相关)概念,其中 zipper 是事物及其上下文的对。
您的BTZ
类型表示为子树的zipper概念。但是, zipper comonadic构造在元素的 zipper 上起作用:extract
表示“在此处提供元素”; duplicate
的意思是“用上下文装饰每个元素”。因此,您需要元素上下文。令人困惑的是,对于这些二叉树,元素 zipper 和子树 zipper 是同构的,但这是出于一个非常特殊的原因(即它们形成了共自由共态)。
通常,例如对于列表,元素和子树 zipper 是不同的。如果我们从构建列表的元素 zipper 开始,那么当我们回到树上时,我们就不太可能迷路。让我也尝试为他人以及您自己补充一些概况。
子列表上下文[a]
只是给出了[a]
的子列表上下文,是我们从子列表到整个列表的途中经过的元素列表。 [3,4]
中[1,2,3,4]
的子列表上下文是[2,1]
。递归数据的子节点上下文始终是代表您在从节点到根的路径上看到的内容的列表。相对于递归变量,每个步骤的类型由一个数据节点的公式的偏导数给出。所以在这里
[a] = t where -- t is the recursive variable standing for [a]
t = 1 + a*t -- lists of a are either [] or an (a : t) pair
∂/∂t (1 + a*t) = a -- that's one step on a path from node to root
sublist contexts are [a] -- a list of such steps
data LinLZ a = LinLZ
{ subListCtxt :: [a]
, subList :: [a]
}
plugLinLZ :: LinLZ a -> [a]
plugLinLZ (LinLZ { subListCtxt = [], subList = ys}) = ys
plugLinLZ (LinLZ { subListCtxt = x : xs, subList = ys})
= plugLinLZ (LinLZ { subListCtxt = xs, subList = x : ys})
LinLZ
设为
Comonad
,因为(例如)来自
LinLZ { subListCtxt = [], subList = [] }
extract
一个元素(
a
中的
LinLZ a
),只能是一个子列表。
[a] = t where -- t is the recursive variable standing for [a]
t = 1 + a*t -- lists of a are either [] or an (a : t) pair
∂/∂a (1 + a*t) = t = [a] -- the context for the head element is the tail list
type DL a =
( [a] -- the sublist context for the node where the element is
, [a] -- the tail of the node where the element is
)
data ZL a = ZL
{ this :: a
, between :: DL a
} deriving (Show, Eq, Functor)
outZL :: ZL a -> [a]
outZL (ZL { this = x, between = (zs, xs) })
= plugLinLZ (LinLZ { subListCtxt = zs, subList = x : xs })
into :: [a] -> [ZL a]
into xs = moreInto (LinLZ { subListCtxt = [], subList = xs })
moreInto :: LinLZ a -> [ZL a]
moreInto (LinLZ { subListCtxt = _, subList = [] }) = []
moreInto (LinLZ { subListCtxt = zs, subList = x : xs })
= ZL { this = x, between = (zs, xs) }
: moreInto (LinLZ { subListCtxt = x : zs, subList = xs })
subList
的形状。另外,
x
位置的 zipper 具有
this = x
。另外,用于装饰
xs
的生成 zipper 具有
subList = xs
和正确的上下文,
x
。测试,
into [1,2,3,4] =
[ ZL {this = 1, between = ([],[2,3,4])}
, ZL {this = 2, between = ([1],[3,4])}
, ZL {this = 3, between = ([2,1],[4])}
, ZL {this = 4, between = ([3,2,1],[])}
]
instance Comonad ZL where
extract
为我们提供了我们要访问的元素。
extract = this
duplicate
一个 zipper ,我们用整个当前的zip
x
(其
zl
)替换当前元素
this = x
...
duplicate zl@(ZL { this = x, between = (zs, ys) }) = ZL
{ this = zl
moreInto
可让我们向内移动,但我们还必须移动
outward
...
, between =
( outward (LinLZ { subListCtxt = zs, subList = x : ys })
, moreInto (LinLZ { subListCtxt = x : zs, subList = ys })
)
}
where
outward (LinLZ { subListCtxt = [], subList = _ }) = []
outward (LinLZ { subListCtxt = z : zs, subList = ys })
= ZL { this = z, between = (zs, ys) }
: outward (LinLZ { subListCtxt = zs, subList = z : ys })
duplicate ZL {this = 2, between = ([1],[3,4])}
= ZL
{ this = ZL {this = 2, between = ([1],[3,4])}
, between =
( [ ZL {this = 1, between = ([],[2,3,4])} ]
, [ ZL {this = 3, between = ([2,1],[4])}
, ZL {this = 4, between = ([3,2,1],[])}
]
)
}
this
是“停留在
2
上”,而我们
between
是“移至
1
”和“移至
3
或移至
4
”。
duplicate
d是元素 zipper 。
TF
)。
data TF t = Leaf | Fork (t, t) deriving (Show, Eq, Functor)
data BT a = a :& TF (BT a) deriving (Show, Eq, Functor)
TF
...
data CoFree f a = a :& f (CoFree f a) deriving (Functor)
f
,之前我们有
TF
。我们可以恢复我们的特定树木。
data TF t = Leaf | Fork (t, t) deriving (Show, Eq, Functor)
type BT = CoFree TF
deriving instance Show a => Show (BT a)
deriving instance Eq a => Eq (BT a)
instance Functor f => Comonad (CoFree f) where
extract (a :& _) = a -- extract root element
duplicate t@(a :& ft) = t :& fmap duplicate ft -- replace root element by whole tree
aTree =
0 :& Fork
( 1 :& Fork
( 2 :& Leaf
, 3 :& Leaf
)
, 4 :& Leaf
)
duplicate aTree =
(0 :& Fork (1 :& Fork (2 :& Leaf,3 :& Leaf),4 :& Leaf)) :& Fork
( (1 :& Fork (2 :& Leaf,3 :& Leaf)) :& Fork
( (2 :& Leaf) :& Leaf
, (3 :& Leaf) :& Leaf
)
, (4 :& Leaf) :& Leaf
)
[]
没有元素。在舒适的社区中,总有一个元素在您所在的位置,您可以看到更深的树状结构,但看不到更深的树状结构。
d/dt (TF t) = d/dt (1 + t*t) = 0 + (1*t + t*1)
type DTF t = Either ((), t) (t, ())
plugF :: t -> DTF t -> TF t
plugF t (Left ((), r)) = Fork (t, r)
plugF t (Right (l, ())) = Fork (l, t)
t
并与节点标签配对,我们将获得子树上下文的一步
type BTStep a = (a, DTF (BT a))
Partial
同构。
plugBTinBT :: BT a -> BTStep a -> BT a
plugBTinBT t (a, d) = a :& plugF t d
BT a
给出了另一个
[BTStep a]
内部的子树上下文。
data DBT a = DBT
{ below :: TF (BT a) -- the rest of the element's node
, above :: [BTStep a] -- the subtree context of the element's node
} deriving (Show, Eq)
Functor
实例。
instance Functor DBT where
fmap f (DBT { above = a, below = b }) = DBT
{ below = fmap (fmap f) b
, above = fmap (f *** (either
(Left . (id *** fmap f))
(Right . (fmap f *** id)))) a
}
data BTZ a = BTZ
{ here :: a
, ctxt :: DBT a
} deriving (Show, Eq, Functor)
above
,以及一个由
here
和
below
给出的子树。那是因为唯一的元素是那些标记节点的元素。
down :: BT a -> BT (BTZ a)
down t = downIn t []
downIn :: BT a -> [BTStep a] -> BT (BTZ a)
downIn (a :& ft) ads =
BTZ { here = a, ctxt = DBT { below = ft, above = ads } }
:& furtherIn a ft ads
a
已替换为关注
a
的 zipper 。子树由另一个助手处理。
furtherIn :: a -> TF (BT a) -> [BTStep a] -> TF (BT (BTZ a))
furtherIn a Leaf ads = Leaf
furtherIn a (Fork (l, r)) ads = Fork
( downIn l ((a, Left ((), r)) : ads)
, downIn r ((a, Right (l, ())) : ads)
)
furtherIn
保留了树结构,但是在访问子树时适当地增加了子树上下文。
down aTree =
BTZ { here = 0, ctxt = DBT {
below = Fork (1 :& Fork (2 :& Leaf,3 :& Leaf),4 :& Leaf),
above = []}} :& Fork
( BTZ { here = 1, ctxt = DBT {
below = Fork (2 :& Leaf,3 :& Leaf),
above = [(0,Left ((),4 :& Leaf))]}} :& Fork
( BTZ { here = 2, ctxt = DBT {
below = Leaf,
above = [(1,Left ((),3 :& Leaf)),(0,Left ((),4 :& Leaf))]}} :& Leaf
, BTZ { here = 3, ctxt = DBT {
below = Leaf,
above = [(1,Right (2 :& Leaf,())),(0,Left ((),4 :& Leaf))]}} :& Leaf
)
, BTZ { here = 4, ctxt = DBT {
below = Leaf,
above = [(0,Right (1 :& Fork (2 :& Leaf,3 :& Leaf),()))]}} :& Leaf)
Comonad
实例。像之前一样...
instance Comonad BTZ where
extract = here
extract
告诉我们重点所在的元素,我们可以利用我们现有的机制来深入研究这棵树,但是我们需要构建新的工具包来探索向外移动的方式。
duplicate z@(BTZ { here = a, ctxt = DBT { below = ft, above = ads }}) = BTZ
{ here = z
, ctxt = DBT
{ below = furtherIn a ft ads -- move somewhere below a
, above = go_a (a :& ft) ads -- go above a
}
} where
go_a t [] = []
go_a t (ad : ads) = go_ad t ad ads : go_a (plugBTinBT t ad) ads
go_ad t (a, d) ads =
( BTZ { here = a, ctxt = DBT { below = plugF t d, above = ads } } -- visit here
, go_d t a d ads -- try other subtree
)
go_d t a (Left ((), r)) ads = Left ((), downIn r ((a, Right (t, ())) : ads))
go_d t a (Right (l, ())) ads = Right (downIn l ((a, Left ((), t)) : ads), ())
1
:
duplicate (BTZ {here = 1, ctxt = DBT {
below = Fork (2 :& Leaf,3 :& Leaf),
above = [(0,Left ((),4 :& Leaf))]}}) =
BTZ {here = BTZ {here = 1, ctxt = DBT {
below = Fork (2 :& Leaf,3 :& Leaf),
above = [(0,Left ((),4 :& Leaf))]}}, ctxt = DBT {
below = Fork (BTZ {here = 2, ctxt = DBT {
below = Leaf,
above = [(1,Left ((),3 :& Leaf)),(0,Left ((),4 :& Leaf))]}} :& Leaf
,BTZ {here = 3, ctxt = DBT {
below = Leaf,
above = [(1,Right (2 :& Leaf,())),(0,Left ((),4 :& Leaf))]}} :& Leaf
),
above = [(BTZ {here = 0, ctxt = DBT {
below = Fork (1 :& Fork (2 :& Leaf,3 :& Leaf),4 :& Leaf),
above = []}}
,Left ((),BTZ {here = 4, ctxt = DBT {
below = Leaf,
above = [(0,Right (1 :& Fork (2 :& Leaf,3 :& Leaf),()))]}} :& Leaf)
)
]}}
fmap (\ z -> extract (duplicate z) == z) (down aTree)
= True :& Fork (True :& Fork (True :& Leaf,True :& Leaf),True :& Leaf)
fmap (\ z -> fmap extract (duplicate z) == z) (down aTree)
= True :& Fork (True :& Fork (True :& Leaf,True :& Leaf),True :& Leaf)
fmap (\ z -> fmap duplicate (duplicate z) == duplicate (duplicate z)) (down aTree)
= True :& Fork (True :& Fork (True :& Leaf,True :& Leaf),True :& Leaf)
关于haskell - 如何使二叉树 zipper 成为Comonad的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25519767/
我一直试图理解为什么我的代码在一个 zip 上不起作用,而在另一个 zip 上不起作用...... THIS zip 解压 , 和 THIS zipper 没有这是我使用的代码: String zip
我最近才开始使用 Java 处理 zip 文件。到目前为止,一切似乎都计划得很好,但我遇到了最后一个障碍:嵌套 zipper 。 我正在尝试搜索具有特定扩展名的文件,以便将它们作为文本文件读取。到目前
我不确定我的命名法在这里是否正确,但我想知道 Haskell 中是否有一个贪婪的 zip 函数。这意味着如果我有 a = [1, 2, 3] b = [4, 5] zip' a b #=> [(Jus
在 Data.Tree.Zipper 中,玫瑰树的 zipper 数据类型是 data TreePos t a = Loc { _content :: t a -- ^ The
我正在比较 Huet's original paper与 Clojure's implementation并试图弄清楚为什么要进行更改。我是 Clojure 新手,所以如果我对 Clojure 代码的
编辑 #2: 这整个问题和探索都是基于我忽略了 zipper 的基本概念;从特定节点的角度来看,它们代表了数据结构中的一个视角。所以 zipper - 在任何时候 - 一对当前节点以及从该节点的角度来
我正在尝试为长度索引列表实现一种 zipper ,它将返回列表的每个项目与删除该元素的列表配对。例如。对于普通列表: zipper :: [a] -> [(a, [a])] zipper = go [
我有两列,第一列的每个单元格包含以逗号分隔的名字列表,第二列的每个单元格包含以逗号分隔的第二名字列表。我需要将两列“压缩”到第三列,其中包含以逗号分隔的全名列表。 例如: Column A
经过几天的努力,我想我终于明白了如何从连续数据创建它们。 但是,搜索了几天后,我似乎找不到任何有关如何将 zipper 转换成其他东西的资源。基本上,我想将一些数据转换为可以传递给 Hiccup 来生
我正在努力解决lens和 zippers 。考虑在 ghci 中运行的以下代码 > import Control.Lens > import Control.Zipper > > :t within
我对分离的 Highcharts 系列之间的间隙有疑问。 例如,我有一个包含两个系列的图表。一个从(2004年3月1日)开始,另一个从(2009年3月1日)开始。它们彼此不重叠。在图表上显示时,条形图
受到最近关于 Haskell 中二维网格的问题的启发,我想知道是否可以创建一个二维 zipper 来跟踪列表列表中的位置。列表上的一维 zipper 使我们能够真正有效地在大型列表中进行本地移动(常见
我在编写可以遍历异构节点树的 zipper 时遇到问题。我有 i) map 列表。每个映射都有 ii) 一个 :inputs 键,其值是映射列表。 我想使用 zipper 来访问每一片叶子并添加一个计
repl> (-> root zip/down zip/right) [{:answer-keys [5 6], :id 3} {:l [{:id 2, :answer-keys []}], :pno
我有大量(比如 1000 个)可变大小(比如从 4k 到 400k)的 zip,一个 zip 条目。我设法以经典方式解压所有内容,但性能并不真正令人满意...您是否知道可以帮助提高性能的其他方式(ni
我有以下无法编译的代码。 fn main() { let a = "123" .chars() .chain("4566".chars()) .zip(
在为期末考试做一些动态规划问题的练习时,我发现这个问题难倒了我。 Zippers:给定三个字符串,你要判断是否可以将前两个字符串中的字符组合成第三个字符串。前两个字符串可以任意混合,但每个字符在第三个
我有两个要压缩的列表: a = ((1,2,3), (4,5,6), ... ) h = ('a','b', ... ) 一个简单的 zip(a,h) 返回: [ ((1,2,3),'a'), ((4
我正在上传一个 zip 文件,然后我需要在具有相同文件名的路径中提取该文件。所以我使用了Chumper/Zipper为了完成我的任务,我使用了以下代码,即 $zipper->zip('storage
我正在学习镜头包。我必须说这是一项相当具有挑战性的任务。 有人能告诉我如何用镜头的 zipper 穿过一棵树吗?特别是,我如何编写一个函数来获取根列表并允许我访问子树的分支? 假设我有这棵树。如果我的
我是一名优秀的程序员,十分优秀!