私は Haskell でゲーム AI を書いています。指定された時間、ゲーム状態ツリーを検索したいです (つまり、AI がどの動きをするかを決定するのに 3 秒かかるようにしたいのです)。
Haskellのような純粋な言語でこれを行うにはどうすればよいですか? スレッドなどに飛び込む必要があると思いますが、できる限り最小限に抑えたいと思います。
私は Haskell でゲーム AI を書いています。指定された時間、ゲーム状態ツリーを検索したいです (つまり、AI がどの動きをするかを決定するのに 3 秒かかるようにしたいのです)。
Haskellのような純粋な言語でこれを行うにはどうすればよいですか? スレッドなどに飛び込む必要があると思いますが、できる限り最小限に抑えたいと思います。
1 つのアイデア: (@MathematicalOrchid によって提案された) をSafeSemaphoretimeout
の変更可能な変数と組み合わせて、プロセスが部分的な結果を計算するたびに中間値を格納します。
import Control.Monad
import Control.Concurrent.MSampleVar
import System.Timeout
fac :: Integer -> Integer
fac 0 = 1
fac n = n * fac (n - 1)
tmo :: Int -> ((a -> IO ()) -> IO ()) -> IO (Maybe a)
tmo ms f = do
mvar <- newSV Nothing
timeout ms (f (writeSV mvar . (Just $!)))
readSV mvar
longComp :: (Integer -> IO ()) -> IO ()
longComp save = let loop n = save (fac n) >> loop (n + 1)
in loop 0
main :: IO ()
main = tmo 10000 longComp >>= print
に渡された関数はtmo
、最初の引数として、IO
中間結果を保存するために使用できるアクションを取得します。タイムアウトになった場合は、最後に保存された結果が返されます。結果は WHNF に変換されるため、実際の計算は、結果が返されたときに結果を処理するスレッドではなく、結果を保存するスレッドで行われtmo
ます。
このバリアントでは、渡された関数はtmo
その出力を保存する必要があり、それを返すことはできません。ただし、署名が になるように変更するのは簡単(a -> IO ()) -> IO a
です。
物事をより純粋に保ちたい場合は、このアイデアを外にIO
出すことなくカプセル化する独自のモナドを作成することをお勧めします。
更新:次のことに注意してください:
例外がすぐに配信されるという保証はありませんが、ランタイムは恣意的な遅延が発生しないように努めます。GHC では、スレッドがセーフ ポイントに到達したときにのみ例外を発生させることができます。セーフ ポイントは、メモリ割り当てが発生する場所です。一部のループは、ループ内でメモリ割り当てを実行しないため、throwTo によって中断することはできません。
( throwToのドキュメントから)。上記の例では、fac
はメモリを割り当てていないため、大きな数の場合でもすぐに中断されることはありません。
更新:私は、最後の結果を返すかタイムアウトで終了する前に部分的な結果を返すことができる計算のモナドを定義するこれらのアイデアに基づいて、小さなライブラリを作成しました。https://github.com/ppetr/timeout-with-resultsを参照してください
探している結果は時間に依存するため、これには必然的に不純なコードが含まれます。
System.Timeout
パッケージからは、タイムアウトまで I/O 計算を実行する機能が提供されているようbase
です (leftaroundabout のコメントによる) IO
。 . 注意が必要な部分は、未評価の結果を返すだけでなく、IO
アクションが実際に結果を計算するようにすることです。そのためには、からが必要だと思います。evaluate
Control.Exception
System.Timeout
行く方法です。非常にクリーンなインターフェイスを備えているため、スレッドをいじっているような感覚はまったくありません。
ゲームスペースの検索は純粋な計算のように聞こえ、アクションをSystem.Timeout
実行IO
するため、値をでラップし、WHNFに評価された直後に回答が返されたとすぐに信じられないようreturn
に、コードを厳密に評価する必要があります。 timeout
。
私が抱えていた同様の問題から、コードがどのように見えるかの例がここにあります。