为什么'Data.List.null'使用'foldr'?

met*_*eap 8 haskell

在我的初学者看来,人们可以实现Data.List.null:

null [] = True
null _ = False
Run Code Online (Sandbox Code Playgroud)

查看Hackage中的实际来源,我看到:

null = foldr (\_ _ -> False) True
Run Code Online (Sandbox Code Playgroud)

我发现这很好奇,当然我错过了一些我应该学习的东西,但是什么呢?

dup*_*ode 15

null是一个Foldable类的方法:

GHCi> :t null
null :: Foldable t => t a -> Bool
Run Code Online (Sandbox Code Playgroud)

您引用的实现是默认实现,Foldable即使它们没有定义特定的实现,也适用于所有实例:

class Foldable t where
    -- etc.
    null :: t a -> Bool
    null = foldr (\_ _ -> False) True
    -- etc.
Run Code Online (Sandbox Code Playgroud)

列表实例,但是,覆盖默认的实现:

instance Foldable [] where
    -- etc.
    null    = List.null
    -- etc.
Run Code Online (Sandbox Code Playgroud)

List.null反过来,以您期望的更简单的方式定义GHC.List:

null                    :: [a] -> Bool
null []                 =  True
null (_:_)              =  False
Run Code Online (Sandbox Code Playgroud)

  • @Xeo,它对列表无关紧要,但在其他情况下,写出所有构造函数是值得的.一个包罗万象的案件可能会错误地抓住; 如果有人向现有类型添加新构造函数,则特别有可能.一个函数`go red = notgo; 如果有人将缺少的`Yellow`构造函数编辑成`TrafficLightColor`类型,go _ = gogogo`将完全做错事.如果它在"红色"和"绿色"上匹配,那么`-Wall`或`-fwarn-incomplete-patterns`将提醒您需要添加案例. (6认同)
  • 任何理由`(_:_)`而不只是`_`?强制错误'undefined`或什么? (2认同)
  • @PaulJohnson你的意思是在`foldr`的二进制操作中使用`(&&)`?如果是这样的话,我相信实际的实现不会与`(&&)`短路.例如,如果要使用列表`foldr`,我们将使用`null(x:[])= foldr(\ _ _ - > False)True(x:[])=(\ _ _ - >> False )x(foldr(\ _ _ - > False)True [])`,立即减少为"False". (2认同)