模式匹配与守卫混合使用

10

我想定义这个函数:

accumulate_list' :: Num a => [a] -> ( a -> a -> a ) -> a
accumulate_list' l f 
    | [] f = 0
    | (x:xs) f = f x (accumulate_list xs f)

但是它无法编译,抱怨x、xs、x、xs不在作用域内。

为了达到相同的结果,我定义了这个函数

accumulate_list :: Num a => [a] -> ( a -> a -> a ) -> a
accumulate_list [] f = 0
accumulate_list (x:xs) f = f x $ accumulate_list xs f

它编译得很好,如果传递的函数是(+),则像列表上的sum函数一样工作。是的,我终于发现,我想要实现的内容已经作为Prelude中的sum函数存在。

然而,我不明白为什么带有混合守卫和模式匹配的第一个版本无法编译。问题出在哪里?

2个回答

26

这是因为守卫基本上是一个布尔表达式,必须评估为TrueFalse。像这样的内容应该可以通过类型检查:

accumulate_list' :: (Eq a, Num a) => [a] -> ( a -> a -> a ) -> a
accumulate_list' l f 
    | l == [] = 0
    | otherwise = undefined -- fill out undefined

值得一提的是,自从Haskell 2010引入了模式守卫,你可以像这样混合使用模式和守卫:

accumulate_list' :: (Eq a, Num a) => [a] -> ( a -> a -> a ) -> a
accumulate_list' l f
    | []     <- l = 0          --pattern for the empty list case
    | 10 < 5      = 10         --arbitrary regular guard just because 
    | (x:xs) <- l = undefined  --pattern for the non-empty case

4

借鉴了@Sibi的答案后,我完成了整个工作代码示例:

accumulate_list' :: (Eq a ,Num a) => [a] -> ( a -> a -> a ) -> a
accumulate_list' l f 
    | l == [] = 0
    | otherwise = f x $ accumulate_list xs f
                    where (x:xs) = l 

1
你可以编写 accumul l f = case l of [] -> 0; (x:xs) | 5 < 10 -> ...; ... 这段代码,它实际上将模式匹配与守卫混合在一起。 - Will Ness

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