3

Haskellを使って金融の組み合わせ問題を解決したいのですが、リストモナドはこれにぴったりのようです。

さて、リストモナドに関する私の問題は、関係する値に名前を付けることができないことです。私は例証しようとします:

loan = [1000*x | x <- [1..3]]
interest_rate = [0.005*x | x <- [4..10]]

calc = do                                                                                    
  l <- loan                                                                                  
  i <- interest_rate                                                                         
  return (l*i)

上記のcalcを実行すると、数値のリスト([20.0,25.0,30.0,35.0,40.0, ... ])が表示されますが、各計算でローンと金利がどのように使用されているかわかりません。

私はここで迷子になります、私の直感は私に自分自身のモナディックタイプを作成するように言います、と言ってHelpfulNumber :: (String,[Double])、どういうわけかそれを言います:

>>=そしてreturnあるべきであり>>= . sndそしてreturn . snd

私はここで正しい方向に進んでいますか、それとももっと良い方法がありますか?正直なところ、少し迷っています。

4

3 に答える 3

6

レコードタイプを使用して、出力をより明確にすることができます。

data Loan = Loan {final :: Double, 
                  rate  :: Double, 
                  loan  :: Integer, 
                  years :: Int}
   deriving Show

printloans :: [Loan] -> IO()
printloans = mapM_ print

printloans loansまたはprintloans loans'ghciプロンプトで使用します。

編集:の定義を含めるのを忘れましたdp。これは、指定された小数点以下の桁数に丸めるためのものです。

dp :: Int -> Double -> Double
n `dp` a = (/ 10.0^n).fromInteger.round.(* 10.0^n) $ a

リストを直接使用する方法は次のとおりです。

loans = [Loan {final = (2 `dp`) $ fromInteger amt*(1+ir)^yrs, 
               rate  = ir,
               loan  = amt,
               years = yrs}  
        | ir <- [0.005*x | x <- [4..10]],
          amt <- [1000*x | x <- [1..3]],
          yrs <- [1..4]
        ]

ただし、モナディックスタイルが好きな場合は、次を使用できます。

loans' = do
  ir <- [0.005*x | x <- [4..10]]
  amt <- [1000*x | x <- [1..3]]
  yrs <- [1..4]
  return Loan {final = (2 `dp`) $ fromInteger amt*(1+ir)^yrs, 
               rate  = ir,
               loan  = amt,
               years = yrs}

これはコンマが少ないという利点があり、<-行の順序を変更して回答の順序を変更する方が簡単です。レコードにエクストラを追加してLoan、それらを使用して計算できます。次のような出力が得られます。

*Main> printloans loans'
Loan {final = 1020.0, rate = 2.0e-2, loan = 1000, years = 1}
Loan {final = 1040.4, rate = 2.0e-2, loan = 1000, years = 2}
Loan {final = 1061.21, rate = 2.0e-2, loan = 1000, years = 3}
Loan {final = 1082.43, rate = 2.0e-2, loan = 1000, years = 4}
Loan {final = 2040.0, rate = 2.0e-2, loan = 2000, years = 1}
Loan {final = 2080.8, rate = 2.0e-2, loan = 2000, years = 2}
...
...

編集:

あなたは他の場所であなたがのような出力が欲しいと私に言いましたir_5% yrs_3 amt_4000 tot_4360.5。それは醜いですが、これがそのようなことをする方法です:

loans'' = do
  ir <- [0.005*x | x <- [4..10]]
  amt <- [1000*x | x <- [1..3]]
  yrs <- [1..4]
  let final = (2 `dp`) $ fromInteger amt*(1+ir)^yrs
  return $ "final_" ++ show final
        ++ ",  ir_" ++ show ((2 `dp`) $ ir*100.0)    -- rounded away a rounding error in 3.5% 
        ++ "%,  amt_" ++ show amt 
        ++ ",  yrs_" ++ show yrs

あなたがするときあなたはmapM_ putStrLn loans''次のような出力を得る

final_1020.0,  ir_2.0%,  amt_1000,  yrs_1
final_1040.4,  ir_2.0%,  amt_1000,  yrs_2
final_1061.21,  ir_2.0%,  amt_1000,  yrs_3
final_1082.43,  ir_2.0%,  amt_1000,  yrs_4
final_2040.0,  ir_2.0%,  amt_2000,  yrs_1
....

しかし、レコードタイプの方がはるかに優れていると思います。出力が読みやすく、文字列をいじることが少なくなります。

于 2012-08-25T15:24:57.860 に答える
2

2つのヘルパー関数を作ってみませんか?

getName (loan, rate) = "loan="++loan++"&rate="++rate

getAnswer (loan, rate) = loan*rate

次に、リスト内包表記を使用します

loans = [1000*x | x <- [1..3]]
interest_rates = [0.005*x | x <- [4..10]]

input_tuples = [(l, i) | l<-loans, i<-interest_rates]]

answers = [(getName t, getAnswer t) | t<-input_tuples]]

モナドは必要ありません。モナドをリストすることすらありません。

于 2012-08-25T14:40:40.217 に答える
1

ここで何を探しているのか正確にはわかりません。金利にどのように名前を付けるのでしょうか。

ただし、もちろん、最終結果とともに金利を保存することもできます。

calc = do                                                                                    
  l <- loan                                                                                  
  i <- interest_rate                                                                         
  return (i, l*i)
-- Yields: [(0.02, 20.0), (0.025, 25.0), ...]
于 2012-08-25T13:31:30.330 に答える