2016-02-19
ユーティリティモジュールに追加した p_try という関数(一種の構文糖)によってFizzBuzzがかなり短く書けるようになった。
fn=p_try(p_mod(, 15), p_try(p_mod(, 5), p_try(p_mod(, 3), , "Fizz"), "Buzz"), "FizzBuzz")
printM mapF(fn, iota(1, 300))
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
2015-07-10
前のよりずっとわかりやすいFizzBuzzができたので書く。
というより下の記事を書いたときは寝ぼけていたとしか思えない。
' 分かりやすいFizzBuzz
fun3 = p_if_else(, Array(p_mod(, 3), placeholder, "Fizz"))
fun5 = p_if_else(, Array(p_mod(, 5), fun3, "Buzz"))
fun15 = p_if_else(, Array(p_mod(, 15), fun5, "FizzBuzz"))
printM mapF(fun15, iota(1, 100))
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
前より短くなったわけではないが、product_setとかreplaceNullといった関数を使う必要は全然なかったのだ。シンプルなif_elseのネストに対してmapFするだけになった。
(この記事ははてなブログ http://mmyymmdd.hatenablog.com/ の再掲です)
2015-04-11
基本的なパーツの紹介の前にFizzBuzzを紹介する。
' 書きたくないコード
If x Mod 15 = 0 Then Debug.print "FizzBuzz"
ElseIf x Mod 5 = 0 Then Debug.print "Buzz"
ElseIf x Mod 3 = 0 Then Debug.print "Fizz"
Else Debug.print x '(改行は省略)
1から100までの整数にこのロジックを当てはめるだけだが、もちろんこんなコードを書かずに基本的なパーツの組み合わせでシンプルに表現したい。
これはなかなか短くできなかった。現状のコードは以下の通り。
m = Array(Array(p_mod(, 15), Null, "FizzBuzz"), _
Array(p_mod(, 5), Null, "Buzz"), _
Array(p_mod(, 3), placeholder, "Fizz"))
printM foldl1(p_replaceNull, product_set(p_if_else, iota(1, 100), m), 2)
使っているパーツは、剰余関数 p_mod、条件分岐関数 p_if_else、mapの直積版 product_set、上書き関数 p_replaceNull、そして foldl1 1 である。
product_set
は与えられた2つのリストの直積に対して関数を適用するので、イメージとしては表のようになる。対象となる関数は if_elseで、1つ目のリストの要素は1~100の整数、2つ目のリストの要素は [条件、真の場合の値、偽の場合の値] だ。
if_else
n | m(0) | m(1) | m(2) | replaceNull |
---|---|---|---|---|
1 | Null | Null | 1 | 1 |
2 | Null | Null | 2 | 2 |
3 | Null | Null | Fizz | Fizz |
4 | Null | Null | 4 | 4 |
5 | Null | Buzz | 5 | Buzz |
6 | Null | Null | Fizz | Fizz |
... | ... | ... | ... | ... |
15 | FizzBuzz | Buzz | Fizz | FizzBuzz |
16 | Null | Null | 16 | 16 |
... | ... | ... | ... | ... |
98 | Null | Null | 98 | 98 |
99 | Null | Null | Fizz | Fizz |
100 | Null | Buzz | 100 | 100 |
15と5については、割り切れない場合にNull値、割り切れる場合にそれぞれFizzBuzzとBuzzを設定し、3についてだけは割り切れないとき元の整数引数を設定している。それぞれの p_mod
で第2引数を束縛していることに注意。
これを左から見ていって、「Nullは新しい値に置き換えるがNullでなかったらそのまま」という関数を繰り返し適用すればよい。その関数はreplaceNullで、この配列に対して foldl1 すれば結果が得られる。foldl1 の最後の引数である 2 は、2次元配列に対する畳み込みを横方向に行えという指定である。
このコードはリンクしたgithubテストモジュール(test_module.bas)の中のデモ関数 vbaUnitに書かれている。
ソースコード:https://github.com/mYmd/VBA
VBAHaskellの紹介 その4 (Find)
VBAHaskellの紹介 その2 (合成関数)
VBAHaskellの紹介 その1 (最初はmapF)
-
Haskellの foldl1 と同様だがVBAには2次元以上の配列があるので、それに合わせた仕様になっている ↩