Sat Jul 23 15:08:45 CEST 2011

General -> concrete type?

I'm trying to express something that doesn't seem to be possible
without special tricks.  Questions: 1. what exactly goes wrong and
2. do I need this?

-- Expr with type annotation and type conversions.
data TExpr = Tfloat {teFloat :: Expr Double}
           | Tint   {teInt   :: Expr Integer}
           | Tbool  {teBool  :: Expr Bool}
             deriving Show

teLift1 :: (Expr a -> Expr a) -> (TExpr -> TExpr)

teLift1 f = l where 
    l :: TExpr -> TExpr
    l (Tfloat x) = Tfloat (f x)
    l (Tint x)   = Tint   (f x)
    l (Tbool x)  = Tbool  (f x)
    l _ = error "teLift1: Type not supported"

The error is:

    Couldn't match expected type `Double'
           against inferred type `Integer'
      Expected type: Expr a
      Inferred type: Expr Integer
    In the first argument of `f', namely `x'
    In the first argument of `Tint', namely `(f x)'
Failed, modules loaded: none.

I think I'm making a conceptual error.  My assumption is that while
`f' has a generic type, at compile time it has a clear and definite
implementation and can't be specialized to the 3 uses of types.

It seems that the approach is flawed.  Is there another way to trick
the compiler into specializing this into 3 different versions?

The following typechecks, but just moves the problem upwards.  Maybe
it is enough though to make this work for instance declarations.

teLift1 ff fi fb = l where 
    l (Tfloat x) = Tfloat (ff x)
    l (Tint x)   = Tint   (fi x)
    l (Tbool x)  = Tbool  (fb x)

teLift2 ff fi fb = l where 
    l (Tfloat x) (Tfloat y) = Tfloat (ff x y)
    l (Tint x)   (Tint y)   = Tint   (fi x y)
    l (Tbool x)  (Tbool y)  = Tbool  (fb x y)

instance Num TExpr where
  (+) = teLift2 (+) (+) (+)
  (*) = teLift2 (*) (*) (*)
  abs = teLift1 abs abs abs
  signum = teLift1 signum signum signum
  fromInteger = Tint . lit

It doesn't seem to be such a problem though.  Just a bit of
duplication to "punish me" because I want to do automatic type
conversion ;)