1

我正在做Typeclassopedia的练习;在该Applicative部分中,我编写了ZipList'spure函数,并检查它是否遵循Applicative法律。

我检查过:

  • 身份法
  • 互换法
  • 组成法

但是当我尝试检查“同态”定律时,我发现 GHCi 没有得到MZipList.

我认为这是因为我错过了指定pure我的Applicative类型类。没有它如何立即运行pure函数?</p> <*>Applicative

这是MZipList定义和类实例:

newtype MZipList a = MZipList { getZipList :: [a] }
    deriving (Show)

instance Functor MZipList where
  fmap gs x = pure gs <*> x

instance Applicative MZipList where
  pure a= MZipList (repeat a)
  (MZipList gs) <*> (MZipList xs) = MZipList (zipWith ($) gs xs)

当我检查“交换”法时,例如:

*Main> (MZipList [(*2),(*3),(*4)]) <*> pure (2)
MZipList {getZipList = [4,6,8]}
*Main> pure ($ 2) <*> (MZipList [(*2),(*3),(*4)])
MZipList {getZipList = [4,6,8]}

但是当我检查“同态”定律时,不叫MZipList's :pure

*Main> pure (*2) <*> pure 2
4
*Main>  pure ((*2) 2)
4
*Main>

这是为什么?

4

1 回答 1

7

是什么pure

pure只是一个在特定Applicativemonad 中“插入”对象的函数。例如在:

test :: [Int]
test = pure 1 -- [1]

我们正在插入1列表 monad,这会导致单例[1]。如果您已经阅读过有关该Monad课程的内容,那么pure基本相同return(如果您不担心)。

您的实例Applicative似乎工作正常。

你的测试

在 GHCi 中运行命令时,您基本上处于IOmonad 中,它也是一个Applicative. 所以一般来说,pure x返回一个IO (type of x).

在:

pure (*2) <*> pure 2

您正在“放入”(*2)一个IO对象,然后也放入2一个IO对象,最后<*>按照instance Applicative IO.

您没有测试您的MZipList实例。

在第二个示例中,您只是调用:

pure ((*2) 2)

如果你还记得,(*2) 2简单地适用(*2)2,从而真正执行2 * 2。所以你的电话实际上是:

pure 4

其中,在 GHCi 中(仍然在IOmonad 的上下文中)返回一个IO Int对象。

如何正确测试

要测试“同态”定律,您只需要给编译器一个关于您真正想要的类型的小提示:

所以而不是:

pure (*2) <*> pure 2

你会写:

pure (*2) <*> (pure 2 :: MZipList Int)

Live demo

于 2014-10-22T08:04:33.423 回答