| Copyright | (c) Justin Le 2015 |
|---|---|
| License | MIT |
| Maintainer | justin@jle.im |
| Stability | unstable |
| Portability | portable |
| Safe Haskell | None |
| Language | Haskell2010 |
Control.Auto.Serialize
Contents
Description
This module provides tools for working with the automatically derived
serializability and resumability of Autos. 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 Autos
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 Autos
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 Autos 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.
Arguments
| :: 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(sumFrom0) ::AutoIO(Int,BlipFilePath)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(sumFrom0) ::AutoIO(Int,BlipFilePath)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
Arguments
| :: 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&&&(every2 .purefp))
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.
Arguments
| :: 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.
Arguments
| :: MonadIO m | |
| => Auto m a (b, Blip FilePath) |
|
| -> Auto m a b |
Takes an Auto that outputs a b and a blip stream of FilePaths
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.