Can I take “snapshots” for IO Monad?

I am currently writing an FRP library built on Arrows (namely timeless ). However, I ran into a problem:

If I transfer the action IOinside the arrow, ( Signal s IO a bin this case, which is the Kleisli arrow), I would like to take a “snapshot” of the final return value instead of launching the action every time. For example, I have an action related to reading a file and parsing in some data structure, and currently this action starts every update frame. I tried a bit of using a lazy Haskell evaluation so that it does not run again and again, but it doesn’t work.

Conceptually, Signalmostly (but not exactly)

a -> IO (b, Signal)

Each update, the signal itself is replaced by a new signal. Now I think that if I pass an action IOwith type IO ain (using the Kleisli arrows), I can somehow replace Signalit with something else that contains the final result of the previous action. However, I cannot find a way to do this, because I cannot extract anything from it IO, and just replacing the signal with a constant one does not seem to stop the action from re-evaluating.

This is the minimum test program:

{-# 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

Here screads "Test.txt" file. He is evaluated every time. I would like to find a way to evaluate only once and keep the value.

BTW will unsafePerformIOprobably work, but as its name suggests, it is probably “unsafe”, so I don’t want to use it

+4
1

, , , :

onceSwitch = mkPureN $ (\_ -> (Just (), mkEmpty))

( Prefab of timeless):

occursFor :: b -> Int -> Signal s m a b
occursFor b n
    | n == 0 = mkEmpty
    | n > 0 = mkPureN $ \_ -> (Just b, occursFor b $ n-1)
    | otherwise = error "[ERROR] occursFor: Nothing occurs for less than zero times!"

() , , :

onceIO = SGen $ f
  where
    f _ ma = return (ma, SArr $ const ma)

. IO:

file <- onceIO <<< sc <<< () `occursFor` 1 -< ()

, , . (: occursFor)

, . , API timeless , , , , . , netwire, timeless, . , .

{-# LANGUAGE Arrows #-}

module Main where

import FRP.Timeless
import Debug.Trace

sc = mkKleisli_ $ \_ -> do
  putStrLn "SC"
  return "A"
sp = mkKleisli_ putStrLn

box :: Signal s IO () ()
box = proc _ -> do
  file <- snapOnce <<< sc <<< inhibitsAfter 1 -< ()
  sp -< file
  returnA -< ()

box2 = proc _ -> do
  box -< ()

main = do
  runBox clockSession_ box2
+1

Source: https://habr.com/ru/post/1611128/


All Articles