我正在进行Typeclassopedia的练习;在Applicative
部分,我编写了ZipList
pure
函数,并检查它是否符合Applicative
定律。
我已经查过:
但是当我试图检查"同态"法律,我发现GHCi没有得到MZipList
的结果。
我认为这是因为我错过了将pure
指定为Applicative
类型的类。如何在没有pure
<*>
的情况下立即运行Applicative
函数?{/ p>
这里是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)
当我查看&#34; Interchange&#34;法律,例如:
*Main> (MZipList [(*2),(*3),(*4)]) <*> pure (2)
MZipList {getZipList = [4,6,8]}
*Main> pure ($ 2) <*> (MZipList [(*2),(*3),(*4)])
MZipList {getZipList = [4,6,8]}
但是当我检查&#34; Homomorphism&#34;法律,MZipList
&#39; s pure
未被调用:
*Main> pure (*2) <*> pure 2
4
*Main> pure ((*2) 2)
4
*Main>
为什么?
答案 0 :(得分:6)
pure
? pure
只是一个在特定Applicative
monad中“插入”对象的函数。例如:
test :: [Int]
test = pure 1 -- [1]
我们将1
插入到列表monad中,从而产生单[1]
。如果您已阅读Monad
课程,则pure
与return
基本相同(如果您不必担心)。
Applicative
的实例似乎工作正常。
在GHCi中运行命令时,您基本上位于IO
monad中,它也是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中(仍然在IO
monad的上下文中)返回IO Int
个对象。
要测试“同态”定律,您只需要给编译器一个关于您真正想要的类型的小提示:
所以而不是:
pure (*2) <*> pure 2
你会写:
pure (*2) <*> (pure 2 :: MZipList Int)