確かに、pythonでのreduce,lambdaより混乱しないですね。lambda x, y : y, xについては
まだよく分かってないかもしれません。
ScalaのfoldLeftとかは、関数の定義時点で初期値を決めてます。
何か分からないのですが、関数の定義をしないで、pythonのように埋め込むことも不可能でないですか?
第一級オブジェクトなら出来そうに思えますが。
コップ本の3版P312,P313に左畳み込みと右畳み込みの定義があります。
左畳み込みだと、リストの一番左に初期値が来て、しかもネストの一番深いとこに置かれます。
右畳み込みだと逆で、リストの一番右に初期値が置かれて、ネストが一番深いところになります。
pythonでは初期値が有るか無いかとx, yなのか?y,xなのか?で決まるようですが
定義を見てないので、らしいしか、分かりません。
フジは地面を枝でない、ツタが這って広がろうとします。厄介です。
from functools import reduce
from operator import sub, truediv
def genzan_fR(xs): return reduce(sub, reversed(xs), 0)
def genzan_fL(xs): return reduce(sub, xs, 0)
def warizan_fR(xs): return reduce(truediv, reversed(xs), 100)
def warizan_fL(xs): return reduce(truediv, xs, 100)
if __name__ == '__main__':
lst2 = [5, 4, 3, 2, 1]
print(f'{genzan_fR(lst2)}\n{genzan_fL(lst2)}')
lst3 = [1, 2, 3, 4, 5]
print(f'{genzan_fR(lst3)}\n{genzan_fL(lst3)}')
lst4 = [10, 5, 2]
print(f'{warizan_fR(lst4)}\n{warizan_fL(lst4)}')
Pythonでは右側から畳み込むreduceはないんで、与えられたリストxsをreversedします。
そこはいいけど、このプログラムを実行すると次のようになるでしょう。
-15
-15
-15
-15
1.0
1.0
全部Scalaで言うトコのfoldRightと同じ結果になります。
これは当然で、リストxsがどんな並びだろうと、減算の累積結果も除算の累積結果も同じ結果にならざると得ない。
じゃあ、ScalaのfoldLeftの計算が間違ってるのか、と言うとさにあらず。実は一般に言うfold(reduce)とfoldLeftでは「関数の適用順序が違う」んです。
細かい事は次のサイトに書いてる通りです。
fold, fold-left, fold-right:
https://blog.practical-scheme.net/shiro/20120314-fold
実は正確な話をすると、fold系の関数はfold、fold-left、fold-rightの3つがあって、fold-rightと対象の計算になってるのはfold-leftで、fold ≠ fold-leftです。
ここを知らないと予期せぬ結果になるでしょう。
【Scala】foldとfoldLeftの違いを知る:
https://dev.classmethod.jp/articles/scala-differece-between-fold-and-foldleft/
幽霊の正体を見たり、なんとか?になれば良いですね。
う〜ん、結局ね。
fold/fold-right/fold-leftを「完全に」理解するにはそれらの実装を一回書いてみた方が早いんですよ。
しかも、実装自体は大してムズくない。っつーか、「単純」な割に強力な機能を有してるんで皆ビックリする、ってわけです。何も強力さは「複雑さ」を要しない、って言う例でしょうね。
また、fold/fold-right/fold-leftは、Lisp等の関数型言語だと「再帰のお題」なんだけど、原理的な話をすると別にforなんかの繰り返し構文で書いても構わない、んです。破壊的変更が無ければ。
よって、Python流に書くと次のようになるでしょう。
def fold(function, value, iterable):
it = iter(iterable)
for element in it:
value = function(value, element)
return value
def foldRight(function, value, iterable):
it = reversed(iterable)
for element in it:
value = function(value, element)
return value
def foldLeft(function, value, iterable):
it = iter(iterable)
for element in it:
value = function(element, value)
return value
これだけ、です。実は3つ共殆ど同じプログラムで、しかも本体はザックリ言うとfor文そのもの、です。他に何も面倒なモノはありません(Pythonの場合は、受け取ったシーケンスをiterでイテラブルに変換してますが、そこは重要じゃない)。
他の、関数が第一級オブジェクトな言語ででもfor文使って何回か実装してみれば、「仕組み」は充分理解可能でしょう。なんせ、実際は、上のコード見てみれば分かりますが「大した事を」やってるわけじゃないんです。
ScalaのfoldLeftとpythonのredumeとlambdaの組み合わせは、同じはないんですね。