Prism
类似于Iso
,只是两次转换之一是部分转换。是否有光学器件可以同时进行两种转换?
当然可以创建类型(s -> Maybe a, b -> Maybe t)
,但我想知道这样的事情是否可以表示为Optic _ _
?
您可以通过将Hask(例如Optic _ _
,这是Iso
定义为(s -> a, b -> t)
的约束)取代了Hask的特征,从而将(s -> m a, b -> m t)
(即Profunctor
)概括为Iso
超过Kleisli类别(此处为Optic
monad)。
Maybe
[要构造这样的profunctor的一个例子,首先要使用我们要使用的伪isos类型class Monad m => KProfunctor m p where
dimapM :: (s -> m a) -> (b -> m t) -> p a b -> p s t
-- dimapM pure pure = id
-- dimapM f g . dimapM h i = dimapM (h >=> f) (g >=> i)
type Optic p s t a b = p a b -> p s t
type KIso m s t a b = forall p. KProfunctor m p => Optic p s t a b
,然后将(s -> m a, b -> m t)
和s
用作主要索引:
t
data PseudoIso m a b s t = MkPseudoIso
{ toM :: s -> m a
, fromM :: b -> m t
}
instance Monad m => KProfunctor m (PseudoIso m) where
-- exercise for the reader
转到PseudoIso
,请使用KIso
(dimapM
的字段正是PseudoIso
的参数的正确类型)dimapM
转到KIso
,请部分应用于身份PseudoIso
实际上,它不一定是Kleisli类别。任意类别PseudoIso a b a b
上的profunctor都会为您提供一类(:->) :: k -> k -> Type
形式的光学元件。
注意:您可以使用(s :-> a, b :-> t)
定义Choice
的实例,因此也许所有内容都应专门用于KProfunctor Maybe
,以便可以合理地将Maybe
作为Choice
的超类添加,然后KProfunctor
是KIso
的子类型。
让我们看一下profunctor编码。更简单。
[Prism
是Choice
的类,我们正在制作Prism
的子类,因此Prisms
是超类的自然选择:
Choice
如果我们尝试为class Choice p => Weird p where
weird :: (s -> Maybe a) -> (b -> Maybe t) -> p a b -> p s t
编写实例,它将无法正常工作。因此,我们的新型光学器件不是p = (->)
的超类。
层次结构可能看起来像:充其量可能看起来像(也许可以将Setter
从而转换为Traversal
的新光学元件吗?)
Lens
让我们尝试另一个具体的Weird
。我将使用 Lens
/ \
Iso Traversal -> Setter
\ /
Prism
\
Weird
Profunctor
用于实现my blog post: Glassery
ForgetM
[preview
可用于在相反的方向上定义内容(不在type Optic' p s a = p a a -> p s s
preview :: Optic' (ForgetM a) s a -> s -> Maybe a
preview o = runForgetM (o (ForgetM Just))
newtype ForgetM r a b = ForgetM { runForgetM :: a -> Maybe r }
instance Profunctor (ForgetM r) where
dimap f _ (ForgetM p) = ForgetM (p . f)
instance Choice (ForgetM r) where
right' (ForgetM p) = ForgetM (either (const Nothing) p)
instance Weird (ForgetM r) where
weird sa _bt (ForgetM ab) = ForgetM $ \s -> sa s >>= ab
中:]]]
TaggedM
我们现在可以尝试这个。
简单的案例:
Glassery
Prisms可以用作新事物(事物
repreview :: Optic' TaggedM s a -> a -> Maybe s repreview o a = unTaggedM (o (TaggedM (Just a))) newtype TaggedM a b = TaggedM { unTaggedM :: Maybe b } instance Profunctor TaggedM where dimap _sa bt (TaggedM b) = TaggedM (fmap bt b) instance Choice TaggedM where right' (TaggedM b) = TaggedM (fmap Right b) instance Weird TaggedM where weird _sa bt (TaggedM b) = TaggedM (b >>= bt)
):
*Main> preview (weird Just Just) 'x' Just 'x' *Main> repreview (weird Just Just) 'x' Just 'x'
还有一个很好的对称
right' = _Right
:
*Main> preview right' (Left 'x') Nothing *Main> preview right' (Right 'x') Just 'x'
我们可以为其编写
Profunctor
实例:
newtype Re p s t a b = Re { runRe :: p b a -> p t s } instance Profunctor p => Profunctor (Re p s t) where dimap f g (Re p) = Re (p . dimap g f) instance Cochoice p => Choice (Re p s t) where right' (Re p) = Re (p . unright) instance Choice p => Cochoice (Re p s t) where unright (Re p) = Re (p . right')
并且我们注意到,我们需要添加
Weird
作为instance Weird p => Weird (Re p s t) where weird sa bt (Re p) = Re (p . weird bt sa)
的超类:
Cochoice
这看起来很有希望。
van-Laarhoven。这很棘手。
比较profunctor和VL编码中的Weird
:
class (Choice p, Cochoice p) => Weird p where weird :: (s -> Maybe a) -> (b -> Maybe t) -> p a b -> p s t
一个好的开始是假设此
Prism
看起来像
type PrismVL s t a b = forall f p. (Choice p, Applicative f) => p a (f b) -> p s (f t) type PrismP s t a b = forall p. (Choice p) => p a b -> p s t
也许我们也需要加强
Weird
约束。
但是我有一些东西要您尝试。还有一个悬而未决的问题是,这种新型type WeirdOptic s t a b = forall p f. (Weird p, Applicative f) => Optic p f s t a b
光学元件背后的直觉是什么?以及它应具有的定律(成为光学器件,而不仅仅是两个功能砸在一起)。感觉比尝试进行类似的f
/ Weird
光学比Monad
还要漂亮的东西很难,但也许也会奏效。