Haskell:关于hackage Control.Applicative文章中应用函子法的描述中的缺陷?:它说Applicative确定了Functor

时间:2015-04-15 08:50:27

标签: haskell functor applicative hackage

我想我在the hackage article for Control.Applicative中发现了一个缺陷。 作为应用仿函数法的描述,它说:

class Functor f => Applicative f where
     

带有应用程序的仿函数,提供操作   嵌入纯表达式(pure)和序列计算并组合它们的结果(<*>)。

     

最小完整定义必须包括满足以下法则的这些函数的实现:

     

身份

pure id <*> v = v
     

组合物

pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
     

同态

pure f <*> pure x = pure (f x)
     

交换

u <*> pure y = pure ($ y) <*> u

(请注意,这并未说明有关fmap的任何内容)并且它声明这些法律确定了Functor实例:

  

作为这些法律的结果,f的Functor实例将满足

fmap f x = pure f <*> x

我一开始觉得这显然是错的。也就是说,我猜测必须存在满足以下两个条件的类型构造函数t

  1. tApplicative符合上述规则的实例,
  2. instance (Functor t)有两种不同的实现方式 (即有两个不同的函数fmap1, fmap2 :: (a->b) -> (t a->t b),  满足算子法则。)
  3. 如果(且仅当)上述内容正确无误,则必须 将上述语句重写为

      

    f的Functor实例必须满足

    fmap f x = pure f <*> x
    
         

    由于这些法律,这符合Functor法律。

    这显然是正确的,无论我的猜测是否正确

    我的问题是 我的猜测正确吗?是否有t具有所需条件?


    以下是我自己在尝试回答这个问题时的想法。

    如果我们仅仅是数学家对实际的Haskell编程不感兴趣,我们可以轻松肯定地回答这个问题。事实上,

    t = Identity
    newtype Identity a = Identity {runIdentity :: a}
    

    符合上述要求1和2(事实上,几乎所有事情都可以)。实际上,Identity只是FunctorApplicative的一个实例,如Data.Functor.Identity中所定义。 (这满足fmap f = (pure f <*>)。) 要定义instance (Functor f)的另一个“实现”,请为每种类型a选择两个函数

    transf_a, tinv_a :: a -> a
    

    这样

    tinv_a . transf_a = id
    

    (这是理论上设置,很简单)。现在定义

    instance (Functor Identity) where
     fmap (f :: a->b) = Identity . transf_b . f . tinv_a . runIdentity
    

    这符合Functor法律,如果有

    ,则与琐碎的法律不同
    x :: a
    f :: a -> b
    

    这样

    f x /= transf_b $ f $ tinv_a x
    

    但我们是否可以在Haskell中完成这一点并不明显。是这样的:

    class (Isom a) where
     transf, tinv :: a -> a
    
    instance (Isom a) where
     transf = id
     tinv = id
    
    specialized instance (Isom Bool) where
     transf = not
     tinv = not
    

    可能在Haskell?


    修改

    我忘了写一些非常重要的东西。我认为Control.Applicative是GHC基础包的一部分,所以我也对我的问题的答案是否会因任何GHC语言扩展而改变感兴趣,例如FlexibleInstancesOverlappingInstances还不明白。

2 个答案:

答案 0 :(得分:13)

Haskell中的任何类型最多只能有Functor的一个实例,因此您的猜测不正确:对于没有类型t,可以存在两种不同的instance (Functor t)实现{1}}。请参阅:http://article.gmane.org/gmane.comp.lang.haskell.libraries/15384

答案 1 :(得分:2)

a -> a类型的属性只有两个居民,即id :: a -> a(定义为id x = x)和bottom :: a -> a定义为{{1} }}。

如果我们仅将第一种情况局限于“合理”,我们得出一个重要的数学定理,即至少有一个bottom = error "Infinite loop."类型的函数fmap满足{{1} }和forall a. forall b. (a -> b) -> f a -> f b

如果我们不这样做,那么你是对的,我们有一个案例fmap id = id而另一个案例fmap f . fmap g = fmap (f . g)。但那有点俗气。