新しいアカウントで始めました。

身の回りの出来事や写真が中心です。

ScalaのfoldLeftとfoldRightを使ってみる。

2024-05-05 21:06:04 | Scala

確かに、pythonでのreduce,lambdaより混乱しないですね。lambda x, y : y, xについては

まだよく分かってないかもしれません。

ScalaのfoldLeftとかは、関数の定義時点で初期値を決めてます。

何か分からないのですが、関数の定義をしないで、pythonのように埋め込むことも不可能でないですか?

第一級オブジェクトなら出来そうに思えますが。

 

コップ本の3版P312,P313に左畳み込みと右畳み込みの定義があります。

左畳み込みだと、リストの一番左に初期値が来て、しかもネストの一番深いとこに置かれます。

右畳み込みだと逆で、リストの一番右に初期値が置かれて、ネストが一番深いところになります。

 

pythonでは初期値が有るか無いかとx, yなのか?y,xなのか?で決まるようですが

定義を見てないので、らしいしか、分かりません。

 

フジは地面を枝でない、ツタが這って広がろうとします。厄介です。

 


コメント (4)    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 暫く振りにintellj IDEAのSca... | トップ | 病とともに生きる、訪問リハ... »
最新の画像もっと見る

4 コメント

コメント日が  古い順  |   新しい順
ScalaのfoldLeft ≠ Pythonのreduceなんで気をつけて (cametan_42)
2024-05-06 01:27:21
例えば、提示コードをPythonで直訳しようとすると次のようになるでしょう。

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/
やはり同じではない、ですね。 (isam)
2024-05-06 08:48:51
 違いを感じてはいましたが、ハッキリしませんでした。pythonの微妙さも、なかなか、と思ってましたが、このコメントをもう少し読めば、おぼろげにわかるかも。
 幽霊の正体を見たり、なんとか?になれば良いですね。
結局、自分で書いてみた方が早いんじゃないんですか? (cametan_42)
2024-05-06 17:24:31
> 幽霊の正体を見たり、なんとか?になれば良いですね。

う〜ん、結局ね。
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文使って何回か実装してみれば、「仕組み」は充分理解可能でしょう。なんせ、実際は、上のコード見てみれば分かりますが「大した事を」やってるわけじゃないんです。
意外と難しいが、簡単に書けてる (isam)
2024-05-08 09:22:12
 cametanさん、有難うございます。本質とはこんなことなんですかね。全てはやってみてませんが、なるほど、の連続です。
 ScalaのfoldLeftとpythonのredumeとlambdaの組み合わせは、同じはないんですね。

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

Scala」カテゴリの最新記事