Build a (Wire s e m a c) from (a -> b -> c) and (Wire s e m a b)

93 Views Asked by At

As a simple example I have this.

import Prelude hiding ((.))
import FRP.Netwire
import Control.Wire

f :: Int -> Char -> String
f = replicate

w :: => Wire s e m Int Char
w = mkSF_ fromInt
    where
        fromInt :: Int -> Char
        fromInt 1 = 'a'
        fromInt 2 = 'b'
        fromInt _ = '_'

w2 :: Wire s e m Int String
w2 = undefined -- This is where I get stuck

And I would like to be able to create a wire from Int's to Strings.

I think it should be easy, but I'm having no luck.

3

There are 3 best solutions below

0
On BEST ANSWER

Another option is to use applicative syntax, which is even cleaner, imo

w2 :: Monad m => Wire s e m Int String
w2 = f <$> id <*> w

This generalizes to

(Category cat, Applicative (cat a)) => (a -> b -> c) -> cat a b -> cat a c

Note that every Arrow gives rise to the above constraint.

0
On

Another solution I came up with was

w2 :: Monad m => Wire s e m Int String
w2 = liftA2 ($) (mkSF_ f) w
-- or w2 = liftA2 ($) (arr f) w
-- or w2 = arr f <*> w
0
On

You need to split the original Int input and fan it out to both w and arr f. The easiest way to explain it is using arrow notation:

{-# LANGUAGE Arrows #-}
w2 :: (Monad m) => Wire s e m Int String
w2 = proc n -> do
    c <- w -< n
    returnA -< f n c

Now, I don't know the first thing about Netwire, but that Monad m constraint is there because that is needed for the Arrow instance of Wire s e m.

If you want to get rid of the arrow notation, the above can be rewritten as

w2 :: (Monad m) => Wire s e m Int String
w2 = arr (uncurry f) . (id &&& w)

You can, of course, generalize the concept into this abstraction:

-- I want to write (Arrow (~>)) => (a -> b -> c) -> (a ~> b) -> (a ~> c)!
-- Damn you TypeOperators!
arr2 :: (Arrow arr) => (a -> b -> c) -> arr a b -> arr a c
arr2 f arr = proc x -> do
    y <- arr -< x
    returnA -< f x y