Dre*_*rew 7 haskell sleep artificial-intelligence thread-sleep
我正在Haskell中编写一个游戏AI,我想在游戏状态树中搜索指定的时间(即我总是希望AI需要3秒才能决定要做出什么样的动作)
我怎么能用像Haskell这样的纯语言来做这件事?我希望我需要做一些潜入线程等,但我宁愿尽量减少这个.
一个想法:在每次进程计算部分结果时,将(timeout
来自@MathematicalOrchid建议)与SafeSemaphore中的可变变量结合起来存储中间值:
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
Run Code Online (Sandbox Code Playgroud)
传递给tmo
它的函数将第一个参数作为一个IO
可以用来保存中间结果的动作.如果它被超时,则返回上次保存的结果.结果转换为WHNF,以便真正的计算发生在保存结果的线程中,而不是在返回结果时处理它的那个tmo
.
在此变体中,传递给的函数tmo
必须保存其输出,它不能返回它.但是很容易修改它以便它的签名(a -> IO ()) -> IO a
.
如果你想让事情变得更加纯粹,我建议你创建一个自己的monad来封装这个想法,而不是放弃IO
.
更新:请注意:
尽管运行时将尽力确保不发生任意延迟,但无法保证异常将立即传递.在GHC中,只有当线程到达安全点时才会引发异常,其中安全点是发生内存分配的位置.一些循环不在循环内执行任何内存分配,因此不能被throwTo中断.
(来自throwTo的文档).在上面的示例中,fac
不分配任何内存,因此对于大数字,它不会立即中断.
更新:我创建了一个基于这些想法的小型库,这些想法定义了可以在返回最终结果或在超时时死亡之前返回部分结果的计算monad.请参阅https://github.com/ppetr/timeout-with-results