タスクによって、foldlbyfoldrを実装する必要がありました。関数のシグネチャとfoldlの実装の両方を比較することで、次の解決策が得られました。
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl _ acc [] = acc
myFoldl fn acc (x:xs) = foldr fn' (fn' x acc) xs
where
fn' = flip fn
関数の引数を反転するだけで、foldrの期待される型を満たし、渡された関数を再帰的に適用することでfoldlの定義を模倣します。私の先生がこの答えをゼロ点で評価したので、それは驚きでした。
この定義が標準のfoldlと同じ方法で中間結果をスタックすることも確認しました。
> myFoldl (\a elm -> concat ["(",a,"+",elm,")"]) "" (map show [1..10])
> "((((((((((+1)+10)+9)+8)+7)+6)+5)+4)+3)+2)"
> foldl (\a elm -> concat ["(",a,"+",elm,")"]) "" (map show [1..10])
> "((((((((((+1)+10)+9)+8)+7)+6)+5)+4)+3)+2)"
正解は次の定義でした。
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
以前の定義が間違っている理由を尋ねるだけですか?