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の紹介 その3 (FizzBuzz)

Last updated at Posted at 2015-04-29

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)

  1. Haskellの foldl1 と同様だがVBAには2次元以上の配列があるので、それに合わせた仕様になっている

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?