これは非常に簡単に翻訳できます。
module PNormalDist where
pnormaldist :: (Ord a, Floating a) => a -> Either String a
pnormaldist qn
| qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
| qn == 0.5 = Right 0.0
| otherwise = Right $
let w3 = negate . log $ 4 * qn * (1 - qn)
b = [ 1.570796288, 0.03706987906, -0.8364353589e-3,
-0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5,
-0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8,
0.3657763036e-10, 0.6936233982e-12]
w1 = sum . zipWith (*) b $ iterate (*w3) 1
in (signum $ qn - 0.5) * sqrt (w1 * w3)
まず、ルビを見てみましょう - 値を返しますが、時々エラーメッセージを表示します (不適切な引数が与えられた場合)。これはあまりハッシュ的ではないので、戻り値を次のようEither String a
にしましょう - ここでLeft String
、不適切な引数が指定された場合はエラー メッセージとともに を返し、Right a
それ以外の場合は を返します。
ここで、上部の 2 つのケースを確認します。
qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
- が範囲外の場合、これはエラー状態qn
です。
qn == 0.5 = Right 0.0
- これはルビーチェックですqn == 0.5 and return * 0.0
w1
次に、ruby コードで定義します。しかし、数行後に再定義していますが、これはあまりルビっぽくありません。最初に保存しw1
た値は の定義ですぐに使用されるw3
ので、 への保存をスキップしないのはなぜw1
ですか? w3 の定義でqn > 0.5 and w1 = 1.0 - w1
積を使用するため、この手順を実行する必要さえありません。w1 * (1.0 - w1)
そのため、すべてをスキップして、定義に直接移動しますw3 = negate . log $ 4 * qn * (1 - qn)
。
次は の定義ですb
。これは、Ruby コードから直接リフトしたものです (配列リテラルに対する Ruby の構文は、リストに対する Haskell の構文です)。
これが最もトリッキーなビットです - の最終的な値を定義しますw3
。ruby コードの機能
w1 = b[0]
1.upto 10 do |i|
w1 += b[i] * w3**i;
end
フォールドと呼ばれるもの - (ruby 配列に格納された) 値のセットを 1 つの値に減らします。以下を使用して、これをより機能的に (ただし、Ruby で) 言い換えることができますArray#reduce
。
w1 = b.zip(0..10).reduce(0) do |accum, (bval,i)|
accum + bval * w3^i
end
b[0]
identity を使用して、ループにプッシュした方法に注意してくださいb[0] == b[0] * w3^0
。
これを haskell に直接移植できるようになりましたが、少し見苦しいです。
w1 = foldl 0 (\accum (bval,i) -> accum + bval * w3**i) $ zip b [0..10]
代わりに、私はそれをいくつかのステップに分割しました - 最初に、 は実際には必要ありません。( から始まる)i
の累乗が必要なだけなので、 でそれらを計算しましょう。w3
w3^0 == 1
iterate (*w3) 1
次に、それらを b の要素とのペアに圧縮するのではなく、最終的に必要なのはそれらの積だけなので、 を使用して各ペアの積に圧縮できますzipWith (*) b
。
これで、折り畳み機能は非常に簡単になりました。積を合計するだけで済みますsum
。
最後に、が 0.5 より大きいか小さいsqrt (w1 * w3)
かに応じて、plus を返すかマイナスを返すかを決定します (等しくないことは既にわかっています)。qn
そこで、Ruby コードのように 2 つの別々の場所で平方根を計算するのではなく、一度計算してから(の符号を返すだけである+1
) の符号を掛けます。-1
qn - 0.5
signum