From oleg-at-okmij.org Fri Aug 6 20:29:40 2004
To: haskell-cafe-at-haskell.org
In-Reply-To: <20040806154413.1799d9ad.Malcolm.Wallace@cs.york.ac.uk>
Subject: Partial signatures
Message-ID: <20040807032940.1BDE4AB7E@Adric.metnet.navy.mil>
Date: Fri, 6 Aug 2004 20:29:40 -0700 (PDT)
Status: RO
Malcolm Wallace wrote:
] and since you cannot write a partial signature,
Can't we really?
It seems `partial signature' means one of two things:
- we wish to add an extra constraint to the type of the function
but we don't wish to explicitly write the type of the
function and enumerate all of the constraints
- we wish to specify the type of the function and perhaps some
of the constraints -- and let the typechecker figure out the
rest of the constraints.
Both of the above is easily possible, in Haskell98.
> module PartialSig where
> import Data.Array -- for the examples below
In the first case, suppose we have a function
> foo x = Just x
and suppose we wish to add an extra constraint (Ord x) but without
specifying the full signature of the function. We just wish to add one
constraint.
> addOrd:: (Ord x) => x -> a
> addOrd = undefined
>
> foo' x | False = addOrd x
> foo' x = Just x
Even a not-so-sufficiently smart compiler should be able to eliminate
any traces of the first clause of foo' in the run code. So, the recipe
is to define a function like `addOrd' (or like an identity), give it
the explicit signature with the desired constraint, and then `mention'
that function somewhere in the body of foo. Or, as the example above
shows, prepend a clause of the form
foo arg ... | False = addOrd arg ...
In that case, the body of the function foo does not have to be changed at
all.
For the second case: suppose we wrote a function
> bar a i = a ! i
and wish to give it a type signature
*> bar:: Array i e -> i -> e
But that won't work: we must specify all the constraints:
Could not deduce (Ix i) from the context ()
arising from use of `!' at /tmp/d.lhs:207
Probable fix:
Add (Ix i) to the type signature(s) for `bar'
In the definition of `bar': bar a i = a ! i
But what if we wish to specify the type without the constraints (and
let the compiler figure the constraints out)? Again, the same trick
applies:
> barSig:: Array i e -> i -> e
> barSig = undefined
>
> bar' a i | False = barSig a i
> bar' a i = a ! i
Incidentally, barSig plays the role of a Java interface of a
sort. barSig is a bona fide function, and can be exported and
imported. To make sure that some other function baz satisfies the
barSig interface (perhaps with a different set of constraints), all we
need to do is to say
baz arg1 ... | False = barSig arg1 ...
We can also attach to barSig some constraints. The typechecker will
figure out the rest, for bar' and baz.