В настоящее время я пишу библиотеку FRP, построенную на стрелках (а именно, timeless). Тем не менее, я столкнулся с проблемой:Могу ли я взять «снимки» для IO Monad?
Если я обернуть IO
действие внутри стрелки, (Signal s IO a b
в этом случае, который является стрелкой Клейсли), я хотел бы сделать «снимок» окончательного возвращаемого значения, а запускать действие каждый раз. Например, у меня есть действие, связанное с чтением файла и разбором в некоторой структуре данных, и в настоящее время это действие запускает каждый кадр обновления. Я немного попытался использовать ленивую оценку Хаскелла, чтобы она не запускалась снова и снова, но это не сработало.
Концептуально Signal
в основном (но не точно)
a -> IO (b, Signal)
Каждое обновление, сам сигнал заменяется новым сигналом. Теперь, я думаю, если я подаю IO
действие с типом IO a
в (используя стрелки Kleisli), я могу как-то заменить 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
вероятно, будет работать, но, как предполагает его название, это, вероятно, «небезопасно», так что я не хочу, чтобы использовать его