金融工学の計算(1)〜ディスカウントファクター(DF):Haskell編その3

前回Haskellで引数をそれぞれ割り当てて表示するところまで行きましたが、今回は計算までやってみたいと思います。

DFの式は、
 DF = \frac{PV}{FV} = \frac{1}{(1+r)^t}
でしたね。

では、Haskellで利率と期間を引数を取って計算式を作ってみましょう。

df.hs

import System

main :: IO ()
main = do args <- getArgs
          putStrLn $ show $ dfFromRateAndTerm args

dfFromRateAndTerm :: [String] -> Float
dfFromRateAndTerm [a,b] = let r = read a::Float
                              t = read b::Float
                          in 1 / (1 + r) ** t

dfFromRateAndTerm という関数で、引数を取り、let式でそれぞれFloatに直してrとtを束縛し、inの中で実際の計算式「1 / (1 + r) ** t」を実行しています。

実行結果です。

$ runghc df.hs 0.01 1
0.990099

うまくいきました!

でも、このコードは dfFromRateAndTerm という関数で引数の分析とDFの計算という、意味の異なった機能を1つの関数で持っているというのが、若干気に入りません。あと、ここで指摘されたように、コマンドライン引数をきれいに関数に渡して、すっきりと書きたいものです(ポイントフリーというんでしょうか。)

そこで、改良してみたのが次のコードです。
df2.hs

import System

main :: IO ()
main = putStrLn . show . df . rateAndTermFromArgs =<< getArgs

df :: [Float] -> Float
df [r,t] = 1 / (1 + r) ** t

rateAndTermFromArgs :: [String] -> [Float]
rateAndTermFromArgs [] = [0, 1] -- 引数がない場合 (利率が0%だとDFは常に1となる)
rateAndTermFromArgs [a,b] = [read a::Float, read b::Float]

rateAndTermFromArgs 関数では、引数を利率と期間に分解だけを行っています。また、main関数はgetArgsからの値を、関数合成によってそれぞれの関数に渡しています。そうすることで、main関数がよりすっきりしました。

実行結果です。

$ runghc df2.hs 0.01 1
0.990099

改良前と同じですね!

また、引数がない場合、利率を0%にして計算するというパターンを追加しています。

$ runghc df2.hs 0 1
1.0

利率が0%であれば、現在価値と将来価値が一致するので、DFは常に1になります。df関数が問題ないことも確認できました。

やっと、一通りRubyHaskellで、金融工学の計算が1つできました。あまり計算内容と関係のないところでやたらつまずいていましたので、次回以降の計算は、もう少しスムーズにできるようになると思います。