Skip to content

dunai: Clean up & organise Data.MonadicStreamFunction.Async #338

Open
@turion

Description

@turion

The module Data.MonadicStreamFunction.Async only contains a single function, concatS, which uses the MSF constructor (which is discouraged). I've often thought that this function must be a special case of some more general principle, similar to how Yampa's switch functions are special cases of exception handling. The module is called Async because it transforms MSFs such that they consume a different number of input and output samples, as opposed to synchronous transformations like morphS which preserve this.

I got the basic insight for a principled generalization from @AshleyYakeley in haskell/mtl#85 (comment). There, we were discussing how ListT interacts with other monads, and that it is a kind of a stream transformer. The argument is: since MSF (MaybeT m) a b == ListT (ReaderT a m) b, it should have a monad instance. This means that if we define

newtype MSFAsync m a b = MSFAsync (MSF (MaybeT m) a b)

we can define Monad m => Monad (MSFAsync m a).

This monad instance can be interpreted this way:

  • An MSFAsync m a b may output several (potentially infinitely many) bs, while producing side effects in m and consuming one a for every b. It can be understood as a side-effectful, a-consuming list of bs.
  • return produces a 1-element list without any further side effects, disregarding the input value.
  • >>= flatmaps the lists, and similarly join concatenates them.

In particular, if we have msfasync >>= f, and msfasync never terminates (producing infinitely many samples), the result will also never terminate. This special case is concatS.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions