Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work around the first-order constraint on arrows?

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.

like image 749
Jason Dagit Avatar asked Jun 29 '13 23:06

Jason Dagit


2 Answers

This is a theoretical answer. Look to Roman Cheplyaka's answer to this question, which deals more with the practical details of what you're trying to achieve.


The reason n is out of scope is that for it to be in scope to use there, you would have the equivalent of bind or >>= from monads. It's the use of the results of a previous computation as a functional input to the next which makes something as powerful as a monad.

Hence you can supply n as a function argument to a subsequent arrow exactly when you can make an ArrowApply instance.

Chris Kuklewicz correctly points out in his comment that -<< would bring n into scope - it also uses app, so you need an ArrowApply instance.

Summary

Not unless you use ArrowApply. This is what ArrowApply is for.

like image 98
AndrewC Avatar answered Oct 01 '22 09:10

AndrewC


noiseR is a signal function; it produces a stream of random numbers, not just one random number (for that, you'd just use randomR from System.Random).

On the other hand, the first argument of accumHold is just one, initial, value.

So this is not just some limitation — it actually prevents you from committing a type error.

If I understand correctly what you're trying to do, then simply using randomR should do the trick. Otherwise, please clarify why you need noiseR.

like image 31
Roman Cheplyaka Avatar answered Oct 01 '22 10:10

Roman Cheplyaka