Mon Aug 15 22:18:18 CEST 2011
( EDITED )
I made a couple of implementations that are all quite similar. The
big conclusion seems to be that signal processors are Kleisli arrows
of the monad that represents signals.
Due to problems with the "growing" state types I had to resort to
existentials to be able to hide that state and implement some class
instances. However, this doesn't seem to work for Monad.
The files in ssm/
* StateSpace.hs: simple composition, abstracted as Category with state
hidden. ( Almost an Arrow. )
* SigApp.hs: applicative built from the ground up. I could not
express input-dependent state. This seems to be normal since I
later found that signal operators are Kleisli arrows.
* SigJoin.hs: monad in terms of fmap & join which works a lot better.
This has instances for Functor, Applicative, Category, Arrow (the
Kleisli arrow of the monad) but misses Monad itself due to a problem
with typing existentials.
( There's also SigBind.hs which is similar but more clumsy.
Starting from fmap and join seems to work better. )
About the need for Kleisli arrows; I don't know how to make it precise
but here it goes:
The imposibility to combine input-dependent state as <*> seems to be
simply a property of the purity of the applicative interface: it is
parameterized by pure functions (i -> o) which do not mesh well with
s -> i -> (s, o).
I read that Applicative provides pure expressions and sequencing
but no binding. Maybe that's the point? Maybe what I need to express
needs binding, or more put differently "joining".
Actually, in retrospect, that I need Kleisli arrows isn't such a
surprise. In general, types like (a -> M b) are used for
"representing a computation like a -> b, but with hidden effects", and
influencing state sure looks like an effect. The monad output M b
represents the state update function, and the fact that it depends on
the input a encodes that a can influence the state transition
function, and so indirectly the state when the SSM is unrolled.