Comonads 或 Representable 上的透镜
Lenses over Comonads or Representable
下面是这个问题的一个更具体的变体:Mutate only focus of Store Comonad?,以免一次问多个问题。
是否有兼容 Control.Lens 的镜头允许我与 comonad 的焦点(来自 extract
的值)或商店 Comonad 的 index/value 交互( pos
)?
好像镜片在这里有点用处,但一直没找到合适的;任何帮助将不胜感激,谢谢!
Comonad
没有给你任何写回 comonad 焦点的方法,所以你不能为 extract
写一个通用的 Lens
。但是 it is very easy to turn any old function into a Getter
:
extracted :: Comonad w => Getter (w a) a
extracted = to extract
当然很多comonads做让你写成重点-Store
,如你所说,而且(包括但不限于)Env
、Traced
和 Identity
.
-- I suspect some of these laws are redundant:
-- write id = id
-- write f . write g = write (f . g)
-- extract . write f = f . extract
-- duplicate . write f = write (write f) . duplicate
-- write (const (extract w)) w = w
class Comonad w => ComonadWritable w where
write :: (a -> a) -> w a -> w a
instance ComonadWritable Identity where
write f (Identity x) = Identity (f x)
-- law-abiding "up to Eq"
instance (Eq s, ComonadWritable w) => ComonadWritable (StoreT s w) where
write f (StoreT w s) = StoreT (write g w) s
where
g k s'
| s' == s = f (k s')
| otherwise = k s'
-- law-abiding "up to Eq"
instance (Eq m, Monoid m, ComonadWritable w) => ComonadWritable (TracedT m w) where
write f (TracedT w) = TracedT (write g w)
where
g k m
| m == mempty = f (k m)
| otherwise = k m
instance ComonadWritable w => ComonadWritable (EnvT e w) where
write f (EnvT e w) = EnvT e (write f w)
给定 ComonadWritable
很容易为 comonad 的焦点构建 Lens
。
focus :: ComonadWritable w => Lens' (w a) a
focus = lens extract (\w x -> write (const x) w)
关于效率的一个注意事项:StoreT
和 TracedT
的 write
实现构建了一个函数链,在向下的过程中进行了相等性检查,所以 extract
是 O (n) 在 write
次调用中。既然你提到你正在使用 Representable
comonad w
,你可以实施一些聪明的策略来批量编辑并经常将它们具体化为实际的 w
。或者,您可以将编辑存储在 Map
中(将 Eq
约束加强为 Ord
),并在发现元素未被编辑时委托给基础 w
。我会把那部分留给你。
下面是这个问题的一个更具体的变体:Mutate only focus of Store Comonad?,以免一次问多个问题。
是否有兼容 Control.Lens 的镜头允许我与 comonad 的焦点(来自 extract
的值)或商店 Comonad 的 index/value 交互( pos
)?
好像镜片在这里有点用处,但一直没找到合适的;任何帮助将不胜感激,谢谢!
Comonad
没有给你任何写回 comonad 焦点的方法,所以你不能为 extract
写一个通用的 Lens
。但是 it is very easy to turn any old function into a Getter
:
extracted :: Comonad w => Getter (w a) a
extracted = to extract
当然很多comonads做让你写成重点-Store
,如你所说,而且(包括但不限于)Env
、Traced
和 Identity
.
-- I suspect some of these laws are redundant:
-- write id = id
-- write f . write g = write (f . g)
-- extract . write f = f . extract
-- duplicate . write f = write (write f) . duplicate
-- write (const (extract w)) w = w
class Comonad w => ComonadWritable w where
write :: (a -> a) -> w a -> w a
instance ComonadWritable Identity where
write f (Identity x) = Identity (f x)
-- law-abiding "up to Eq"
instance (Eq s, ComonadWritable w) => ComonadWritable (StoreT s w) where
write f (StoreT w s) = StoreT (write g w) s
where
g k s'
| s' == s = f (k s')
| otherwise = k s'
-- law-abiding "up to Eq"
instance (Eq m, Monoid m, ComonadWritable w) => ComonadWritable (TracedT m w) where
write f (TracedT w) = TracedT (write g w)
where
g k m
| m == mempty = f (k m)
| otherwise = k m
instance ComonadWritable w => ComonadWritable (EnvT e w) where
write f (EnvT e w) = EnvT e (write f w)
给定 ComonadWritable
很容易为 comonad 的焦点构建 Lens
。
focus :: ComonadWritable w => Lens' (w a) a
focus = lens extract (\w x -> write (const x) w)
关于效率的一个注意事项:StoreT
和 TracedT
的 write
实现构建了一个函数链,在向下的过程中进行了相等性检查,所以 extract
是 O (n) 在 write
次调用中。既然你提到你正在使用 Representable
comonad w
,你可以实施一些聪明的策略来批量编辑并经常将它们具体化为实际的 w
。或者,您可以将编辑存储在 Map
中(将 Eq
约束加强为 Ord
),并在发现元素未被编辑时委托给基础 w
。我会把那部分留给你。