私はおそらく次のものを使用します:
f xs = foldr g (k (last xs)) (init xs)
k x
基本的には、リストの最後が折りたたみ時に置き換えられることを意味します。どこにでもある遅延評価のおかげで、無限リストでも機能します。
他に 2 つの解決策があります - 空のケースを追加することと、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
次に、単一要素の tableaux を として表すことができ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)
。