[Haskell-beginners] question on types
Daniel Fischer
daniel.is.fischer at googlemail.com
Fri Jul 29 18:50:25 CEST 2011
On Friday 29 July 2011, 18:14:30, Jake Penton wrote:
> On 2011-07-29, at 11:22 AM, Brandon Allbery wrote:
> > Ask yourself this: is True *every* instance of Ord? You are expecting
> > it to be an "any", but it's an "every" (forall).
> >
> > By the way, True happens to be an instance of Ord but it doesn't have
> > to be. You're working backwards here, I think. It happens that
> > useful operations on things in class Ord generally produce Bool; that
> > doesn't mean Bool must be Ord.
>
> Right - actually, I did not expect it to compile. I gave the code as,
> perhaps, a counterexample to what some other responses seemed to be
> asserting, although it is possible I did not get their point(s)
> correctly. They seemed to say that adding a constraint is of itself
> what makes the cases that used numeric literals work.
Given the fact that per the report a numeric literal is interpreted as a
call to fromInteger or fromRational (depending on whether it's an integer
literal or a fractional literal), the addition of the constraint is all
that is needed to make it work, since by those functions' types, the value
represented by a numeric literal is polymorphic.
f = 1
is really
f = fromInteger 1&
(where n& stands for the Integer of the appropriate value, it's not
Haskell; in GHC [with integer-gmp], it would be
f = fromInteger (S# 1#)
where S# is a constructor of Integer [MagicHash extension required to use
it] and 1# is a literal of type Int#, raw signed machine int, four or eight
bytes of raw memory).
True, on the other hand, is a monomorphic value of type Bool, it cannot
have any other type than Bool and trying to specify any other type for it
leads to a compile time error.
> But it seems (as
> described in Brent Yorgey's post) that there is more to it than that.
The fundamental difference is monomorphic vs. polymorphic expressions.
A monomorphic expression like [True] has a specific type, it doesn't make
sense to add constraints to it (but it makes sense to ask whether
constraints are satisfied for using it).
A polymorphic expression like (toEnum 0) can have many types, but in
general the types it can have are constrained by the types of
subexpressions/used functions. There is a minimal set of constraints you
need to specify, e.g.
l = [toEnum 0, 3]
needs the constraints (Enum a) and (Num a) in the type signature
l :: (Num a, Enum a) => [a]
but you can use more or more restrictive constraints to specify a less
general type than it could have, for example
l :: (Enum a, Bounded a, Num a, Read a) => [a]
or
l :: (Enum a, RealFrac a) => [a]
are valid signatures since they are less general/more constrained than the
first one.
You could also give a monomorphic signature, l :: [Double], which will
compile if and only if the specified type of list elements belongs to Num
and Enum.
More information about the Beginners
mailing list