高階関数の書き方 (invoke_in, invoke_from)

C++側で書く場合は、どちらにしろContextオブジェクトをmethod invocationに渡すので、そのContextをcallerにすればいいだけだが、gsで高階関数を書く場合、これといって、このあたりのidiom的なものが無い。
というか、C++で書いてばかりで、gsで書くことが無かったので、考えてなかった。これももちろん、普通のclosureが無いことが一番の問題なんだが、ともかく、現状で一番マシなやり方を考えてみた。

例題として単なるpredicateを受け取るものを考える。渡すのは、ローカル変数と引数を比較するMethod。

o: { //selfがContextだとlocal variableを参照可能になるのでオブジェクト化。
  one_or_not: `m[
    m(1).? 'one', 'other'
  ]
}

v: 1
o.one_or_not(`n[n.== v]).flush //vに参照できずerror

one_or_notは一件綺麗に書けてる高階関数だが、これではContext関係が機能しない。(昔はContextを常に継承してたから機能したが、それはそれで別の問題が発生するのでやめた。)

o: {
  one_or_not: `m[
    m$.closure(caller).(1).? 'one', 'other' //書き換えここだけ
  ]
}

v: 1
o.one_or_not(`n[n.== v]).flush //one

これならうまく行く。冗長な言語である。one_or_notを呼ぶ側が必要に応じてそう(closure)すればいいという気もするが、each等の仕様を考えると、やはり実装側が責任を持つ部分に思える。
渡すmethodがすぐに呼ばれない場合は、渡す側がclosure等をやることになるが、また別の話。
mがmethodじゃ無い場合にも機能するようにしたい場合は、closureではなくresolveとevalを使い、以下のようになる。

o: {
  one_or_not: `m[
    [;m$.(1).? 'one', 'other'].resolve2.eval(caller) //書き換えここだけ
  ]
}

v: 1
o.one_or_not(`n[n.== v]).flush //one

どうあれ、mをそのまま呼べる仕様なのに、呼ぶとダメ、というのは残念な仕様と言える。
せめて、もっと単純に、m$.invoke_with_caller(1)とでもできればいいように思う。ああ、そういえば、call_with_contextがあったか。
と思ったが、これ、callがcontext継承しないから全く意味無い。callerを設定できるだけだ。
というわけで、Method.invoke_fromという指定ContextからのinvokeができるMethodを考えてみた。

o: {
  one_or_not: `m[
    m$.invoke_from(caller 1).? 'one', 'other' //書き換えここだけ
  ]
}

v: 1
o.one_or_not(`n[n.== v]).flush //one

mがMethodで無い場合もinvokeできるようにするには、invoke_fromとinvokeをObjectに持たせないといけない。これにより、MethodではなくObject.invoke_from, invokeが発生。
Coroutine等のinvokeを持っているオブジェクトでも使えるよう、Object.invoke_fromはself.invokeを指定Contextで呼ぶ。Object.invokeはselfがMethodの場合のみ従来のMethod.invokeと同じになり、ほかはselfを返す。
call_without_clone_contextと対になるMethod.invoke_without_clone_contextもそれに合わせて、Objectへ移動し、名前もinvoke_inとして、引数のContextでの実行とし、デフォルト引数をlocalとする。合わせてcall_...の方もcall_inにした。*1

*1:次verでcall_inもinvoke_inと同じくContext指定可能にする。忘れてた。合わせるならcall_fromも定義する。