如何为 Applicative 实例制作适当的 "pure"?

How to make a proper "pure" for an Applicative instance?

我发现这个 Applicative 实例至少有 2 个 pure 的实现,它们遵循所有法则(同一性、同态性、互换性、组合性)。还是其中一个错误?

data List a = 
    Nil 
  | Cons a (List a) 
  deriving (Eq, Show) 

newtype ZipList' a = 
  ZipList' (List a) 
  deriving (Eq, Show)

instance Applicative ZipList' where 
  ZipList' fss <*> ZipList' xss = ZipList' $ applicate fss xss
    where applicate (Cons f fs) (Cons x xs) = Cons (f x) (applicate fs xs)
          applicate Nil         _           = Nil
          applicate _           Nil         = Nil
pure x = ZipList' (Cons x Nil)

pure a = ZipList' as
  where as = Cons a as

对于第一个 pure同一性 定律 成立。事实上,这条法律规定:

pure id <*> v = v

这意味着:

ZipList' (Cons id Nil) <*> <i>v</i> = <i>v</i>

所有 v。但这并不成立。说 v = ZipList' (Cons 1 (Cons 2 Nil)),所以基本上是一个列表 [1,2]。那么人们期望:

ZipList' (Cons id Nil) <*> ZipList' (Cons 1 (Cons 2 Nil)) = ZipList' (Cons 1 (Cons 2 Nil))

但是,如果我们评估您对 Applicative 的实施,我们会看到:

ZipList' (Cons id Nil) <*> ZipList' (Cons 1 (Cons 2 Nil))
    = ZipList' (applicate (Cons id Nil) (Cons 1 (Cons 2 Nil)))
    = ZipList' (Cons (id 1) (applicate Nil (Cons 2 Nil)))
    = ZipList' (Cons 1 Nil)

但这不是我们期望的恒等律,因为这里我们得到一个ZipList',基本上是[1],而它应该是[1,2].

每个<*>最多支持一个有效的pure。假设 pure1pure2 都是合法的。然后对于任何 x,

pure2 x
= -- Identity for pure1
pure1 id <*> pure2 x
= -- Interchange for pure2
pure2 ($x) <*> pure1 id
= -- Functor/Applicative for pure2
fmap ($x) (pure1 id)
= -- Functor/Applicative for pure1
pure1 ($x) <*> pure1 id
= -- Homomorphism for pure1
pure1 x