I implemented transducers in Haskell as follows:
{-# LANGUAGE RankNTypes #-}
import Prelude hiding (foldr)
import Data.Foldable
type Reducer b a = a -> b -> b
type Transducer a b = forall t. Reducer t b -> Reducer t a
class Foldable c => Collection c where
insert :: a -> c a -> c a
empty :: c a
reduce :: Collection c => Transducer a b -> c a -> c b
reduce f = foldr (f insert) empty
mapping :: (a -> b) -> Transducer a b
mapping f g x = g (f x)
Now I want to define a generic map
function. Hence I load the above code into GHCi:
Prelude> :load Transducer
[1 of 1] Compiling Main ( Transducer.hs, interpreted )
Ok, modules loaded: Main.
*Main> let map = reduce . mapping
<interactive>:3:20:
Couldn't match type ‘Reducer t0 b1 -> Reducer t0 a1’
with ‘forall t. Reducer t b -> Reducer t a’
Expected type: (a1 -> b1) -> Transducer a b
Actual type: (a1 -> b1) -> Reducer t0 b1 -> Reducer t0 a1
Relevant bindings include
map :: (a1 -> b1) -> c a -> c b (bound at <interactive>:3:5)
In the second argument of ‘(.)’, namely ‘mapping’
In the expression: reduce . mapping
*Main> let map f = reduce (mapping f)
*Main> :t map
map :: Collection c => (a -> b) -> c a -> c b
So I can't define map = reduce . mapping
. However, I can define map f = reduce (mapping f)
.
I believe that this problem is caused by the monomorphism restriction. I would really like to write map = reduce . mapping
instead of map f = reduce (mapping f)
. Hence, I have two questions:
- What's causing this problem? Is it indeed the monomorphism restriction?
- How do I fix this problem?
If you make
Transducer
anewtype
, than the GHC will work out the types much better. Existential type variable won't escape the scope — transducer will stay polymorphic.In other words, with below definition
map = reduce . mapping
worksAlso you could want to check http://www.reddit.com/r/haskell/comments/2cv6l4/clojures_transducers_are_perverse_lenses/ where definition is
type Transducer a b =:: (a -> Constant (Endo x) a) -> (b -> Constant (Endo x) b)
and various other. Also other interestig discussion.