我想使用Haskell来解决财务组合问题,列表monad似乎非常适合这个。
现在,我对list monad的问题是它无法为所涉及的值赋予名称。我将尝试举例说明:
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, ... ]
),但我不知道每次计算的贷款和利率是多少。
我迷失在这里,我的直觉告诉我要创建我自己的monadic类型,比如说HelpfulNumber :: (String,[Double])
并以某种方式说:
>>=
和return
应为>>= . snd
和return . snd
我是在正确的路线上,还是有更好的方法?说实话,我感到有些失落。
答案 0 :(得分:6)
您可以使用记录类型使输出更清晰:
data Loan = Loan {final :: Double,
rate :: Double,
loan :: Integer,
years :: Int}
deriving Show
printloans :: [Loan] -> IO()
printloans = mapM_ print
在ghci提示符处使用printloans loans
或printloans loans'
。
编辑:我忘了包含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]
]
但如果你喜欢monadic风格,你可以使用:
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
....
但我认为记录类型多更好 - 它的输出更容易阅读,而且字符串的麻烦也更少。
答案 1 :(得分: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]]
不需要monad,甚至不包括monad。
答案 2 :(得分:1)
我不确切地知道你在这里寻找什么,因为你如何给出利率的名字?
但是你当然可以存储利率以及最终结果:
calc = do
l <- loan
i <- interest_rate
return (i, l*i)
-- Yields: [(0.02, 20.0), (0.025, 25.0), ...]