PlayHardGoPro
PlayHardGoPro

Reputation: 2933

The function is applied with three arguments

I need to create a list of tuples, each tuple represents a rectangle with (x, y, height,width).
With width constant, and I need to double the value of the height.

The output necessary:

> genRects 3 (0,0)
 [(0.0,0.0,5.5,5.5),(5.5,0.0,5.5,5.5),(11.0,0.0,5.5,5.5),(16.5,0.0,5.5,5.5)]  

My Currently code:

genRects :: Int -> (Int,Int) -> [(Float,Float,Float,Float)]
genRects 0 _ = []
genRects n (x,y) = let height=5.5; width=5.5 in [(fromIntegral x, fromIntegral y, height, width)] genRects (n-1) (x+height, y)  

Getting error:

Couldn't match expected type `(Int->(Int, Int)-> [(Float, Float, Float, Float)])
                                  -> Int -> (Int, Int) -> [(Float, Float, Float, Float)]'
                with actual type `[(Integer, Integer, Double, Double)]'
    The function `[(fromIntegral x, fromIntegral y, height, width)]'
    is applied to three arguments,
    but its type `[(Integer, Integer, Double, Double)]' has none
    In the expression:
      [(fromIntegral x, fromIntegral y, altura, comp)]
        genRects (n - 1) (x + x, y)
    In the expression:
      let
        height= 5.5
        width = 5.5
      in
        [(fromIntegral x, fromIntegral y, height, width)]
          genRects (n - 1) (x + x, y)
Failed, modules loaded: none.  

Also why is it going to double instead of Float?

Upvotes: 1

Views: 1965

Answers (3)

ErikR
ErikR

Reputation: 52049

Any time you have a function which creates n of something where n is an explicit parameter to the function, ask yourself if you could instead write it as:

take n $ some_infinite_list

where some_infinite_list is an expression which creates an infinite list of the somethings.

For instance, here is the pattern of calls created by genRects n (x,y):

genRects n (x,y)
  calls genRects (n-1) (x+h,y)     -- h = height
  calls genRects (n-2) (x+h+h, y)
  calls genRects (n-3) (x+h+h+h, y)
  ...

So if we start with the sequence:

xys = [ (x,y), (x+h, y),  (x+h+h, y), (x+3*h, y), ... ]

and create a function to4Tuple:

to4Tuple :: (Int,Int) -> (Float,Float,Float,Float)

mapping a pair (x,y) to your 4-tuple of floating point numbers, we can write genRects as:

genRects n (x0,y0) = take n $ map to4Tuple sys
  where xys = [ (x,y0) | x <- [x0, x0+h .. ] ]
        to4Tuple (x,y) = ...construct 4-tuple from x,y here...

Now you've avoided explicit recursion in the definition of genRects.

Upvotes: 2

dfeuer
dfeuer

Reputation: 48611

In

[(fromIntegral x, fromIntegral y, height, width)] genRects (n - 1) (x + x, y)

you are applying a list to three arguments. Lists are not functions and cannot be applied like that. GHC is talking about Double because you've confused it and when it doesn't know what sort of floating point it's supposed to be dealing with, it defaults to Double.

Side note: unless you're dealing with algorithms specialty tuned for single precision floating point, or dealing with special library functions that require such, or using unboxed arrays of them to save on space, you should really be using Double in your code.

Upvotes: 1

JHobern
JHobern

Reputation: 864

Have a look at

[(fromIntegral x, fromIntegral y, height, width)] genRects (n-1) (x+height, y)

That doesn't make sense. What you are trying to do is create one of the rectangles, and cons it on to all of the other rectangles, so you should use something like

(fromIntegral x, fromIntegral y, height, width): genRects (n-1) (x+height, y)

However, after making this change, you will see that

Couldn't match expected type `Int' with actual type `Float'
In the second argument of `(+)', namely `height'
In the expression: x + height
In the second argument of `genRects', namely `(x + height, y)'

Which makes sense, you are trying to add a Float (5.5) to the x value, which you have said is an Int. The simplest solution is to use Floats for x,y, instead of Ints. So you can change your code to,

genRects :: Int -> (Float,Float) -> [(Float,Float,Float,Float)]
genRects 0 _ = []
genRects n (x,y) = let height=5.5; width=5.5 in (x, y, height, width): genRects (n-1) (x+height, y) 

And get the desired result.

Upvotes: 6

Related Questions