「EXCEL」Lambda関数

謎が多いLambda関数。

外部からの参照時にパラメータを貰い、Lambda関数の処理に引き渡せる点が光っている。

=LAMBDA(a,b,SQRT(a*b))

と書くと

#CALC!

になってしまう。

これはパラメータを指定していないためで、パラメータを追加すると

=LAMBDA(a,b,SQRT(a*b))(10,10) ⇒ 10

となるけど、こうなってしまっては使い道が全くない。

そこで、セル名の参照範囲が=で始まるのを利用し、(10,10)抜きでLAMBDA式を適当なセル名で登録すれば・・・

セル名:あああ
参照範囲:=LAMBDA(a,b,SQRT(a*b))

どこかのセルの式:あああ(10,10)⇒10

と云う感じでVBAマクロを使わなくてもユーザ関数(今風にはカスタム関数と云うらしい)を作ることができる。

但し、処理が1行に収まる様に纏められるならないが

そこはLET関数を使って、1行に纏められるなら

ワークシートに散乱している=LET(・・・な計算式を一纏めにできるので

後々の修正もセル名の計算式を治すだけでうまくいく(かもしれない

好感度やランキングの様なその時々で評価式を一斉に変えないといけない案件には非常に有効な気がする。

尚、このLAMBDA関数はループができるらしい。

式:=REDUCE(0,A1:C2, LAMBDA(a,b,a+b^2))

ちょっと見、訳が判らないけど、A1からC2の2乗値を合算する式となっている

LAMBDAの第1パラメータは多分、初期値か前回のLAMBDA関数の計算結果

LAMBDAの第2パラメータは計算して欲しいセルの値

つまり、LAMBDA関数はA1:C2の6セル分のループ中に6回も計算させられる。

1回目:LAMBDA(0,1,0+1^2)
2回目:LAMBDA(1,2,1+2^2)
3回目:LAMBDA(5,3,5+3^2)
4回目:LAMBDA(14,4,14+4^2)
5回目:LAMBDA(30,5,30+5^2)
6回目:LAMBDA(55,6,55+6^2)
最後:91

な感じになるので、LAMBDAのパラメータが2つあるようだ。

セル単位で処理が済むならMAP関数でループする方が簡単かも、

下図は範囲の値を2倍した範囲を作るだけ

式:=MAP(A1:C2,LAMBDA(a, a*2))

計算式はMAP関数のパラメータに範囲があるので自動的にスピルされるのでD3のみに書けばよい。

さらにMAP関数には範囲を複数指定できるらしいので、A範囲+B範囲な計算結果もつくれるっぽい。

式:=MAP(A1:C2,A4:C5,LAMBDA(x, y, x + y ))

再びLAMBDAのパラメータが2つになったけど、扱う範囲が2つなんだから仕方が無い。

同様に、BYROWやBYCOL関数もあるが、動きは(多分)予想できると思う。

SEQUENCE関数が引き渡した数だけ連番(つまり配列)を出力してくれる。

これを使うとLEN関数を組み合わせ、文字列の長さ分の連番を作ることができるから・・・

それをMAP関数に食わせると、1文字づつ何かの処理をやってくれる。

式:=LET(セル, A1, MAP(SEQUENCE(LEN(セル)), LAMBDA(x, MID(セル, x, 1))))

しかし、具体的な使い道となると、1文字コマンドなプロトコルの場合かな?

ロボットのコマンドとかで、

“1422”: “1”:右折、”4″:後退、”2″:左折

⇒ 右折、後退、後退、左折 とかかな?

更に、自己再帰処理が可能らしい。

式:下参照
=LET(対象セル,A1,
  Z,  LAMBDA(f, LET(g, LAMBDA(x, f(LAMBDA(v, LET(w, x(x), w(v) )))), g(g))),
  myfact, Z(LAMBDA(myfact, LAMBDA(x, IF(x=0, 1, x * myfact(x-1))))),
  myfact(対象セル)
)

元ネタ

元ネタの元ネタ。※リンク切れの可能性あり

再帰して欲しいと思って直行ルートで書くと

=LET(対象セル,$A$1,
  myfact,  LAMBDA(x, IF(x=0, 1, x * myfact(x-1))),
  myfact(対象セル)
)
⇒ #NAME?

そう、LET関数でのmyfact変数宣言中は「myfactの宣言が確定していない」ので、

myfact(x – 1)のmyfactなんて知らないがな?エラーが発生する。

注意1:LET文は直書きな再帰処理は不可能。

なので、事前作業として何か変数宣言して、ここを経由して名前の確定を遅延させてしまえばよい。

しかしmyfactを直接引き渡せないことに変わりは無いので、

LAMBDA関数を使って仮引数仮引数を含む処理の形で一旦処理中で参照するmyfactの実体の確定を保留しつつmyfactの宣言を先に完了させる。

=LET(対象セル,$A$1,
  Z, ・・・(検討中)・・・
  myfact, Z(LAMBDA(myfact, LAMBDA(x, IF(x=0, 1, x * myfact(x-1))))),
  IF( 対象セル=0, 0, myfact(対象セル))
) ⇒ #CALC!

LAMBDA(LAMBDA())な感じになって見苦しいなぁ・・・(泣き

さて・・・

Zは不動点コンビネータで書けばいいらしいけど、

Z = lambda f: (lambda x: f(lambda *y: x(x)(*y)))(lambda x: f(lambda *y: x(x)(*y)))

他の言語の例は無名再帰にあるらしいがEXCELは載ってない。

不動点コンビネータの1例にYコンビネータというのがあるらしく、

これをEXCELの計算式にすると

LAMBDA(f, LET(g, LAMBDA(x, f(x(x)), g(g))))

しかし式を確定しようとすると

LAMBDA関数の宣言中なのに『f(x(x))』の『x(x)』部分を直ぐに計算しようとしてバグった

つまり、今のLAMBDA関数の処理部で関数の引数の式に関数が含まれていると

即評価してしまうのではないか?(ちょっと有り得ないけどね!

そんな気がした。

『x(x)』なら、直ぐに計算しようとは思わない。(ハズ

EXCELの為に少し難易度を下げてみる。

f(x(x))をfとx(x)に分離し

x(x)の処理を一旦wとして定義してから、

x(x)を計算する様にしてみると

LAMBDA(v, LET(w, x(x), w(v) ))

となる。

この仮引数vには外側のLAMBDA関数『LAMBDA(x, f(x(x))』の仮引数xが引き渡されるハズなので、『f(x(x))』と等価になるハズだ。

これで調整しなおして

LAMBDA(f, LET(g, LAMBDA(x, f(LAMBDA(v, LET(w, x(x), w(v) )))), g(g)))

になった。

・・・

元ネタ記事では「今風」に詳しく説明されているので、間違いなくそちらの方が理解しやすいだろう。

僕はよーく読んだ末にやっぱりイミフになってしまった。※頭悪いなぁボクは!

EXCELの式の処理の都合をイメージしながら

僕なりに考察してみるしかなかった。※頭悪いなぁボクは!

だから、やはりあのゴニョゴニョなZの式

「EXCEL風Yコンビーネータ」

の様に思えた。




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA