关于可折叠的 Maybe 实例的问题

3

来源:Hutton, Graham. "Programming in Haskell" (p. 267)

  1. 展示如何通过给出fold、foldMap、foldr、foldl和traverse的显式定义来使Maybe类型可折叠和可遍历。

我已经定义了foldr。为了检查我的解决方案,我在网上找到了这段代码:

 -- foldr :: (a -> b -> b) -> b -> Maybe a -> b
    foldr _ _ Nothing = mempty
    foldr f v (Just a) = f a v

看起来在基础情况下应返回累加器(而不是 mempty)。没错吧?

3
mempty 看起来像是从 foldMap 定义中搭便车而来的,因为 foldMap :: Monoid m => (a -> m) -> Maybe a -> m - chepner
1
最简单的定义方式是考虑 [] 实例,并将 Nothing 视为 [],将 Just a 视为 [a] - chepner
谢谢您的建议,@chepner。您说:「用[a]识别Just a[]实例没有[a]情况。我希望您能澄清,因为我肯定错过了您的重点。」 - F. Zer
它知道如何处理任意非空列表;[a]是一个非空列表。 - chepner
1
fmap f (x:xs) == f x : fmap f xs,所以在单元素列表的情况下,fmap f [x] == f x : fmap f [] == f x : [] == [f x] - chepner
谢谢你,@chepner! - F. Zer
1个回答

6

是的,你所看到的代码是虚假的,甚至无法编译。它应该像你说的那样操作:

foldr _ v Nothing = v

请注意,除了练习之外,您不需要进行所有这些手动工作。您可以只编写:


{-# language DeriveTraversable #-}
module MyModule where
import Prelude hiding (Maybe (..))
data Maybe a = Nothing | Just a
  deriving (Show, Eq, Ord, Functor, Foldable, Traversable)

并完成它。如果您不想依赖语言扩展,那么您仍然只需要编写一个方法:traverse。您可以编写。

import Prelude hiding (Maybe (..))
import Data.Traversable

data Maybe a = Nothing | Just a deriving (Show, Eq)

instance Foldable Maybe where
  foldMap = foldMapDefault
instance Functor Maybe where
  fmap = fmapDefault
instance Traversable Maybe where
  traverse _ Nothing = _1 -- fill in the blanks
  traverse f (Just a) = _2

Maybe的情况下,这应该会生成所有类方法的最优定义。 对于某些类型,您需要手动编写一些方法以获得最佳结果。 例如,默认通常不会为递归类型的<$提供良好的定义。

1
是的,我觉得依赖派生机制肯定是作弊。但只定义“traverse”可能是唯一可行的方法,除非是为了练习。 - luqui
@luqui,是的,虽然我说过有些类型确实希望某些方法得到优化,但大多数情况下 <$null 和/或 length 最需要被优化。 - dfeuer
谢谢。我做完了作业。这个代码正确吗? traverse _ Nothing = pure Nothing traverse f (Just a) = Just <$> (f a)``` - F. Zer
1
@F.Zer,没错,就是那个! - dfeuer
1
@F.Zer:由于此处的评论框不显示换行符和缩进,因此明确使用 { ; } 是有帮助的,以便代码是有效的 Haskell 代码:instance Traversable Maybe where { traverse _ Nothing = pure Nothing; traverse f (Just a) = Just <$> f a }。然后人们可以简单地复制并粘贴来测试您的工作,一般来说,这样更容易阅读。 - Jon Purdy
谢谢,@Jon Purdy! - F. Zer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接