if_else

以前qiitaに書いたVBAHaskellにおけるFizzBuzz実装の紹介記事で if_else 関数を使った。 qiita.com

ここで if_else 関数自体の説明を書く。
if_else およびこれを関数化した p_if_else Haskell_2_stdFunモジュールにある。

形式

Function if_else(ByRef val As Variant, ByRef trans As Variant) As Variant

  第1引数(val)は対象値
  第2引数(trans)は以下の要素からなる長さ3の1次元配列
   trans(0) : 判定の値/関数
   trans(1) : 真の時の変換値/関数
   trans(2) : 偽の時の変換値/関数

概要
trans(0)が関数 p_fn の場合*1、p_fn(val) の値、
trans(0)が関数でない場合、一致条件 val = trans(0) の判定結果、
のいずれかで真偽判定し、真の場合はtrans(1)、偽の場合はtrans(2)の処理にいく。
trans(1)やtrans(2)が関数の場合はそれにvalを適用したもの、そうでない場合はその値を戻り値とする。
ただしこの値がplaceholderだった場合は、val を戻り値とする。


与えられた整数が3の倍数の時は"Fizz"を、そうでないときはその整数を返す関数。
if_else(x, Array(p_mod(, 3), placeholder, "Fizz"))
x に整数を代入するとこうなる。
 x = 1 のとき ---> Mod(1, 3) = 1 ---> ---> placeholder ---> 1
 x = 2 のとき ---> Mod(2, 3) = 2 ---> ---> placeholder ---> 2
 x = 3 のとき ---> Mod(3, 3) = 0 ---> ---> "Fizz"
・・・
そこでMod 3,Mod 5,Mod 15に対してこれを関数化したものを作って組み合わせる。

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"))

このようにして構成した fun15 に対して、mapF(fun15, iota(1, 100)) とすれば1から100までのFizzBuzz列が作られる。

qiita.com

github.com

*1:make_funPointerを使ってファンクタ化されたもの