【问题标题】:Implement Applicative for custom ZipList为自定义 ZipList 实现 Applicative
【发布时间】:2019-10-28 15:02:20
【问题描述】:

这来自Haskell from First Principles一书中的一个练习。练习是为ZipList' 实现Applicative,类似于Prelude 的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,因为它也应该适用于无限列表。

【问题讨论】:

  • 您的 instance Applicative 似乎正在使用您未在此处定义的 ZipList' 类型?
  • @WillemVanOnsem 忘记粘贴了,我更新了问题
  • 您的pure 不正确,一旦您弄清楚了正确的实现,您就会看到引用了哪个以r 开头的函数。关键是考虑fmap f x == (pure f) &lt;*&gt; x 对合法Applicative 实例的要求,并认识到列表x 的长度没有上限。这应该足以让您弄清楚。
  • @RobinZigmond pure 1 :: ZipList Int 创建了一个无限列表,所以这似乎是我的问题,我正在尝试弄清楚它现在如何满足法律要求。

标签: haskell typeclass applicative algebraic-data-types custom-data-type


【解决方案1】:

阅读原帖下的帖子,我得出一个结论,该帖子的作者试图证明实现符合法律(fmap f xs = (pure f) &lt;*&gt; xs):

让我们尝试证明它是一个经典的身份,摆脱包装。因此,让我们用右手工作:

(pure f) &lt;*&gt; xs = (repeat' f) &lt;*&gt; xs = zipWith' ($) (repeat' f) xs;

就身份而言,证明zipWith' ($) (repeat' f) xs 等于fmap f xs 就足够了。

它们相同的原因很明显:

length (zipWith op xs ys) == min (length xs) (length ys); (如果xsys 都是无限的,则无法评估此表达式。

因为repeat' f 是无限的,所以length $ zipWith' ($) (repeat' f) xs 实际上是length xs(这里,这样的值是否存在实际上并不重要:索引的存在就足够了)。 xs 的每个元素都被应用到相同的函数 f 上,重复此过程。可以看到,大小被保留,每个元素都被一个常量函数变形,这就是fmap的定义。

【讨论】:

  • 你可以通过结构归纳使其形式化,代入zipWithrepeatmap的定义:zW ($) (f:rep f) (x:xs) = (f $ x) : zW ($) (rep f) xs = (f x) : map f xs其中zW ($) (rep f) xs == map f xs由IH持有,zW ($) (rep f) [] = [] = map f []是基本情况。
  • @WillNess 没错,这就是我最初想发布的内容,但是既然我们已经掌握了所有定义,那又有什么意义呢?有时 RT 分析可能是一种更有用的技能,而不是严格的证明。
  • 请问什么是“RT”?
  • @WillNess 运行时分析。 (对不起,应该有一个“i”,而不是“e”,即不是复数)。
【解决方案2】:

Robin Zigmond's comment之后我想了想:

关键是考虑fmap f x == (pure f) &lt;*&gt; x对合法Applicative实例的要求,并认识到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

【讨论】:

  • 是的,就是这样 :-) 您可以通过与official implementation 进行比较来检查自己(它在代码的底部附近)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-30
  • 2022-10-02
  • 2013-09-11
  • 2020-02-15
  • 1970-01-01
  • 2016-07-20
相关资源
最近更新 更多