Reputation: 2933
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
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
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
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 Float
s for x,y, instead of Int
s.
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