Copyright | (c) Justin Le 2015 |
---|---|
License | MIT |
Maintainer | justin@jle.im |
Stability | unstable |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
This module provides tools for working with the automatically derived
serializability and resumability of Auto
s. The first half contains
boring wrappers around encoding and decoding to and from binary,
filepaths on disk, etc.
The second half contains Auto
transformers that "imbue" an Auto
with
IO serialization abilities. Note that these all require an underlying
Monad
that is an instance of MonadIO
.
You have "identity-like" transformers that take an Auto
and spit it
back out operationally unchanged...but every step, it might do some
behind-the-scenes saving or re-load itself from disk when it is first
stepped. Or you have some "trigger enhancers" that take normal Auto
s
and give you the ability to "trigger" saving and loading events on the
Auto
using the Blip
mechanisms and blip stream semantics from
Control.Auto.Blip.
Note that the entire Auto
construct is a little bit awkward when it
comes to performing IO effects --- it isn't exactly what they were
designed for originally. Hooking on effects to stepping can be
powerful, but as of now, not much has been looked into meaningful error
handling when working with IO. If you have any experience with this and
are willing to help, please feel free to send me an e-mail or open an
issue on the issue tracker!
- saveAuto :: Auto m a b -> Put
- resumeAuto :: Auto m a b -> Get (Auto m a b)
- encodeAuto :: Auto m a b -> ByteString
- decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b)
- writeAuto :: FilePath -> Auto m a b -> IO ()
- readAuto :: FilePath -> Auto m a b -> IO (Either String (Auto m a b))
- readAutoDef :: FilePath -> Auto m a b -> IO (Either String (Auto m a b))
- saving :: MonadIO m => FilePath -> Auto m a b -> Auto m a b
- loading' :: MonadIO m => FilePath -> Auto m a b -> Auto m a b
- loading :: MonadIO m => FilePath -> Auto m a b -> Auto m a b
- serializing' :: MonadIO m => FilePath -> Auto m a b -> Auto m a b
- serializing :: MonadIO m => FilePath -> Auto m a b -> Auto m a b
- saveOnB :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b
- loadOnB' :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b
- loadOnB :: MonadIO m => Auto m a b -> Auto m (a, Blip FilePath) b
- saveFromB :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b
- loadFromB' :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b
- loadFromB :: MonadIO m => Auto m a (b, Blip FilePath) -> Auto m a b
Serializing and deserializing Auto
s
To and from Data.Serialize types
saveAuto :: Auto m a b -> Put Source
Returns a Put
--- instructions (from Data.Serialize) on how to
"freeze" the Auto
, with its internal state, and save it to a binary
encoding. It can later be reloaded and "resumed" by
'resumeAuto'/'decodeAuto'.
resumeAuto :: Auto m a b -> Get (Auto m a b) Source
Returns a Get
from an Auto
--- instructions (from
Data.Serialize) on taking a ByteString and "restoring" the originally
saved Auto
, in the originally saved state.
To and from binary
encodeAuto :: Auto m a b -> ByteString Source
Encode an Auto
and its internal state into a ByteString
.
decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b) Source
Resume an Auto
from its ByteString
serialization, giving
a Left
if the deserialization is not possible.
To and from disk
Imbuing Auto
s with serialization
Implicit automatic serialization
Transforms the given Auto
into an Auto
that, when you first
try to run or step it, "loads" itself from disk at the given FilePath
.
Will throw a runtime exception on either an I/O error or a decoding error.
Note that (unless the Auto
depends on IO), the resulting Auto
is
meant to be operationally identical in its inputs/outputs to the
fast-forwarded original Auto
.
:: MonadIO m | |
=> FilePath | filepath to read from and write to |
-> Auto m a b |
|
-> Auto m a b |
Like serializing
, except suppresses all I/O and decoding errors.
Useful in the case that when the Auto
is first run and there is no
save state yet on disk (or the save state is corrupted), it'll "start
a new one"; if there is one, it'll load it automatically. Then, on
every further step in both cases, it'll update the save state.
Triggered (blip stream-based) automatic serialization
Note that these follow the naming conventions from
Control.Auto.Switch: Something "from" a blip stream is a thing
triggered by the Auto
itself, and something "on" a blip stream is
a thing triggered externally, from another Auto
.
Takes an Auto
and basically "wraps" it so that you can trigger saves
with a blip stream.
For example, we can take
:sumFrom
0
saveOnB
(sumFrom
0) ::Auto
IO
(Int
,Blip
FilePath
)Int
It'll behave just like
(with the input you pass in the
first field of the tuple)...and whenever the blip stream (the second
field of the input tuple) emits, it'll save the state of sumFrom
0
to disk at the given sumFrom
0FilePath
.
Contrast to saveFromB
, where the Auto
itself can trigger saves; in
this one, saves are triggered "externally".
Might be useful in similar situations as saveFromB
, except if you want
to trigger the save externally.
Like loadOnB
, except silently ignores errors. When a load is
requested, but there is an IO or parse error, the loading is skipped.
Takes an Auto
and basically "wraps" it so that you can trigger
loads/resumes from a file with a blip stream.
For example, we can take
:sumFrom
0
loadOnB
(sumFrom
0) ::Auto
IO
(Int
,Blip
FilePath
)Int
It'll behave just like
(with the input you pass in the
first field of the tiple)...and whenever the blip stream (the second
field of the input tuple) emits, it'll "reset" and "reload" the
sumFrom
0
from the sumFrom
0FilePath
on disk.
Will throw a runtime exception if there is an IO error or a parse error.
Contrast to loadFromB
, where the Auto
itself can trigger
reloads/resets; in this one, the loads are triggered "externally".
Might be useful in similar situations as loadFromB
, except if you want
to trigger the loading externally.
Intrinsic triggering
:: MonadIO m | |
=> Auto m a (b, Blip FilePath) |
|
-> Auto m a b |
Takes an Auto
that produces a blip stream with a FilePath
and
a value, and turns it into an Auto
that, outwardly, produces just the
value.
Whenever the output blip stream emits, it automatically serializes and
saves the state of the Auto
to the emitted FilePath
.
In practice, this allows any Auto
to basically control when it wants
to "save", by providing a blip stream.
The following is an alternative implementation of saving
, except
saving every two steps instead of every step:
saving2 fp a =saveFromB
(a&&&
(every
2 .pure
fp))
Or, in proc notation:
saving2 fp a = saveFromB $ proc x -> do y <- a -< x b <- every 2 -< fp id -< (y, b)
(Recall that
is the Auto that emits the received value
every every
nn
steps)
In useful real-world cases, you can have the Auto
decide whether or
not to save itself based on its input. Like, for example, when it
detects a certain user command, or when the user has reached a given
location.
The following takes a FilePath
and an Auto
(a
), and turns it into
an Auto
that "saves" whenever a
crosses over from positive to
negative.
saveOnNegative fp a = saveFromB $ proc x -> do y <- a -< x saveNow <-became
(< 0) -< y id -< (y, fp<$
saveNow)
Contrast to saveOnB
, where the saves are triggered by outside input.
In this case, the saves are triggered by the Auto
to be saved itself.
:: MonadIO m | |
=> Auto m a (b, Blip FilePath) |
|
-> Auto m a b |
Like loadFromB
, except silently ignores errors. When a load is
requested, but there is an IO or parse error, the loading is skipped.
:: MonadIO m | |
=> Auto m a (b, Blip FilePath) |
|
-> Auto m a b |
Takes an Auto
that outputs a b
and a blip stream of FilePath
s
and returns an Auto
that ouputs only that b
stream...but every time
the blip stream emits, it "resets/loads" itself from that FilePath
.
The following is a re-implementation of loading
...except delayed by
one (the second step that is run is the first "resumed" step).
loading2 fp a =loadFromB
$ proc x -> do y <- a -< x loadNow <-immediately
-< fpid
-< (y, loadNow)
(the blip stream emits only once, immediately, to re-load).
In the real world, you could have the Auto
decide to reset or resume
itself based on a user command:
loadFrom = loadFromB $ proc x -> do steps <- count -< () toLoad <- case words x of ("load":fp:_) -> do immediately -< fp _ -> do never -< () id -< (steps, toLoad)
This will throw a runtime error on an IO exception or parsing error.