`Circuit` currying

I don’t have a particular use case for it now, but I mistakenly thought I did a moment ago. Anywho, I’m curious - is there a way to write some function that allows for something like

curryCircuit2 ::
  forall a b c.
  Fwd a ->
  Circuit (a, b) c ->
  Circuit b c -- I don't think this is the right return type
curryCircuit2 fwdA circuit = ???
 where
  circuitFn :: ((Fwd a, Fwd b), Bwd c) -> ((Bwd a, Bwd b), Fwd c)
  Circuit circuitFn = circuit
  circuitFnC :: Fwd a -> Fwd b -> Bwd c -> ???
  circuitFnC fwdA fwdB bwdC = ???

I’m not sure how to write this in a way such that the backwards channel of a isn’t dropped.

Furthermore, I’m not even sure if this is possible. The thought occurred to me since for some of the things I’ve been working on I’ve been treating Circuit a b as approximately analagous to a -> b, thus Circuit (a, b) c would be similar to (a, b) -> c. I thought it would be nice to have something like curry for such a situation.

I don’t think this is possible. If a is a Protocol, it has a Bwd a that must be driven. There is no mechanism in your supplied type that would allow this.

Right, yeah, I’m curious if there’s another way I could write this that would allow for it to be driven still.

The plugin allows you to extract the forward channel as a signal (it will drive the backwards with some typeclass, I don’t quite remember which) And you can then use the forward signals as a normal signal!

foo = circuit $ \input -> do
  Fwd signalFwd -< input
  bar signalFwd -< ()

Maybe it could help if I elaborated a bit more on what exactly my use case is. I’ve been working on writing more Circuits based on this one:

applyC ::
  forall a b.
  (Fwd a -> Fwd b) ->
  (Bwd b -> Bwd a) ->
  Circuit a b
applyC fwdFn bwdFn = Circuit go
 where
  go :: (Fwd a, Bwd b) -> (Bwd a, Fwd b)
  go (fwdA, bwdB) = (bwdFn bwdB, fwdFn fwdA)

in order that I am then able to write something like

zipC ::
  forall a b n.
  (KnownNat n) =>
  Circuit (Vec n a, Vec n b) (Vec n (a, b))
zipC = applyC (uncurry zip) unzip

The general idea here being that Circuit a b now behaves like a -> b. However, the issue is then when I want to drive this Circuit with the output of two others, those must be bound to something first. For example:

let c = circuit $ \(a, b, c, d) -> do
  tup1 <- exampleCircuitA -< (a, b)
  tup2 <- exampleCircuitB -< (c, d)
  idC <| zipC -< (tup1, tup2)

In a more ideal world, I would be able to write something like

let c = circuit $ \(a, b, c, d) -> do
  idC
    <| zipC
    -- Pretend `<<|` is a magical, nonexistent currying operator
    <<| (exampleCircuitA -< (a, b))
    <<| (exampleCircuitB -< (c, d))

Like I said in the first post, the idea is that since zipC is Circuit (a, b) c (sort of), then it’s (sort of) equivalent to (a, b) -> c. As such I’d like to have some equivalent of uncurry for Circuits that would behave like a -> b -> c. I’m just not sure if there’s such a function (operator) or Circuit I could write that would do such a thing. There’s a bunch of ideas I’ve had that seem plausible, but fall apart on some key detail. Or maybe I need to look into creating some Curry a type with a special Protocol instance? Dunno.