0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VBAHaskellの紹介 その13 (プレースホルダの追加: _1 と _2 )

Last updated at Posted at 2015-05-15

VBAHaskellで2変数関数を合成するときの自由度を高めるために新しいプレースホルダ ph_1 と ph_2 を導入した。これの直接のきっかけは以下の問題 1 を解くことだった。

問題4
正の整数のリストを与えられたとき、数を並び替えて可能な最大数を返す関数を記述せよ。例えば、[50, 2, 1, 9]が与えられた時、95021が答えとなる。

これには下のような比較関数を使ってソートする必要がある。2

'比較関数(aとbは数字だけからなる文字列とする)
Function Question4Comp(ByRef a As Variant, ByRef b As Variant) As Variant
    'a,bの順に結合した文字列を数値化  <  b,aの順に結合した文字列を数値化
    Question4Comp = IIf(Val(a & b) < Val(b & a), 1, 0)
End Function

もちろんこれでいいのだが、こういう単純な比較関数はいちいちモジュールに書くのではなく、関数合成で作り出したい。しかし今までの実装では難しかったので、C++側を改造しVBA側で新しく2種類のプレースホルダを追加した。
これまでの実装では比較関数 f(x, y) の中で何か計算をしようとして関数を合成しても、f(g(x), h(y)) という形にしかならなかった 3。 f(x, y) の x には第1引数のみ、y には第2引数のみを渡していたのである。実引数(a, b)を代入すると f(g(a), h(b)) となるので、a と b は分離され結合文字列を作ることができない。ab を逆順の ba にすることも難しい。
単純に f(g(a, b), h(a, b)) を評価するように変えればいいが、合成されていないただの f(x, y) に適用したときには f(a, b) となるべきで、 f(a, a) とか f(b, b) になってはいけない。もちろんVBAのユーザーコードは修正不要にしたい。
そこで、C++標準ライブラリのstd::placeholdersにある _1 や _2 のような明示的なプレースホルダを導入することにした。これまでプレースホルダは関数の中で置かれている位置によって第1引数を受け取るか第2引数を受け取るかが決まっていたが、これらは場所に依存せずに受け取る引数を決め打ちできる。もちろん _1 は第1引数を受け取り、_2 は第2引数を受け取るプレースホルダだ。
VBAではアンダースコア '_' で始まる変数や関数がエラーになってしまうので、_1、_2 ではなく ph_1 と ph_2 と名付けている 4

具体的にはこうなる。

' f(x, y) = CLng(x & y) < CLng(y & x)    と同じ
comp4 = p_less(p_getCLng(p_plus(ph_1, ph_2)), p_getCLng(p_plus(ph_2, ph_1)))

' dumpFunで中身を見てみる
?dumpFun(comp4)
F8652(F1868(F6828(_1, _2), _), F1868(F6828(_2, _1), _))

これを使って対象の配列に対するソートインデックスを作ればいい。ただし問題が「最大数」を求めるものなので逆順にしてから適用する。

' 上の方のcomp4を使う
s = sortIndex_pred(arr, comp4)     ' ソートインデックスを出力
result = subM(arr, reverse(s))     ' 逆順に並べ替える

このサンプルをテストモジュールに追加した。(Sub sortTest2)

VBAHaskellの紹介 その12(1時間以内に解けなければプログラマ失格がなんたら)
VBAHaskellの紹介 その1(最初はmapF)

  1. 1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に の問題4

  2. これの説明は、ブログ 比較関数の自然な例(2) の方に書いた。

  3. 正確には g と h は2変数関数のうち1変数を束縛したものなので、f(g(x, x), h(y, y)) が正しい。

  4. Haskell_1_Core.basモジュール に追加。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?