Скорее всего, я бы использовал следующее:
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) use Maybe:
С другой стороны, если 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
В целом, сворачивание является идиоматическим и должно использоваться, когда вы подходите к шаблону рекурсии.В противном случае используйте явную рекурсию или попробуйте повторно использовать существующие комбинаторы.Если есть новый шаблон, создайте комбинатор, но только если вы будете часто использовать шаблон - иначе это излишне.В этом случае шаблон складывается для непустых списков, определяемых как: data List a = End a | Cons a (List a)
.