[Haskell-cafe] Are casts required?
Steffen Schuldenzucker
sschuldenzucker at uni-bonn.de
Mon Jun 6 11:22:22 CEST 2011
Hi Patrick,
On 06/06/2011 09:45 AM, Patrick Browne wrote:
> Are casts required to run the code below?
> If so why?
> Thanks,
> Pat
>
>
> -- Idetifiers for objects
> class (Integral i) => IDs i where
> startId :: i
> newId :: i -> i
> newId i = succ i
> sameId, notSameId :: i -> i -> Bool
> -- Assertion is not easily expressible in Haskell
> -- notSameId i newId i = True
> sameId i j = i == j
> notSameId i j = not (sameId i j)
> startId = 1
>
>
> instance IDs Integer where
>
>
>
> -- are casts need here?
> sameId (newId startId::Integer) 3
I'll take this as an example. First of all, note that
WHAT YOU'VE WRITTEN IS NOT A CAST
, that is, if x is an Int, then x :: Double is a type error. What the
'::' does is (in this situation) that it specializes the type of a
polymorphic value.
In GHCi, omitting the ':: Integer' part, I get
*Main> let x1' = sameId (newId startId) 3
<interactive>:1:10:
Ambiguous type variable `i' in the constraint:
`IDs i' arising from a use of `sameId' at <interactive>:1:10-33
Probable fix: add a type signature that fixes these type variable(s)
Let's take the above expression apart:
We have:
*Main> :t newId startId
newId startId :: (IDs i) => i
*Main> :t 3
3 :: (Num t) => t
*Main> :t sameId
sameId :: (IDs i) => i -> i -> Bool
Now, when trying to evaluating your expression, the machine ultimately
has to know what (newId startId) and 3 are. This, of course, depends on
the type chosen for i and t, respectively.
For example, if I define the following instance:
instance IDs Int where
startId = 2
we have:
*Main> sameId (newId startId :: Integer) 3
False
*Main> sameId (newId startId :: Int) 3
True
, so the result type clearly depends on the types chosen.
But, lacking an explicit signature, there is no way for the machine to
tell which types should be used, in particular as the information which
types were chosen is completely lost in the resulting type 'Bool'.
The example above does not look as if it was created to illustrate your
problem. Then however, note that you don't have to use a class if you
don't expect people to overwrite your default implementations. Normal
Functions are sufficient:
> -- I always want this
> {-# LANGUAGE NoMonomorphismRestriction #-}
>
> startId :: (Integral i) => i
> startId = 1
>
> newId :: (Integral i) => i -> i
> newId = succ
>
> sameId, notSameId :: (Integral i) => i -> i -> Bool
> sameId = (==)
> notSameId i j = not $ sameId i j
Ok, now this works even without the signatures:
*Main> sameId (newId startId) 3
False
, which is probably caused by defaulting on the top level (IIRC, an
unresolved Integral type variable defaults to Integer. Don't have the
documentation at hand right now.) like this:
*Main> let i3 = 3 :: (Integral x => x)
*Main> :t i3
i3 :: Integer
and the same thing happens on the (newId startId) side, too.
As one last remark, your original problem that caused the "Ambiguous
type variable" error looks very similar to the well-known (show . read)
problem.
-- Steffen
More information about the Haskell-Cafe
mailing list