我很可能会使用以下内容:
f xs = foldr g (k (last xs)) (init xs)
它基本上意味着列表的末尾被k x
折叠时替换。由于无处不在的惰性求值,它甚至适用于无限列表。
还有其他两种解决方案 - 添加空案例和使用 Maybe。
A)添加空案例:
最好f []
有明确的定义。然后,您可以将定义写为
f [] = c
f (x:xs) = g x (f xs)
这是f = foldr g c
。例如,如果您更改
data Tableau = N Expr | S Expr Tableau | B Expr Tableau Tableau
到
data Tableau = N | S Expr Tableau | B Expr Tableau Tableau
那么您可以将单元素表格表示为S expr N
,并将函数定义为单线
f = foldr S N
只要空壳有意义,这是最好的解决方案。
B)使用也许:
另一方面,如果f []
不能合理定义,那就更糟了。偏函数通常被认为是丑陋的。要使其总计,您可以使用Maybe
. 定义
f [] = Nothing
f [x] = Just (k x)
f (x:xs) = Just (g x w)
where Just w = f xs
这是一个完整的功能 - 更好。
但是现在您可以将函数重写为:
f [] = Nothing
f (x:xs) = case f xs of
Nothing -> Just (k x)
Just w -> Just (g x w)
这是一个正确的折叠:
addElement :: Expr -> Maybe Tableaux -> Maybe Tableaux
addElement x Nothing = Just (N x)
addElement x (Just w) = Just (S x w)
f = foldr addElement Nothing
一般来说,折叠是惯用的,应该在适合递归模式时使用。否则使用显式递归或尝试重用现有的组合器。如果有一个新的模式,做一个组合器,但前提是你会经常使用这个模式 - 否则它是矫枉过正的。在这种情况下,模式是 fold 对于由定义的非空列表:data List a = End a | Cons a (List a)
。