私はHaskellでUCTアルゴリズムの実装に取り組んでいますが、これにはかなりの量のデータジャグリングが必要です。詳細に立ち入ることなく、これはシミュレーションアルゴリズムであり、各「ステップ」で、検索ツリーのリーフノードがいくつかの統計プロパティに基づいて選択され、そのリーフに新しい子ノードが構築され、それに対応する統計情報が表示されます。新しいリーフとそのすべての祖先が更新されます。
そのすべてのジャグリングを考えると、私は検索ツリー全体を岡崎のような不変のデータ構造にする方法を理解するのに十分なほど鋭敏ではありません。代わりに、私はST
モナドを少しいじって、可変STRef
のsで構成される構造を作成してきました。不自然な例(UCTとは無関係):
import Control.Monad
import Control.Monad.ST
import Data.STRef
data STRefPair s a b = STRefPair { left :: STRef s a, right :: STRef s b }
mkStRefPair :: a -> b -> ST s (STRefPair s a b)
mkStRefPair a b = do
a' <- newSTRef a
b' <- newSTRef b
return $ STRefPair a' b'
derp :: (Num a, Num b) => STRefPair s a b -> ST s ()
derp p = do
modifySTRef (left p) (\x -> x + 1)
modifySTRef (right p) (\x -> x - 1)
herp :: (Num a, Num b) => (a, b)
herp = runST $ do
p <- mkStRefPair 0 0
replicateM_ 10 $ derp p
a <- readSTRef $ left p
b <- readSTRef $ right p
return (a, b)
main = print herp -- should print (10, -10)
明らかに、この特定の例は、を使用せずに作成する方がはるかに簡単ですST
が、うまくいけば、これをどこに使用するかが明確になります...この種のスタイルをUCTのユースケースに適用する場合、それは間違っていますか?
数年前に誰かがここで同様の質問をしましたが、私の質問は少し違うと思います...必要に応じてモナドを使用して可変状態をカプセル化することに問題はありませんが、それが「適切な場合」の句です。ゲッターとセッターを備えたオブジェクトがたくさんあるオブジェクト指向の考え方に時期尚早に戻ってしまうのではないかと心配しています。正確には慣用的なHaskellではありません...
一方、それがいくつかの問題の合理的なコーディングスタイルである場合、私の質問は次のようになると思います:この種のコードを読みやすく保守しやすくするためのよく知られた方法はありますか?私はすべての明示的な読み取りと書き込みにうんざりしていて、特にモナドSTRef
内の私のベースの構造からST
外の同形であるが不変の構造に変換する必要があることによってうんざりしています。