[Haskell-beginners] Need Help

Daniel Fischer daniel.is.fischer at web.de
Mon Apr 13 00:01:26 EDT 2009


Am Samstag 11 April 2009 14:16:47 schrieb kaushal Pathak:
> Hi There,
>    Here is a very simple haskell program I have written to find whether a
> number is prime or not, which doesn't give me any compilation error but
> gives following run-time error :
>
> Any help would help me move ahead, I know that the type concepts is what I
> am lacking, anly pointer to simple/good article/paper would definitely
> help.
>
> Lots of thannx jut even to look at the mail :-)
>
> Regards
> Kaushal
>
> *Run Time Error :*
>
> kaushal > isPrime1 171
>
> <interactive>:1:0:
>     Ambiguous type variable `t' in the constraints:
>       `Integral t'
>         arising from a use of `isPrime1' at <interactive>:1:0-11
>       `Floating t'
>         arising from a use of `isPrime1' at <interactive>:1:0-11
>       `RealFrac t'
>         arising from a use of `isPrime1' at <interactive>:1:0-11
>     Probable fix: add a type signature that fixes these type variable(s)
> kaushal >
>
> *Program :*
>
> isPrime1 x =
>     let canDivide num 0 = 0
>         canDivide num 1 = 0
>         canDivide num divisor = if ((mod num divisor) == 0) then 1
>                                 else canDivide num (divisor - 1)
>     in
>         if ( x == 1 )
>         then putStrLn("1 is Neither prime nor composite!!!")
>         else if ((canDivide x first_div) == 1)
>              then putStrLn(show(x) ++ " is not a Prime Number!!!")
>              else putStrLn(show(x) ++ " is a Prime Number!!!")
>         where
>         first_div :: Integral a => a ; first_div = round (sqrt x)

Make it first_div = round (sqrt $ fromIntegral x)

And use Bool for boolean expressions:

canDivide num 0 = False
canDivide num 1 = False
canDivide num divisor = num `mod` divisor == 0 || canDivide num (divisor -1)

The error happens because Haskell does no automatic type conversions.
In canDivide, you use mod on x, since the type of mod is

Prelude> :t mod
mod :: (Integral a) => a -> a -> a

both arguments of canDivide must belong to the same type which must be an Integral type.
The second argument of canDivide is first_div, which you defined as

first_div = round (sqrt x)

The type of sqrt is

Prelude> :t sqrt
sqrt :: (Floating a) => a -> a

so to call sqrt x, the type of x must belong to the Floating class, the result of sqrt has 
the same type as its argument.

Then you round the result of sqrt, the type of round is

Prelude> :t round
round :: (RealFrac a, Integral b) => a -> b

The argument of round is the result of sqrt, which has the same type as x, which also must 
belong to the class RealFrac for this to work.

So, for your function to work, its argument must have a type belonging to the three 
classes
Integral
Floating
RealFrac

That's perfectly legal, so the code compiles and isPrime1 has the type

isPrime1 :: (Integral a, Floating a, RealFrac a) => a -> IO ().

And when you type

isPrime1 171

at the prompt, ghci doesn't really know what to do, to know that, it must know the exact 
type of 171 (different types could expose different behaviour and might even lead to 
different results). Since all classes are standard classes and at least one of them is 
numeric, ghci tries then to default the type, looking for a type satisfying these 
constraints in the default list (Integer, Double is the default-default).

But there is no type which belongs to all three classes (unless you provide the instances 
for some type, and it wouldn't really make sense for a type to be Integral as well as 
Floating), so ghci gives up and reports that it couldn't resolve the type variable.

In situations like this, usually the remedy is inserting a few explicit conversion 
functions.



More information about the Beginners mailing list