2016-04-12 17 views
1

私はいくつかのコードを残していますが、残念なことに、プログラム内の状態を追跡するための参照の幅広い使用があります。オイラー法を経て、多くの値を更新し一つのモジュールにおけるそれらの特に悪質な利用があります:バインディングを繰り返す方法はありますか?

eulerUpdate states timestep = do 
    _val1 <- readReference (val1 states) 
    _dval1 <- readReference (dval1 states) 
    _val2 <- readReference (val2 states) 
    _dval2 <- readReference (dval2 states) 
    -- ... 
    _valn <- readReference (valn states) 
    _dvaln <- readReference (dvaln states) 
    let euler val deriv = val + deriv * timestep 
    writeReference (val1 states) euler _val1 _dval1 
    -- ... 
    writeReference (valn states) euler _valn _dvaln 

私はHaskellのは比較的新しいんだけど、私の理解では、この恐ろしい、恐ろしい、ない良い、非常に悪いことということです。その周りのすべてのものをリファクタリングするのではなく、読みやすさのためにLOCを少なくするための方法があると思っていました。 readReference (x states)を多数の識別子に「マップ」するためにここで実行できることはありますか?私はKliesliの矢をもっと見てきましたが、私はここで私を助けてくれることはあまりありません。

+3

これらはおそらくすべての異なるタイプがありますか?そうでなければ、 'mapM'や' forM'を使ってこれをリスト表現に変換できるはずですが、それほど素晴らしいものは得られません - しかし、あなたがよく見れば、2つの値だけを一緒に使用するようです本当に長いリストなぜあなたはこれを利用していないのですか? – Carsten

+1

私はいくつかの派手なリファクタリング技術の必要はないと思う、単純な機能はおそらくトリックを行うでしょう。例えば'f ::(状態 - >参照a) - >(状態 - >参照b) - >(a - > b - > IO a) - > IO a = \ val dval f - > join(f <$> readReference (valval states)<*> readReference(dval states))>> = writeReference(val states) ' - 明らかに正確な型が分からない(少なくとも)すべての参照が同じ型を持つ場合は、 'map'のようなものを使用してください。 – user2407038

答えて

1

まず最初に、読み書き操作を並べ替えることは可能ですか?もしそうなら、あなたは

let updateOne val dval = do 
    _val = readReference (val states) 
    _dval = readReference (dval states) 
    writeReference (val states) (euler _val _dval) 

のような単純なもので逃げることができない場合は、単に

eulerUpdate states timestep = do 
    updateOne val1 dval1 
    updateOne val2 dval2 
    ... 

のようにそれを使用して、書き込みが読書を崩し、よく、あなたは創造的な取得したい場合がありますし、操作は別々の読み取りおよび書き込み続けるが、同じ構造で:

data ReadWriteReference where 
    ReadWriteReference :: (States -> IO a) -> (States -> a -> IO()) -> ReadWriteReference 
performReadWrite :: States -> ReadWriteReference -> IO() 
performReadWrite states (ReadWriteReference read write) = do 
    a <- read states 
    write states a 
makeRW :: (States -> Reference) -> (States -> Reference) -> ReadWriteReference 
makeRW val dval = ReadWriteReference read write where 
    read states = do 
     _val <- readReference (val states) 
     _dval <- readReference (dval states) 
     writeReference (val states) (euler _val _dval) 
(<+>) :: ReadWriteReference -> ReadWriteReference -> ReadWriteReference 
ReadWriteReference read1 write1 <+> ReadWriteReference read2 write2 = ReadWriteReference read write where 
    read states = do 
     a <- read1 states 
     b <- read2 states 
     return (a, b) 
    write states (a, b) = do 
     write1 states a 
     write2 states b 

今、あなたはこのようにそれを使用することができます:

ReadWriteReferenceをMonoidのインスタンスにして標準コンビネータを使用することもできます。

関連する問題