What I mean by first-order constraint
First, I'll explain what I mean by first-order constraint on arrows: Due to the way arrows desugar, you cannot use a locally bound name where an arrow command is expected in the arrow do-notation.
Here is an example to illustrate:
proc x -> f -< x + 1
desugars to arr (\x -> x + 1) >>> f
and similarly proc x -> g x -< ()
would desugar to arr (\x -> ()) >>> g x
, where the second x
is a free variable. The GHC user guide explains this and says that when your arrow is also a monad you may make an instance of ArrowApply
and use app
to get around this. Something like, proc x -> g x -<< ()
becomes arr (\x -> (g x, ())) >>> app
.
My Question
Yampa defines the accumHold
function with this type: a -> SF (Event (a -> a)) a
.
Due to this first-order limitation of arrows, I'm struggling to write the following function:
accumHoldNoiseR :: (RandomGen g, Random a) => (a,a) -> g -> SF (Event (a -> a)) a
accumHoldNoiseR r g = proc f -> do
n <- noiseR r g -< ()
accumHold n -< f
The definition above doesn't work because n
is not in scope after desugaring.
Or, similarly this function, where the first part of the pair to SF
is meant to be the initial value passed to accumHold
accumHold' :: SF (a,Event (a -> a)) -> a
accumHold' = ...
Is there some combinator or trick that I'm missing? Or is it not possible to write these definitions without an ArrowApply
instance?
tl;dr: Is it possible to define accumHoldNoiseR :: (RandomGen g, Random a) => (a,a) -> g -> SF (Event (a -> a)) a
or accumHold' :: SF (a,Event (a -> a)) -> a
in yampa?
Note: There is no instance of ArrowApply
for SF
. My understanding is that it doesn't make sense to define one either. See "Programming with Arrows" for details.
ArrowApply
or not, but one way to approach the problem is to ask yourself what you think your code without the first-order limitation should desugar to. – Zima-<<
requires anArrowApply
instance so it doesn't make sense here (ie., you can't makeSF
into a monad). – Thermae