Reputation: 2857
I've been playing around with Arrowized FRP libraries in Haskell (Yampa, in particular), but I can't quite figure out how to do "continual" switching. By that I mean that a signal passes through a signal function (sf
below) which is itself a signal (as drawn in the upper half of the image).
Since I don't know ahead of time what the parameters of the switch will be, I can't see how to reduce this to a simpler, binary switch.
How then should one do it, if it's possible at all? I'd prefer Yampa code, but am happy with any Arrowized FRP code. I haven't tried other libraries (e.g. Sodium or Reactive Banana) to know whether I'd have the same confusion in those cases, but I'm curious about them too.
EDIT
To make this clearer an more concrete, I've labeled the image; possible types for the labels are:
in: Either Int (Int -> Int)
1: (Int -> Int) -> (Either Int (Int -> Int) -> (Int -> Int))
sf could be:
(Either Int (Int -> Int) -> (Int -> Int)) -> Either Int (Int -> Int) -> (Int -> Int)
(e.g., app
). But that's only if the part labeled with a question mark represents an input into sf
. If it represents a more complex switch, the type would be
(Either Int (Int -> Int) -> (Int -> Int)) -> (Int -> Int)
instead.
The idea is that I want the circuit to behave as if sf
were app
, with the signal labeled f
representing the function that is applied to in
, and with in
itself being the source of both the arguments to f
s, and the f
s themselves. I want to get a circuit that can process inputs and change it's behavior (the signal functions that constitute it) dynamically based on those inputs.
On the one hand, it seems to me like sf
can't in fact be app
, since in this case we don't have an ArrowApply
; but on the other hand I imagine that same behavior can be achieved with some form of sophisticated switching.
Upvotes: 2
Views: 572
Reputation: 9424
I still think it's a case of ArrowLoop
!
You have
in :: Arr () A
sf :: Arr (A -> B, A) B
one :: Arr B (A -> B)
two :: Arr B C
sf
is just arr (uncurry ($))
.
Then you have sf >>> (one &&& two) :: Arr (A -> B, A) (A -> B, C)
and you can use loop
(or rather loop
with arr swap
judiciously placed) to get an Arr A C
.
Will that give you what you want?
Upvotes: 1
Reputation: 23
You're asking to have an arrow that's output by an arrow to be used as an arrow.
That's what app
from ArrowApply
is for.
If you want to use that in some looped construct like your diagram, you might need ArrowLoop, but actually the do
notation allows you to be fairly flexible with all this stuff anyway.
There's quite a lengthy explanation of app
in this answer but I'll copy the main relevant bit:
What does app exactly do? it's type doesn't even have an (->) It lets you use the output of an arrow as an arrow. Let's look at the type.
app :: ArrowApply m => m (m b c, b) c
I prefer to use m
to a
because m
feels more like a computation and a
feels like a value. Some people like to use a type operator (infix type constructor), so you get
app :: ArrowApply (~>) => (b ~> c, b) ~> c
We think of b ~> c
as an arrow, and we think of an arrow as a thing which takes b
s, does something and gives c
s. So this means app
is an arrow that takes an arrow and a value, and can produce the value that the first arrow would have produced on that input.
It doesn't have ->
in the type signature because when programming with arrows, we can turn any function into an arrow using arr :: Arrow (~>) => (b -> c) -> b ~> c
, but you can't turn every arrow into a function, thus (b ~> c, b) ~> c
is usable where (b ~> c, b) -> c
or (b -> c, b) ~> c
would not be.
Upvotes: 2