[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