やり方
if_ = @(bool,t,f)feval(@(list,index)list{index},{f,t},uint8(logical(bool)+1));
とする。
するとそれ以降、
if_(true, "はい", "いいえ")は"はい"、
if_(false, "はい", "いいえ")は"いいえ"になる。
Q1. え?w関数で十分なんじゃないの?わざわざ変数で作るなしwww
A. MATLABの仕様で、ライブ スクリプトとかでは関数を定義できません。
(作った瞬間ライブ関数に変化し、ライブ スクリプトの外部からも呼べるようになってしまいます。pythonでいうJupyter Notebookのようにはいかないのです。)
ライブ スクリプトでしか使わない簡単な処理で、わざわざ関数を別ファイルで作りたくない時などに重宝するかと。
Q2. コード解説
A. 外側から順に解説します。
Q2-1. @(A, B, ...)Xってなによ
A. まず@(A,B,...)Xというのは「即時関数」といって、pythonでいうラムダ式みたいなものです。
たとえば、f = @(x)a*x+b;とすると、function y=f(x); y=a*x+b; end したのと同じになります。
つまり、今回のコードは次に等価です。
function rtn=if_(bool,t,f)
function anony_rtn=anonymous(list, index) % matlabでは関数内関数が可能
anony_rtn = list{index};
end
rtn = feval(anonymous(list, index),{f,t},uint8(logical(bool)+1));
end
Q2-2. いつの間にか謎がfevalだけになってる
A. feval(f,A,B,...)はf(A,B,...)を返却します。
つまり、次と等価なわけです。
function rtn=if_(bool,t,f)
function anony_rtn=anonymous(list, index)
anony_rtn = list{index};
end
rtn = anonumous({f,t}, uint8(logical(bool)+1)));
% uint8(logical(bool)+1))はboolが偽なら1に、真なら2になる
% →cell配列{f,t}のインデックスにすれば、偽のときf、真のときtが取り出せる
end
Q2-3. feval要らない子じゃね?
A. fevalは一見無駄な存在に見えますが、即時関数@()とめちゃくちゃ仲良しです。
2人の友情は、関数を作れなかったはずのライブ スクリプトに革命をもたらします。
例えばfeval(@(x)hoge, 1)は何と等価でしょうか?
(@(x)hoge)(1)と等価に思えますが、MATLABでは実はこういう書き方が出来ません。
anonymous = @(x)hoge; anonymous(1);と2文も書かなくてはならず、しんどいです。
そのしんどさを軽減し、1文で済ませてくれるのがfevalってわけです。
しかも1文で済んでるってことは、こいつを丸ごと即席関数の戻り値にすることもできるってことです。
だから事実上、
@(x)feval(@(x)feval(@(x)feval(@(x)feval... , var),fuga), hoge)
みたいに「即席関数←→feval」を間接再帰的に繰り返すことで、
複数の処理を即席関数1つですませることも可能なのです。可読性は著しく下がりますが。
可読性さえ諦めれば、ライブスクリプトで関数作りたい/使いたい放題です!
というわけで「fevalは要らない子」なんていったら即時関数に怒られます(笑)。
謝辞
昨日、メモ代わりにこの記事を投稿しました。そりゃもう「やり方」の章だけで。
今日の朝見てみたら通知が来ていたので「スパムとみなされて消されでもしたのかな」と思ったら、LGTMが3つも来てて大喜び。
慌てて記事の内容をまだマシにした次第です。
LGTMしてくれたみなさん、ありがとうございます。