这来源于“Haskell”一书中的“基本原则”中的练习。练习是为Applicative实现ZipList',这类似于前奏曲的ZipList。这本书有这样的暗示
检查预存功能,这些函数可以满足您的需要。一个以字母
z开头,另一个以字母r开头。您正在从这些函数中寻找灵感,而不能直接重用它们,因为您使用的是自定义List类型,而不是Prelude提供的列表类型。
我猜想以z开头的函数是zipWith,但我不知道以r开头的函数。
data List a =
Nil
| Cons a (List a)
deriving (Eq, Show)
zipWith' :: (a -> b -> c) -> List a -> List b -> List c
zipWith' _ Nil _ = Nil
zipWith' _ _ Nil = Nil
zipWith' f (Cons x xs) (Cons y ys) = Cons (f x y) (zipWith' f xs ys)
newtype ZipList' a = ZipList' (List a)
deriving (Eq, Show)
instance Functor ZipList' where
fmap f (ZipList' xs) = ZipList' $ fmap f xs
instance Applicative ZipList' where
pure x = ZipList' $ Cons x Nil
(ZipList' fs) <*> (ZipList' xs) = ZipList' $ zipWith' ($) fs xs这通过了书中的一个测试用例,但我想知道是否有更好的方法来实现它,因为我没有使用以r开头的函数。我有一种感觉,这应该是repeat,因为它也应该在无限列表上工作。
发布于 2019-10-28 20:08:45
我在Robin Zigmond's comment之后想了一会儿
关键是考虑合法的
Applicative实例fmap f x == (pure f) <*> x的要求,并认识到列表x的长度没有上限。
这一实施应符合适用法律。
data List a =
Nil
| Cons a (List a)
deriving (Eq, Show)
zipWith' :: (a -> b -> c) -> List a -> List b -> List c
zipWith' _ Nil _ = Nil
zipWith' _ _ Nil = Nil
zipWith' f (Cons x xs) (Cons y ys) = Cons (f x y) (zipWith' f xs ys)
repeat' :: a -> List a
repeat' x = Cons x $ repeat' x
newtype ZipList' a = ZipList' (List a)
deriving (Eq, Show)
instance Functor ZipList' where
fmap f (ZipList' xs) = ZipList' $ fmap f xs
instance Applicative ZipList' where
pure x = ZipList' $ repeat' x
(ZipList' fs) <*> (ZipList' xs) = ZipList' $ zipWith' ($) fs xs发布于 2019-10-28 16:53:27
阅读原文下面的帖子,我得出了一个结论:文章的作者试图证明实现满足法律(fmap f xs = (pure f) <*> xs):
让我们试着证明它是一个经典标识,去掉包装器。因此,让我们用右手工作:
(pure f) <*> xs = (repeat' f) <*> xs = zipWith' ($) (repeat' f) xs;
就身份而言,证明zipWith' ($) (repeat' f) xs等于fmap f xs就足够了。
它们相同的原因很明显:
length (zipWith op xs ys) == min (length xs) (length ys);(在xs和ys都是无限的情况下,不能计算这个表达式)。
由于repeat' f是无限的,length $ zipWith' ($) (repeat' f) xs实际上就是length xs (实际上,是否存在这样的值并不重要:索引的存在就足够了)。xs的每个元素都被应用到相同的函数f中,这是重复的。如您所见,大小保持不变,每个元素都由一个常量函数(即fmap的定义)进行变形。
https://stackoverflow.com/questions/58593349
复制相似问题