前回記事 VBAHaskellの紹介 その15(引数の部分文字列のリストを取り出す) で、問題を解くためのアドホックな関数を定義して使ったことを不満点としてあげた。

VBAHaskellで実装している関数合成はスコープがフラットで、すべてのプレースホルダに実引数を渡して一斉に評価することしかできないのが問題で、このままでは本物のラムダ式からはほど遠い。

一応これを解決する関数lambdaExprを作ったのでその内容を書く。
Haskell_1_Core モジュールに追加)

問題にしたのは以下のコードだ。

'consMap 関数の定義は cons 関数を map しているだけ
Function consMap(ByRef a As Variant, ByRef v As Variant) As Variant
    consMap = mapF(p_cons(a), v)
End Function
'consMap関数を組み込む
f = p_cons(p_makeSole, p_consMap(ph_1, ph_2))  '[a] : map (a:) b
m = foldr(p_catV, Array(), scanr(f, Array(), a))

ここで p_mapF(p_cons(ph_1), ph_2) というような形に書ければ、consMap関数は不要になる。しかし「すべてのプレースホルダに実引数を渡して一斉に評価することしかできない」と書いたとおり、これに引数 a, v を渡すと mapF(cons(a, a), v) もしくは mapF(cons(a, v), v) などと代入され、先にcons関数が評価されてしまう。本来は mapF(p_cons(a, _), v) というように、引数を代入した後もプレースホルダを残したファンクタのままでいてほしいのだ。
これは要するに引数の代入に対する関数呼び出しを遅延させればいいので、Haskell_1_CoreモジュールlambdaExprという関数を追加してそれができるようにした。

lambdaExprを使うコードはこうなる。*1

'                         p_consを第1引数によって遅延 bind1st する
f = p_cons(p_makeSole, p_mapF(lambdaExpr(p_cons, 1, ph_1), ph_2))
m = foldr(p_catV, Array(), scanr(f, Array(), a))

lambdaExprの実質は単なる遅延 bind1st(またはbind2nd) である。
上の p_mapF(lambdaExpr(p_cons, 1, ph_1), ph_2) に引数 a, v を与えると、
mapF(bind1st(p_cons, a), v)
と評価され、最終的に
mapF(p_cons(a, _), v)
という、プレースホルダを残したままの形になっている。
これをラムダ式と呼ぶのは苦しいが lambdaExpr と名付けた。

VBAHaskellの紹介 その15(引数の部分文字列のリストを取り出す)
VBAHaskellの紹介 その1(最初はmapF)

*1:テストモジュール にテスト関数segmentsTest2として追加した。