作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在玩Cofree
,并不能完全理解它。
比如我想玩Cofree [] Num
在 ghci 中,并不能得到任何有趣的例子。
例如,如果我构造一个 Cofree 类型:
let a = 1 :< [2, 3]
extract a == 1
,但我收到此错误:
No instance for (Num (Cofree [] a0)) arising from a use of ‘it’
In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
extract a :: (Num a, Num (Cofree [] a)) => a
[]
, 或
Maybe
, 或
Either
,这表明
extract
extend
unwrap
duplicate
? > let a = 1 :< []
> extract a
1
> let b = 1 :< [(2 :< []), (3 :< [])]
> extract b
1
> unwrap b
[2 :< [],3 :< []]
> map extract $ unwrap b
[2,3]
最佳答案
让我们回顾一下 Cofree
的定义数据类型。
data Cofree f a = a :< f (Cofree f a)
1 :< [2, 3]
f = []
和
a
是数字,因为
1 :: a
.相应地你需要
[2, 3] :: [Cofree [] a]
2 :: Cofree [] a
Cofree [] a
就可以了也是
Num
的实例.因此,您的定义获得了一个不太可能被满足的约束,实际上,当您使用您的值时,满足约束的尝试失败了。
1 :< [2 :< [], 3 :< []]
Cofree f ()
?特别是
Cofree [] ()
?后者与
[]
的不动点同构:树结构,其中每个节点都是一个子树列表,也称为“未标记的玫瑰树”。例如。,
() :< [ () :< [ () :< []
, () :< []
]
, () :< []
]
Cofree Maybe ()
或多或少是
Maybe
的固定点: 自然数的副本,因为
Maybe
给我们零个或一个位置来插入子树。
zero :: Cofree Maybe ()
zero = () :< Nothing
succ :: Cofree Maybe () -> Cofree Maybe ()
succ n = () :< Just n
Cofree (Const y) ()
,这是
y
的副本.
Const y
仿函数没有给出子树的位置。
pack :: y -> Cofree (Const y) ()
pack y = () :< Const y
data Cofree nodeOf label = label :< nodeOf (Cofree nodeOf label)
(Const y)
例如,我们得到对
pair :: x -> y -> Cofree (Const y) x
pair x y = x :< Const y
one :: x -> Cofree Maybe x
one = x :< Nothing
cons :: x -> Cofree Maybe x -> Cofree Maybe x
cons x xs = x :< Just xs
0 :< [ 1 :< [ 3 :< []
, 4 :< []
]
, 2 :< []
]
extract
操作为您提供顶级节点的标签。
extract :: Cofree f a -> a
extract (a :< _) = a
extract
丢弃顶部标签的上下文。
duplicate
操作用自己的上下文装饰每个标签。
duplicate :: Cofree f a -> Cofree f (Cofree f a)
duplicate a :< fca = (a :< fca) :< fmap duplicate fca -- f's fmap
Functor
Cofree f
的实例通过访问整棵树
fmap :: (a -> b) -> Cofree f a -> Cofree f b
fmap g (a :< fca) = g a :< fmap (fmap g) fca
-- ^^^^ ^^^^
-- f's fmap ||||
-- (Cofree f)'s fmap, used recursively
fmap extract . duplicate = id
duplicate
用它的上下文装饰每个节点,然后
fmap extract
扔掉装饰。
fmap
只看输入的标签来计算输出的标签。假设我们想根据上下文中的每个输入标签计算输出标签?例如,给定一个未标记的树,我们可能想用其整个子树的大小来标记每个节点。感谢
Foldable
Cofree f
的实例,我们应该能够计算节点。
length :: Foldable f => Cofree f a -> Int
fmap length . duplicate :: Cofree f a -> Cofree f Int
extend :: Comonad c => (c a -> b) -> c a -> c b
extend f = fmap f -- context-dependent map everywhere
. -- after
duplicate -- decorating everything with its context
extend
更直接地为您省去重复的麻烦(虽然那只是共享)。
extend :: (Cofree f a -> b) -> Cofree f a -> Cofree f b
extend g ca@(_ :< fca) = g ca :< fmap (extend g) fca
duplicate
拿回来
duplicate = extend id -- the output label is the input label in its context
extract
作为对上下文中的每个标签要做的事情,您只需将每个标签放回原处:
extend extract = id
g :: c a -> b
extend
的工作是将 co-Kleisli 箭头解释为整个结构上的函数。
extract
操作是身份 co-Kleisli 箭头,由
extend
解释作为恒等函数。当然还有Kleisli的合奏
(=<=) :: Comonad c => (c s -> t) -> (c r -> s) -> (c r -> t)
(g =<= h) = g . extend h
=<=
是联想和吸收
extract
,为我们提供了共同的 Kleisli 类别。此外,我们有
extend (g =<= h) = extend g . extend h
extend
是从 co-Kleisli 范畴到集合和函数的仿函数(在分类意义上)。这些法律不难查
Cofree
,因为它们来自
Functor
节点形状的规律。
a :< fca
a
,或“继续”,通过选择
fca
的子树.例如,考虑
Cofree ((->) move) prize
move
继续: 这是
move
的列表s。比赛进行如下:
play :: [move] -> Cofree ((->) move) prize -> prize
play [] (prize :< _) = prize
play (m : ms) (_ :< f) = play ms (f m)
move
是
Char
和
prize
是解析字符序列的结果。
[move]
是
Free ((,) move) ()
的一个版本.自由单子(monad)代表客户策略。仿函数
((,) move)
相当于一个只有“发送
move
”命令的命令界面。仿函数
((->) move)
是对应的结构“响应
move
的发送”。
data Comms x = Send Char x | Receive (Char -> x)
data Responder x = Resp {ifSend :: Char -> x, ifReceive :: (Char, x)}
chatter :: Free Comms x -> Cofree Responder y -> (x, y)
关于haskell - Haskell 中 Cofree CoMonad 的一些激励示例是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38816993/
背景:C++ inline 关键字不能确定函数是否应该被内联。 相反,内联允许您提供单个函数或变量的多个定义,只要每个定义出现在不同的翻译单元中。 基本上,这允许在头文件中定义全局变量和函数。 是否有
我是一名优秀的程序员,十分优秀!