3

Haskell では、演算子の初期値foldlは明らかに必須です

Prelude> foldl (+) 0 [1]
1
Prelude> foldl (+) 0 []
0
Prelude> :t foldl
(a -> b -> a) -> a -> [b] -> a

しかし、reduce 関数 (またはfunctools.reduce) では、初期値はオプションです。

reduce(function, sequence[, initial]) -> value

初期値が必要になるのは、シーケンスが空の場合のみです。これは、haskell の動作と一致しています。Pythonreduceでは、シーケンスのサイズが 1 であると想定しています。次に、これらのコーナーケースを内部で処理しますか?

>> reduce(operator.sub, [1])
1
>> reduce(operator.mul, [1])
1
>> reduce(operator.add, [1])
1
4

2 に答える 2

6

Haskell には 2 つのバージョンの折り畳みがあることを思い出してください。1 つは何らかの結果型のシードを受け取るもので、もう 1 つはシードがシーケンスの最初の要素であると想定するものです。

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
        where
            go []     = z
            go (y:ys) = y `k` go ys

foldr1 :: (a -> a -> a) -> [a] -> a
foldr1 _ [x]            =  x
foldr1 f (x:xs)         =  f x (foldr1 f xs)
foldr1 _ []             =  errorEmptyList "foldr1"

foldrシーケンスの最初の要素を最初の状態として使用します。

もう 1 つの重要な違いがあります。シーケンスの最初の要素を入力状態として使用することによりfoldr1、入力リストと同じ型の配列を返すように制限されます。foldrただし、いくつかの異なる型を返すことができます。

于 2012-06-04T14:35:26.967 に答える
5

マニュアルから:

初期化子が指定されておらず、イテラブルにアイテムが 1 つしか含まれていない場合、最初のアイテムが返されます


これについてもコメントしたい:

初期値が必要になるのは、シーケンスが空の場合だけです

これは完全に真実ではありません。折り畳み操作では、通常、作業する前の結果があると常に想定します。折り畳み操作が要素をリストに追加している場合、最初の要素は空のリストになる可能性があるため、それに要素を追加できます。より一般的には、関数の戻り値の型がリスト内の要素の型と異なる場合、常に初期値が必要になります。

于 2012-06-04T14:30:22.317 に答える