棱镜是用于聚焦到副产品类型的光学器件,而affine traversal是一种可以聚焦在1个元素的0上的光学器件,即AffineTraversal s t a b(s -> Maybe a, (s, b) -> t)是同构的。据我所知,如果使用适当的棱镜编码,当镜头由棱镜组成时,我们会得到仿射遍历。

我有兴趣将(原始)公式中的Maybe移动到setter端,而不是getter端,这样我就可以拥有一个光学器件,该光学器件总是精确地提取一个元素,但是可能无法将其放回去。

我的用例与优化类型有关。想象一下,我们有一个A类型及其改进的B(B ⊆ A)。然后是一个棱镜refined :: Prism' A B:A可能是有效的B,也可能不是,但是每个B可以是re,进入A。结合Lens' C Arefined,我们就可以进行仿射遍历。在另一个方向上,可以想象光学unrefinedre refined聪明一点:如果A是有效的Just b,则B可以转换为Nothing;如果不是,则可以转换为Lens' C B。现在,如果我们将unrefinedA结合使用,我们将实现双重仿射遍历:它始终可以从C获得A,但是放回任何旧的C可能会违反Nothing的不变性,并产生Just c而不是(s -> a, b -> Maybe t)。可以类似的方式确保更复杂的不变式。

有趣的是,Scala的monocle库为精炼类型提供了棱柱,但没有为反向提供棱柱。

我很难为这些(s -> a, (s, b) -> Maybe t)Cochoice小 object 提出定律,我想知道光学的更抽象的表达方式是否有帮助。

我知道有了专业镜头,我们有

type Lens s t a b = forall p. Strong p => p a b -> p s t
type Prism s t a b = forall p. Choice p => p a b -> p s t
type AffineTraversal s t a b = forall p. (Strong p, Choice p) => p a b -> p s t

这很清楚地表明,镜头放大到产品类型,棱镜放大到副产品类型,仿射遍历具有放大代数数据类型(产品或副产品,不少于)的能力。

答案是否与Costrong甚至ojit_code之类的东西相关(从提示器中删除产品/副产品而不是引入产品/副产品)?我无法从他们那里恢复天真的表述,但是...

最佳答案

这是答案的一半,显示了Cochoice光学镜片和(s -> a, b -> Maybe t)之间的对应关系。

{-# LANGUAGE RankNTypes #-}

module P where

import Data.Profunctor
import Control.Monad

data P a b s t = P (s -> a) (b -> Maybe t)

instance Profunctor (P a b) where
  dimap f g (P u v) = P (u . f) (fmap g . v)

instance Cochoice (P a b) where
  unleft (P u v) = P (u . Left) (v >=> v') where
    v' (Left t) = Just t
    v' (Right _) = Nothing

type Coprism s t a b = forall p. Cochoice p => p a b -> p s t

type ACoprism s t a b = P a b a b -> P a b s t

fromCoprism :: ACoprism s t a b -> P a b s t
fromCoprism p = p (P id Just)

toCoprism :: P a a s t -> Coprism s t a a
toCoprism (P u v) = unleft . dimap f g where
  f (Left s) = u s
  f (Right a) = a
  g b = case v b of
    Nothing -> Right b
    Just t -> Left t

10-08 12:41