[Haskell-cafe] arr f

Chris Kuklewicz haskell at list.mightyreason.com
Sat Jan 28 11:49:25 EST 2006


Sven Biedermann wrote:
> Hello Henrik & Ross,
> 
> Man thanks for your input. I have realised that I should have explained
> my problem better.
> 
> So, I try...
> 
> I want to create a datatype like this:
> 
> 	data D a b = DepVoid (a->b)   | -- a = ()
> 			 DepSingle (a->b) | -- a = a      simple ones
> 			 DepPair (a->b)   | -- a = (c,d)
> 			 DepTriple (a->b) | -- a = (c,d,e)
> 			 ...
> 			 DepFun (a->b)      -- a = (c->d)
> 			 ...

You have a serious typing problem in Haskell with that.  Every constructor could
be replaced with DepSingle.

> Its easy to construct them:
> 
> 	mkArrVoid :: (() -> c) -> D () c
> 	mkArrVoid f	= DepVoid f
> 
> 	mkArrPair :: ((a,b) -> c) -> D (a,b) c
> 	mkArrPair f = DepPair f  
> 
> 	...
> 
> Now I want to make D an instance of Arrow:
> 
> 	instance Arrow (D) where -- my problems stems from
> 		arr f = ???
> 
> I have no clue to glue the mkArr* functions together to reach what I
> want: a different Dep* for different functions f.
> What can I pattern match, here? What can I do else?

This is not easily fixable, since (arr = DepSingle ) is always a valid choice
for the compiler to make.  Thus typeclass solutions badly overlap.

> 
> Greetings
> 
> Sven
> 

I can come closer with a GADT.  The serious typing problem is still there.  So I
made arr and pure into error messages.

{-# OPTIONS -farrows -fglasgow-exts #-}
import Control.Arrow

-- GADT style
data D x y where
  DepVoid :: (()->b) -> D () b
  DepSingle :: (a->b) -> D a b
  DepPair :: ((a1,a2)->b) -> D (a1,a2) b
  DepFun :: ( (a1->a2) -> b ) -> D (a1->a2) b

-- And these are the constructors, so we could skip them
mkArrVoid = DepVoid
mkArrSingle = DepSingle
mkArrPair = DepPair
mkArrFun = DepFun

-- The destructor is more annoying (template haskell would help)
-- http://haskell.org/hawiki/GADT_20with_20record_20syntax might make this easier
getF :: D x y -> (x -> y)
getF (DepVoid f) = f
getF (DepSingle f) = f
getF (DepPair f) = f
getF (DepFun f) = f

-- This is useful for diagnosing which constructor you have, for testing
getF' :: D x y -> Int
getF' (DepVoid f) = 1
getF' (DepSingle f) = 2
getF' (DepPair f) = 3
getF' (DepFun f) = 4

instance Arrow D where
  arr _ = error "Use Dep* instead" -- or arr = DepSingle
  pure _ = error "Use Dep* instead" -- or pure = DepSingle
  first arrD = let toPair :: (x->y) -> D (x,d) (y,d)
                   toPair f = DepPair (\(b,d) -> (f b,d) )
               in toPair (getF arrD)
  -- (template haskell would help with defining >>>)
  (>>>) arr1 arr2 = let comp f = (getF arr2) . f
                    in case arr1 of
                         DepVoid f -> DepVoid (comp f)
                         DepSingle f -> DepSingle (comp f)
                         DepPair f -> DepPair (comp f)
                         DepFun f -> DepFun (comp f)

-- This >>> loses the constructor info of arr1 but is simpler
(>>>>) arr1 arr2 = DepSingle ( (getF arr2) . (getF arr1) )



More information about the Haskell-Cafe mailing list