Haskell 理解Data.Functor.Constant构造函数及其应用定律

Haskell 理解Data.Functor.Constant构造函数及其应用定律,haskell,constants,functor,applicative,monoids,Haskell,Constants,Functor,Applicative,Monoids,我对Data.Functor.Constant的类型构造函数以及它如何与applicative一起工作感到困惑 首先,建造师: 当我检查常量::a->常量a b的类型时 我看到它接受一个a,但返回一个常数ab b从何而来,为什么存在 其次,我正在努力解决应用性问题: 我理解常量需要有一个幺半群才能成为一个应用实例 它必须遵守的法则是:纯id常数x=x 我认为这和:常量id常量x=x 但我想我错了,因为下面的代码清楚地显示了不同的纯行为 :t pure id <*> Constan

我对Data.Functor.Constant的类型构造函数以及它如何与applicative一起工作感到困惑


首先,建造师:

当我检查
常量::a->常量a b的类型时

我看到它接受一个
a
,但返回一个
常数ab

b
从何而来,为什么存在


其次,我正在努力解决应用性问题:

我理解常量需要有一个幺半群才能成为一个应用实例

它必须遵守的法则是:
纯id常数x=x

我认为这和:
常量id常量x=x

但我想我错了,因为下面的代码清楚地显示了不同的纯行为

:t pure id <*> Constant "hello" // Constant [Char] b

:t Constant id <*> Constant "hello" // Couldn't match expected type `a0 -> a0' with actual type `[Char]'

:t pure id <*> Constant reverse //  Constant ([a] -> [a]) b

:t Constant id <*> Constant reverse // Constant ([a] -> [a]) b
:t纯id常量“hello”//Constant[Char]b
:t常量id常量“hello”//无法将预期类型“a0->a0”与实际类型“[Char]”匹配
:t纯id常量反向//常量([a]->[a])b
:t常量id常量反向//常量([a]->[a])b
我发现只有当
x
是同一个幺半群时它才起作用,除非我使用纯幺半群。所以我不知道为什么pure的工作方式不同。我怀疑这与
b
有关,这就是为什么他们在同一个问题中

总结这两个问题:

  • b
    在常量构造函数中做什么

  • 为什么即使幺半群内部不同,纯幺半群也能工作


  • 非常感谢

    好的,你有这种类型的

    data Const a b = Const { getConst :: a }
    
    你的第一个问题是“这个
    b
    从哪里来?”

    答案是它不是来自任何地方。与您可以将
    可能b
    视为一个容器,其中包含类型
    b
    的0或1个值相同,a
    常量a b
    是一个容器,它正好包含类型
    b
    的0个值(但肯定包含类型
    a
    的值)

    你的第二个问题是“它为什么在那里?”

    有时候,有一个函子说它可能包含
    b
    类型的值,但实际上却包含其他的值,这是很有用的(例如,想想
    或者a b
    函子——区别在于
    或者a b
    可能包含
    b
    类型的值,而
    常量a b
    肯定不会)

    然后您询问了代码片段
    pure id Const“hello”
    Const id Const“hello”
    。你以为它们是一样的,但事实并非如此。原因是
    Const
    Applicative
    实例

    instance Monoid m => Applicative (Const m) where
      -- pure :: a -> Const m a
      pure _ = Const mempty
    
      -- <*> :: Const m (a -> b) -> Const m a -> Const m b
      Const m1 <*> Const m2 = Const (m1 <> m2)
    
    data Identity a = Identity { getIdentity :: a }
    
    get :: Lens b a -> b -> a
    get l = getConst . l Const
    
    另一方面,当您编写
    Const id Const“hello”
    时,左侧参数的类型为
    Const(a->a)b
    ,右侧参数的类型为
    Const String b
    ,您会看到类型不匹配,这就是为什么会出现类型错误的原因

    现在,这为什么有用呢?库中有一个应用程序,它允许您在纯函数设置中使用getter和setter(与命令式编程相似)。透镜的简单定义如下:

    type Lens b a = forall f. Functor f => (a -> f a) -> (b -> f b)
    
    i、 e.如果您给它一个转换
    a
    类型值的函数,它将还给您一个转换
    b
    类型值的函数。那有什么用?好吧,让我们为一个特定的函子
    f
    选择一个类型为
    a->fa
    的随机函数。如果我们选择
    Identity
    函子

    instance Monoid m => Applicative (Const m) where
      -- pure :: a -> Const m a
      pure _ = Const mempty
    
      -- <*> :: Const m (a -> b) -> Const m a -> Const m b
      Const m1 <*> Const m2 = Const (m1 <> m2)
    
    data Identity a = Identity { getIdentity :: a }
    
    get :: Lens b a -> b -> a
    get l = getConst . l Const
    
    如果
    l
    是镜头,则定义

    modify :: Lens b a -> (a -> a) -> (b -> b)
    modify l f = runIdentity . l (Identity . f)
    
    为您提供了一种方法,可以将转换
    a
    s的函数转换为转换
    b
    s的函数

    我们可以传入的另一个类型为
    a->fa
    的函数是
    Const::a->Const a a
    (注意,我们已经专门化了第二个类型,因此第二个类型与第一个类型相同)。然后镜头
    l
    的作用是将其转换为
    b->Const a b
    类型的函数,这告诉我们它可能包含
    b
    ,但实际上它实际上暗中包含
    a
    !一旦我们将它应用于
    b
    类型的某个对象以获得
    常数ab
    ,我们就可以使用
    getConst::Const a b->a
    a
    类型的值从帽子中取出。因此,这为我们提供了一种从a
    b
    中提取a类型值的方法,即它是一个getter。定义看起来像

    instance Monoid m => Applicative (Const m) where
      -- pure :: a -> Const m a
      pure _ = Const mempty
    
      -- <*> :: Const m (a -> b) -> Const m a -> Const m b
      Const m1 <*> Const m2 = Const (m1 <> m2)
    
    data Identity a = Identity { getIdentity :: a }
    
    get :: Lens b a -> b -> a
    get l = getConst . l Const
    
    作为镜头示例,您可以定义

    first :: Lens (a,b) a
    first f (a,b) = fmap (\x -> (x,b)) (f a)
    
    这样您就可以打开GHCI会话并编写

    >> get first (1,2)
    1
    >> modify first (*2) (3,4)
    (6,4)
    

    正如你所想象的,这在各种情况下都是有用的。

    答案不错,尽管我认为说“
    Const a b
    是谎称持有
    b
    类型的值”是误导性的。也许“
    a b
    可能包含类型为
    b
    的值,而
    Const a b
    肯定不包含该类型的值。”?@TomEllis这是一个很好的建议,已编辑以包含它。如果您能提供有关我对镜头的解释的反馈,我将不胜感激。这是我第一次尝试解释它。我只想链接到SPJ的视频来解释它。好吧,也许还可以链接到它,并说“这是另一个非常棒的解释。”太棒了!非常感谢。我不敢相信我没有意识到Const部分地应用于mempty。这很有道理。事实上,镜头是我首先考虑这个问题的动机。非常感谢。
    first
    的类型应该是
    Lens(a,b)a