镜片覆盖共函子或表示函子

5
这是一个更具体的问题变种:仅改变Store Comonad的聚焦点怎么做?,不要同时提出多个问题。
是否有与Control.Lens兼容的镜头,可以让我与共单子的聚焦点(从extract中获取的值)或Store Comonad的索引/值(pos)进行交互?
似乎镜头在这里可能有些用处,但我一直无法找到符合条件的内容;任何帮助都将不胜感激,谢谢!

我认为这里有两个不同的问题:“我能否使用镜头来处理Comonad的焦点?”和“我能否使用索引光学来处理Representable函子?”我已经回答了第一个问题,但你应该将第二个问题提取出来作为另一个问题。 - Benjamin Hodgson
1个回答

3

Comonad 没有为您提供向 comonad 的焦点写回的任何方法,因此您无法编写通用的 Lens 以进行 extract。但是,将任何旧函数转换为 Getter 非常容易

extracted :: Comonad w => Getter (w a) a
extracted = to extract

当然,很多共同的 Comonad 允许你写入焦点 - Store,正如你所提到的,但也包括(但不限于)EnvTracedIdentity

-- 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)

注意效率方面的问题:StoreTTracedTwrite实现在下降时建立了一个带有等式检查的函数链,因此,extract的时间复杂度是write调用次数的O(n)。既然您提到了使用了一个Representable协同范畴w,您可以实现一些聪明的策略来批处理编辑并将其重新定义为实际的w。或者您可以将编辑存储在Map中(强化Eq约束为Ord),并在发现元素没有被编辑时委派给底层的w。我会将这部分留给您。

这很有帮助,但O(n)是我关心的问题;使用底层向量(来自其他问题)和组合“ix”镜头,我可以做得更好;不过还是谢谢,这很有趣! - Chris Penner
我可以使用底层向量做得更好 - 当您编辑不可变向量的元素时,必须复制整个向量,因此您可以在O(1)extract的代价下获得一个O(n)的write,这就是为什么我建议批处理编辑并仅在每隔一段时间构建新的w,这样您就可以分摊成本并获得读取和写入的O(1)。 - Benjamin Hodgson
@dfeuer 的“write(const(extract w))w = w”法则表示,write 只会定位 w a 中的一个 a,即 extract 定位的那个。我是根据获取然后设置 Lens 法则得出这个结论的。 - Benjamin Hodgson
好问题。你应该恢复你的评论! - Benjamin Hodgson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接