Comonad
没有为您提供向 comonad 的焦点写回的任何方法,因此您无法编写通用的 Lens
以进行 extract
。但是,将任何旧函数转换为 Getter
非常容易:
extracted :: Comonad w => Getter (w a) a
extracted = to extract
当然,很多共同的 Comonad 允许你写入焦点 - Store
,正如你所提到的,但也包括(但不限于)Env
、Traced
和 Identity
。
class Comonad w => ComonadWritable w where
write :: (a -> a) -> w a -> w a
instance ComonadWritable Identity where
write f (Identity x) = Identity (f x)
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'
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
的时间复杂度是
write
调用次数的O(n)。既然您提到了使用了一个
Representable
协同范畴
w
,您可以实现一些聪明的策略来批处理编辑并将其重新定义为实际的
w
。或者您可以将编辑存储在
Map
中(强化
Eq
约束为
Ord
),并在发现元素没有被编辑时委派给底层的
w
。我会将这部分留给您。
Comonad
的焦点?”和“我能否使用索引光学来处理Representable
函子?”我已经回答了第一个问题,但你应该将第二个问题提取出来作为另一个问题。 - Benjamin Hodgson