Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell basic function definition problem

I'm learning Haskell and I'm trying to write a function to return a list of factors for a number. Here's what I have:

factors :: Int -> [Int]
factors n = [x | x <- [2..s], n `mod` x == 0]
    where s = floor (sqrt n)

When I try to load the module in ghci, I get two errors,

p003.hs:3:14:
    No instance for (RealFrac Int)
      arising from a use of `floor' at p003.hs:3:14-27
    Possible fix: add an instance declaration for (RealFrac Int)
    In the expression: floor (sqrt n)
    In the definition of `s': s = floor (sqrt n)
    In the definition of `factors':
        factors n = [x | x <- [2 .. s], n `mod` x == 0]
                  where
                      s = floor (sqrt n)

p003.hs:3:21:
    No instance for (Floating Int)
      arising from a use of `sqrt' at p003.hs:3:21-26
    Possible fix: add an instance declaration for (Floating Int)
    In the first argument of `floor', namely `(sqrt n)'
    In the expression: floor (sqrt n)
    In the definition of `s': s = floor (sqrt n)
Failed, modules loaded: none.

Any suggestions?

like image 925
exupero Avatar asked Mar 06 '11 04:03

exupero


People also ask

How do you define a function in Haskell?

The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.

What does == mean in Haskell?

The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.

What is zipWith in Haskell?

As the name suggests zipWith function in Haskell is used to zip the elements pausing to the function. With the zipWith function, we can pass our vales, zipWith always followed by one operator it can be anything on the basis of which it will zip the value of the argument and produce the result for us.


2 Answers

The parameter has type Int, so you cannot calculate a square root for it. You need to convert it to a floating point type first, which you can do with fromIntegral. Unlike some other languages, Haskell does not automatically promote integers to floating point numbers (nor do any other automatic type conversions).

So change sqrt n to sqrt (fromIntegral n).

like image 180
Chris Smith Avatar answered Sep 22 '22 09:09

Chris Smith


The cause of the problem

The type of the sqrt function is

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

You can check this by typing :t sqrt in ghci.

Int is not an instance of Floating, which is why you're seeing the second error.

The cause of the first error is the same; checking :t floor reveals that the type is:

floor :: (RealFrac a, Integral b) => a -> b

The function is expecting an instance of RealFrac, and you're supplying an Int.

Typing :info RealFrac or :info Floating reveals that neither has an instance for Int, which is why the body of the error says

No instance for ... Int


The solution

The solution to this problem, is to make sure that the types are correct; they must be members of the proper type classes.

A simple way to do this is to use the fromIntegral function, which :t reveals is of type:

fromIntegral :: (Integral a, Num b) => a -> b

Using fromIntegral is necessary because the incoming type is Int, but the functions floor and sqrt operate on types RealFrac and Floating, respectively.

It's allowed because, as you can see from the type signature, fromIntegral returns an instance of Num, which includes both the RealFrac and Floating types. You can convince yourself of this by typing :info Num and :info Float into ghci, and viewing the output.

Making his change to your program would have the final result below, which should work as you want:

factors :: Int -> [Int]
factors n = [x | x <- [2..s], n `mod` x == 0] 
    where s = floor (sqrt $ fromIntegral n) 

Further reading

Two good resources for understanding exactly what's going on are the Haskell tutorial's sections on Type Classes and Numbers.

like image 40
Ezra Avatar answered Sep 23 '22 09:09

Ezra