我偶然发现了Getter Functor
在Contravariant
上同时约束f
和(a -> f a) -> s -> f s
的定义。
“getter”对“包含的部分”不起作用并不奇怪,但这个签名在s
的“van Laarhoven”设置中看起来像Phantom。隐含约束“a
是否知道lens
”在Getter
中以这种方式表示?
如何找到map
的某些具体实例的源代码,以便我可以看到contramap
和raw
被使用?
答案 0 :(得分:8)
entrypoint
的想法是它是一个只读镜头。如果Getter
Getter s a
,您可以从a
中提取s
,但不能将其中的一个放入。因此定义了类型:
type Getter s a = forall f. (Contravariant f, Functor f) => (a -> f a) -> s -> f s
当一个类型同时是Functor
和Contravariant
时,它实际上根本不依赖于它的类型参数:
import Data.Void
change :: (Functor f, Contravariant f) => f a -> f b
change = fmap absurd . contramap absurd
对于某些Const b
,这样的仿函数看起来总是非常像b
。
所以Getter s a
基本上是
type Getter s a = forall b . (a -> b) -> s -> b
但为了使其与镜头生态系统的其余部分一起使用,它具有额外的多态性。
答案 1 :(得分:5)
嗯,吸气剂基本上只是一个功能。同构是这样的:
getter :: (Functor f, Contravariant f) => (s->a) -> (a->f a) -> s->f s
getter f q = contramap f . q . f
在这里,contramap
实际上只会强制执行类型,因为正如您所说,Functor
和Contravariant
的组合要求f x
不会实际上包含x
。基本上,确保这也是Functor
约束的唯一原因。
答案 2 :(得分:1)
类型
Getter s a = forall f . (Contravariant f, Functor f) => (a -> f a) -> (s -> f s)
与s -> a
类型同构。同构的两个侧面由
toGetter :: (s -> a) -> Getter s a
toGetter h alpha = contramap h . alpha . h
fromGetter :: Getter s a -> (s -> a)
fromGetter getter = getConst . getter Const
不难看出fromGetter (toGetter h)
等于h
。
到现在为止(即为了实现toGetter
和fromGetter
并证明fromGetter . toGetter = id
),我们还没有使用Functor f
约束。但是,为了证明toGetter . fromGetter = id
是必需的。
首先假设f
既是协变Functor
也是Contravariant
函子。然后,任何函数g :: x -> y
都会产生函数fmap g :: f x -> f y
和contramap g :: f y -> f x
。参数性与函子定律相结合,使它们相互相反,即f x ≅ f y
。因此,f
是(直到同构)常数函数,因此我们可以认为Getter s a
被定义为
Getter s a = forall f0 . (a -> b) -> (s -> b)
(如dfeuer的回答所述)。根据Yoneda引理,这与s -> a
是同构的。
值得注意的是,如果我们取消Functor f
约束:
OddGetter s a = forall f . Contravariant f => (a -> f a) -> (s -> f s)
然后,我们获得Getter s a
的子类型,该子类型不再与s -> a
同构,而是与s -> Aux a s
同构:
newtype Aux a x = Aux {aAux :: a, gAux :: x -> a}
instance Contravariant (Aux a) where
contramap f (Aux a g) = Aux a (g . f)
toAux :: a -> Aux a a
toAux a = Aux a id
(Aux a, toAux)
是所有对(F, toF)
的缩写,其中F
是互逆函子,toF :: a -> F a
类似于(Const a, Const)
的缩写在所有对(F, toF)
中,其中F
是协变函数和toF :: a -> F a
的函子。
同构的两个方面可以实现如下:
toOddGetter :: (s -> Aux a s) -> OddGetter s a
toOddGetter sigma alpha s1 =
contramap (\s2 -> gAux (sigma s1) s2) $ alpha $ aAux (sigma s1)
fromOddGetter :: OddGetter s a -> (s -> Aux a s)
fromOddGetter getter = getter toAux
同样,很容易检查fromOddGetter . toOddGetter = id
,它已经表明OddGetter s a
与s -> a
同构( not )。为了证明fromOddGetter . toOddGetter = id
,我们再次需要一个参数论证。
参数性意味着对于任何自然变换nu :: forall x . d x -> f x
,任何getter :: OddGetter s a
和任何alphaD :: a -> d a
,我们都有
nu . getter alphaD = getter (nu . alphaD) :: s -> f s
现在,我们将d
实例化为Aux a
,将alphaD
实例化为toAux
,将nu
实例化为{{1} }):
factor alpha
,其属性为alpha : a -> f a
。然后我们有
factor :: (a -> f a) -> forall x . Aux a x -> f x
factor alpha (Aux a g) = contramap g $ alpha a
现在,当我们将其应用于某些factor alpha . toAux = alpha
时,我们发现factor alpha . getter toAux = getter (factor alpha . toAux) = getter alpha :: s -> f s
(应用的RHS)等于
s1 :: s
即getter alpha s1
。
鉴于同构,这种类型也许很明显
factor alpha (getter toAux s1)
= contramap (gAux $ getter toAux s1) $ alpha (aAux $ getter toAux s1)
{-by definition of factor-}
= contramap (\s2 -> gAux (getter toAux s1) s2) $ alpha $ aAux (getter toAux s1)
{-by eta-expansion and regrouping-}
= toOddGetter (getter toAux) alpha s1
{-by definition of toOddGetter-}
= toOddGetter (fromOddGetter getter) alpha s1
{-by definition of fromOddGetter-}
是
的子类型getter = toOddGetter (fromOddGetter getter)
“强制”功能
OddGetter s a ≅ s -> Aux a s
对应于功能
Getter s a ≅ s -> a
在这些同构下。