2016-03-26 12 views
2

私は100回ループする関数を記述しようとしています。このループではpriceJumpという関数を呼び出しています。ループが最初に開始されるとき、この関数のprice引数は100の初期値をとる。しかし、すべてのループの後で、関数はpriceJump関数に渡すべき新しい価格を生成する。ループ中に新しい値で関数を呼び出す

私はこのロジックをコード化しようとしましたが、失敗しました(以下のコード)。問題は、新しい価格を生成するコードがモナド的な方法で行われるため、値mの型がDoubleで、mが型クラスPrimMonadによって制約されていることです。

私はおそらく、私がこれらの問題を経験している理由である慣用的なハスケルでこれをやっていないので、正しい方向へのポインタがあればそれも分かります。要約すると、初期価格が引き渡された価格関数を呼び出すことであり、新しい価格が生成されるたびに新しい価格がその値に戻されるべきです。

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 

答えて

3

ハスケルのループに関して考えることが時々役に立ちます。 k回何かを繰り返す場合は、replicateなどに到達する必要があります。この場合、価格をとり、新しい価格を100回生成する(そして、あるモナドで何らかの計算を実行する)関数を繰り返すことを望んでおり、それらをすべて長い連鎖で並べます。

これを考慮して

、コードが

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が)あなたがここに必要な正確に何していることが判明しました。このようにして、>=>は通常の関数構成のように見えますが、モナドの内側にあります。

ランダムな値を事前に生成し、そこから純粋な値を処理することもできます。つまり、ランダムなシードのリストを純粋に折りたたむことです。

loop gen turns price rate vol ts 
    = foldr (\rnd p -> priceJump p rate vol ts rnd) price <$> 
    replicateM turns (normal 0 1 gen) 
+0

追記:これは、リストの素敵な使用であることが判明し、GHCは賢いことと、それは非常に効率的ですので、私のためにリストを離れてストリーミングするために表示されますが、コードが異なることを見終わっていません。 – jozefg

+0

私はあなたの例をコンパイルすることができません。私は間違ったことをする必要があります。私はここにエラーメッセージを貼り付けました:http://lpaste.net/156961。私はあなたの2番目の例のように 'foldr'を使いたかったのですが、ランダムな値のリストを前もって生成する方法は決してできませんでした。 –

+0

@ Mika'ilエラーはこのコードに関連していないようです - 彼らは 'priceJump'関数を指しているようです。しかし、それは私のためにうまくコンパイルされました。あなたのコードに追加された答えの中のどちらの関数も私のためにコンパイルされます。 @jozefg実際には、あなたが頼りにすることができる(まだ私はそうしていない)融合ルールを見つけたら、それはより簡単になりますが、 'foldr/replicate'と' foldr/sequence/replicate'は通常うまくいきます。 – user2407038

関連する問題