2012-01-09 10 views
6

Estaba pasando por some Arrow tutorial, jugando con funciones que devuelven una nueva versión de sí mismos en un intento de mantener algún estado.¿Qué hay de malo en definir la composición de esta manera?

El nuevo tipo se define así:

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

Porque quiero ser capaz de componer circuitos que hacen que sea una instancia de Categoría. Al componer dos circuitos, el resultado también debe ser un circuito. (Circuit b c) . (Circuit a b) da un Circuit a c.

me escribió esto:

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) 

pero falla:

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 

busqué la respuesta en el tutorial y esta respuesta fue la introducción de una función intermedia de este tipo, que recoge muy bien:

(.) = 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) 

No veo la diferencia.

Respuesta

10

El . en new_g . new_f es del preludio, no de Control.Category. Entonces necesita usar Cat...

Pero la forma habitual de usar Control.Category es:

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

perfecto, añadiendo 'Cat.' simplemente funciona. Gracias por el consejo, ahora veo por qué querríamos ocultar la identificación y (.). – Niriel

Cuestiones relacionadas