我正在尝试编写一个循环100次的函数,并在此循环中调用一个名为priceJump的函数。当循环首次启动时,此函数的price参数的初始值为100.但是在每个循环之后,该函数会生成一个新的价格,应该传递给priceJump函数。
我试图将此逻辑编码失败(下面的代码)。问题是产生新价格的代码是以monadic方式进行的,所以值是m double类型,其中m受类型PrimMonad约束。
我可能不会在惯用的Haskell中这样做,这就是为什么我遇到这些问题所以任何正确方向的指针也会受到赞赏。总结一下,主要目标是通过传入初始价格来调用定价函数,然后对于它生成的每个新价格,将新价格传递回它。
import Control.Monad.State
import Control.Monad.Primitive
import System.Random.MWC
import System.Random.MWC.Distributions
priceJump :: Double -- price
-> Double -- rate
-> Double -- vol
-> Double -- ts
-> Double -- rnd
-> Double -- new price
priceJump price rate vol ts rnd = price * (1 + (rate * ts) + (vol * sqrt(ts) * rnd))
loop :: PrimMonad m => Gen (PrimState m) -> Int -> Double -> Double -> Double -> Double -> m Double
loop gen turns price rate vol ts
| turns <= 0 = (priceJump price rate vol ts) <$> (normal 0 1 gen)
| turns == 100 = (priceJump price rate vol ts) <$> (normal 0 1 gen)
| otherwise = loop gen (turns - 1) (priceJump price rate vol ts) <$> (normal 0 1 gen) rate vol ts
答案 0 :(得分:3)
在Haskell中考虑循环只会有时有用。如果您想重复k
次内容,则应该找到replicate
之类的内容。在这种情况下,你想重复一个价格并产生100倍新价格的函数(并在一些monad中执行一些计算),然后将它们一起排成长链。
考虑到这一点,代码变为
loop :: PrimMonad m => Gen (PrimState m) -> Int -> Double -> Double -> Double -> Double -> m Double
loop gen turns price rate vol ts
= foldr (>=>)
return
(replicate turns (\p -> priceJump p rate vol ts <$> normal 0 1 gen))
price
事实证明,Kleisli作文(>=> :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
)完全符合您的需要。通过这种方式,您可以看到>=>
与常规函数组合一样,但在monad中。
另一种选择是提前生成随机值,然后只处理那里的纯值 - 即随机种子列表中的纯粹折叠。但是代码最终看起来并没有那么不同:
loop gen turns price rate vol ts
= foldr (\rnd p -> priceJump p rate vol ts rnd) price <$>
replicateM turns (normal 0 1 gen)