我目前正在編寫一個建立在箭頭上的FRP庫(即timeless)。但是,我遇到了一個問題:我可以爲IO Monad拍攝「快照」嗎?
如果我換箭頭內的IO
動作,(Signal s IO a b
在這種情況下,這是一個Kleisli箭頭),我想借一個最終的返回值的「快照」,而不是每次運行動作。例如,我有一個涉及讀取文件並解析爲某種數據結構的操作,並且當前此操作正在運行每一幀更新。我嘗試了一下,以利用Haskell的懶惰評估來防止它一次又一次地運行,但它不起作用。
在概念上,Signal
基本上是(但不完全)
a -> IO (b, Signal)
每次更新中,信號本身是由新的信號所取代。現在,我認爲如果我使用Kleisli箭頭輸入IO a
的IO
動作,我可以以某種方式將Signal
替換爲保留上一個動作最終結果的其他東西。但是,我找不到辦法做到這一點,因爲我無法從IO
中提取任何信息,只是將信號替換爲常量信號似乎不會阻止重新評估操作。
這是一個最小的測試程序:
{-# LANGUAGE Arrows #-}
module Main where
import FRP.Timeless
import Debug.Trace
s1 :: (Monad m) => Signal s m a Int
s1 = mkConst $ trace "Signal 1" $ Just 5
s2 :: (Monad m) => Signal s m Int Int
s2 = arr $ trace "Signal 2" (+1)
s3 :: (Monad m) => Signal s m a()
s3 = arr $ \_ ->()
sc = mkKleisli_ $ \_ -> do
putStrLn "SC"
readFile "test.txt"
sp = mkKleisli_ putStrLn
box :: Signal s IO()()
box = proc _ -> do
file <- sc -<()
sp -< file
returnA -<()
box2 = proc _ -> do
box -<()
main = do
runBox clockSession_ box2
這裏,sc
讀取文件 「Test.txt的」。每次評估。我想找到一種方法來評估一次,並保持價值。
BTW,unsafePerformIO
可能會工作,但是,正如它的名字所暗示的,它可能是「不安全」,所以我不希望使用它