What's wrong with defining composition this way?

214 views Asked by At

I was going through some Arrow tutorial, toying with functions returning a new version of themselves in an attempt to maintain some state.

The new type is defined like that:

newtype Circuit a b = Circuit {runCircuit :: a -> (b, Circuit a b)}

Because I want to be able to compose circuits I make it an instance of Category. When composing two circuits, the result must also be a circuit. (Circuit b c) . (Circuit a b) gives a Circuit a c.

I wrote this :

import qualified Control.Category as Cat
instance Cat.Category Circuit where
    (Circuit g) . (Circuit f) = Circuit $ \a -> let
                                                    (b, new_f) = f a
                                                    (c, new_g) = g b
                                                    new_circ = new_g . new_f
                                                in (c, new_circ)

but it fails:

Main.hs:70:64:
    Couldn't match expected type `b0 -> c0'
                with actual type `Circuit b c'
    In the first argument of `(.)', namely `new_g'
    In the expression: new_g . new_f
    In an equation for `new_circ': new_circ = new_g . new_f

I looked up the answer in the tutorial and this answer was introducing an intermediate function like this, which compiles nicely:

(.) = dot where
    (Circuit g) `dot` (Circuit f) = Circuit $ \a -> let
                                                        (b, new_f) = f a
                                                        (c, new_g) = g b
                                                        new_circ = new_g `dot` new_f
                                                    in (c, new_circ)

I fail to see the difference.

1

There are 1 answers

1
Sjoerd Visscher On BEST ANSWER

The . in new_g . new_f is from the prelude, not from Control.Category. So you need to use Cat...

But the usual way to use Control.Category is:

import Prelude hiding (id, (.))
import Control.Category