我一直在阅读这个 article 以了解镜头。我知道这与
Edward Knett 的镜头包,但它对基础知识很有用。

因此,A Lens 定义如下:

type Lens a b = (a -> b, b -> a -> a)

有人提到镜头形成一个类别,我一直在
尝试为 Category 类型类创建一个实例。首先,我
编写函数的类型定义:
(.) :: Lens y z -> Lens x y -> Lens x z
id :: Lens x x

在这之后,我只是盯着它一整天。究竟是什么
编写定义的思考过程?

最佳答案

我发现这个 article(Joseph Abrahamson 在 fpcomplete 上从零开始的镜头)非常好,它从你开始使用的相同镜头表示开始,定义了它的构图,并沿着路径继续前进到更类似于 lens 的表示

编辑:在做这种事情时,我发现类型孔非常好:

(<.>):: Lens y z -> Lens x y -> Lens x z
(getA,setA) <.> (getB,setB) = (_,_)

所以现在我们有 2 个孔,元组中的第一个说(输出已清理):
Found hole ‘_’ with type: x -> z
...
Relevant bindings include
  setB :: y -> x -> x
  getB :: x -> y
  setA :: z -> y -> y
  getA :: y -> z
  (<.>) :: Lens y z -> Lens x y -> Lens x z

仔细查看绑定(bind),我们已经拥有了我们需要的东西! getB :: x -> ygetA :: y -> z 与函数组合 (.) :: (b -> c) -> (a -> b) -> a -> c
所以我们很高兴地插入这个:
(<.>):: Lens y z -> Lens x y -> Lens x z
(getA,setA) <.> (getB,setB) = (getA . getB, _)

并继续第二种类型的孔,它说:
Found hole ‘_’ with type: z -> x -> x
Relevant bindings include
  setB :: y -> x -> x
  getB :: x -> y
  setA :: z -> y -> y
  getA :: y -> z

我们拥有的最相似的是 setA :: z -> y -> y ,我们首先插入一个 lambda,捕获参数:
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> _)

将您的类型孔更改为:
Found hole ‘_’ with type: x
Relevant bindings include
  x :: x
  z :: z
  setB :: y -> x -> x
  getB :: x -> y
  setA :: z -> y -> y
  getA :: y -> z

我们可以插入类型检查的 x ,但不会给我们想要的东西(设置时什么也没发生)。唯一可以为我们提供 x 的其他绑定(bind)是 setB ,因此我们插入:
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> setB _ _)

我们的第一种类型孔说:
Found hole ‘_’ with type: y
Relevant bindings include
  x :: x
  z :: z
  setB :: y -> x -> x
  getB :: x -> y
  setA :: z -> y -> y
  getA :: y -> z

所以我们需要一个 y,看看范围内的内容,如果我们给它一个 getBy 可以给我们一个 x ,我们碰巧有,但这会导致我们再次无用的镜头什么都不做。另一种方法是使用 setA :
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> setB (setA _ _) _)

(从这里开始加快速度)
同样,第一个洞需要 z 类型的东西,他碰巧将它作为我们 lambda 的参数:
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> setB (setA z _) _)

为了填充 y 类型的第一个类型孔,我们可以使用 getB :: x -> y 给它我们的 lambda 参数:
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> setB (setA z (getB x)) _)

这给我们留下了一个剩余的类型漏洞,可以简单地替换为 x ,导致最终定义:
(<.>):: Lens y z -> Lens x y -> Lens x z
(getA,setA) <.> (getB,setB) = (getA . getB, \z x -> setB (setA z (getB x)) x)

您可以尝试为自己定义 id,必要时使用类型孔和 hoogle

关于haskell - 自定义镜头的书写类别实例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22404939/

10-12 14:01