clocker
clocker

Reputation: 1366

Using (ceiling . sqrt) in range causes error

I just started learning Hasekll a few days ago and was playing around with ranges when I ran into a cryptic error while trying a quick and dirty prime number checker.

isprime n = all ((<) 0)  [n `rem` k | k <- [2..n-1]] -- okay
isprime' n = all ((<) 0)  [n `rem` k | k <- [2..(ceiling . sqrt) n]] -- compiles but busted

Example:

Prelude> isprime 19
True

Prelude> isprime' 19

<interactive>:46:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘isprime'’
      prevents the constraint ‘(Floating a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Floating Double -- Defined in ‘GHC.Float’
        instance Floating Float -- Defined in ‘GHC.Float’
    • In the expression: isprime' 19
      In an equation for ‘it’: it = isprime' 19

<interactive>:46:10: error:
    • Ambiguous type variable ‘a0’ arising from the literal ‘19’
      prevents the constraint ‘(Num a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Num Integer -- Defined in ‘GHC.Num’
        instance Num Double -- Defined in ‘GHC.Float’
        instance Num Float -- Defined in ‘GHC.Float’
        ...plus two others
        ...plus one instance involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘isprime'’, namely ‘19’
      In the expression: isprime' 19
      In an equation for ‘it’: it = isprime' 19

So I checked the following, and both turn out as expected.

Prelude> [rem 19 k | k <- [2.. 19-1]] 
[1,1,3,4,1,5,3,1,9,8,7,6,5,4,3,2,1]

Prelude> [rem 19 k | k <- [2..(ceiling . sqrt) 19]] 
[1,1,3,4]

Can anyone help me understand the issue? If there is a good section in the online Haskell tutorials, would appreciate a pointer. Thanks!

Upvotes: 0

Views: 206

Answers (1)

chi
chi

Reputation: 116139

Use an explicit conversion, instead:

[2..(ceiling . sqrt . fromIntegral) n]

Otherwise, you are calling sqrt on the type of n, forcing that type to be a Floating. The rest of the code already requires n to have some Integral type.

These two requirements can not be satisfied: standard numeric types are either floating point, or fixed point (Integral, roughly).

It would also greatly help if you started to write your functions from their type annotations. This prevents GHC to infer a type which was not intended -- when that happens errors are detected much later on, causing confusion.

Upvotes: 1

Related Questions