Are the parentheses necessary in this Haskell code - haskell

data Point = Point Float Float deriving (Show)
data Line = Line Point Point deriving (Show)
onLine :: Line -> Point -> Bool
onLine (Line (Point x1 y1) (Point x2 y2)) (Point x y) = True
Is there a way not to use so many brackets ?

I recommend a tool called hlint for identifying places where you can simplify your code.
In your code /as written/, you're not using the values x1, y1, x2, y2, x or y, so you could just write:
onLine _ _ = True
However, I assume that's just a stub, and in reality you will do something with the variables. In general, if you really need to reference all those variables, then you need to write it the way you have done. However, maybe you're using a helper function that only needs the entire line value. Then you could write something like:
onLine l p = blah blah blah
-- use slope l and yIntercept l to figure out if p is on the line
slope :: Line -> Float
slope (Line (Point x1 y1) (Point x2 y2)) = (y2 - y1) / (x2 - x1)
yIntercept :: Line -> Float
yIntercept (Line (Point x1 y1) (Point x2 y2)) = blah blah blah
Alternatively, you can just use accessor functions to extract the x and y co-ordinates from points and lines, but in this case it will probably make your code messier.
Also, in Haskell I believe it's generally more efficient to use Double rather than Float.

You can sometimes avoid brackets with record notation, sometimes with $, sometimes with infix functions, and sometimes they're OK if not excessive.
Let's use record notation for points, which get heavy access for the coordinates, but we'll leave Line alone.
data Point = Point {x::Double,y::Double} deriving (Show)
data Line = Line Point Point deriving (Show)
This defines x :: Point -> Double and y :: Point -> Double.
There's no such thing as equality for floating points, but I'll go for roughly right:
accuracy = 0.000000000001
is :: Double -> Double -> Bool
is x y = abs (x - y) < accuracy
I can use this as x point1 `is` x point2 neatly avoiding the bracketed is (x point1) (x point2)
When your data structure is not so heavily nested with pattern matching, a few brackets are easy to read:
gradient :: Line -> Double
gradient (Line one two) = (y two - y one) / (x two - x one)
But we can go one level deeper without using excessive brackets because of the functions x and y.
asFunction :: Line -> (Double -> Double) -- ( ) for clarity, not necessity
asFunction l#(Line point _) = \xx -> gradient l * (xx - x point) + y point
Notice I've used l# to introduce an alias for (Line point _) to save typing on the right.
Now we can use the infix function trick to get rid of a few more brackets:
onLine :: Line -> Point -> Bool
onLine l p = l `asFunction` x p `is` y p
On the right hand side, you can use $ to get rid of brackets, but you can't use it on the left in pattern matching because it's a function f $ x = f x. For example
this (that (the other thing (something other)))
= this $ that $ the other thing $ something other
= this . that . the other thing $ something other

You can take the line and point apart within the function by defining accessors, but there is no way to do the pattern matching without the parentheses.

Another way of getting rid of the parentheses is to do the pattern matching in a number of case expressions:
onLine l p = case l of
Line p1 p2 -> case p1 of
Point x1 y1 -> case p2 of
Point x2 y2 -> case p of
Point x y -> True -- you can use x1,y1,x2,y2,x and y here
This is close to what the compiler 'translates' the patternmatches to, but of course this is not much of an improvement!
However, there are a number of ways of writing this expression that also translate to the same cascaded pattern matching; here's one:
onLine l p = let
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
in True
and here's another:
onLine l p = True where
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
The last one is pretty nice and readable, in my opinion, but the other suggestions are much better, since they'll lead to a better structured program!
(There's some stuff about irrefutable patterns that I'm glossing over, and this only works for single-constructor datatypes)

Related

The constructor `Rectangle' should have 2 arguments, but has been given none

I have this code
type Point = (Int, Int)
data Points
= Rectangle Point Point
| Union Points Points
| Difference Points Points
inMax :: Int -> Int -> Int
inMax a b
| a < b = b
| otherwise = a
inMin :: Int -> Int -> Int
inMin a b
| a < b = a
| otherwise = b
inPoints :: Point -> Points -> Bool
inPoints (x, y) Rectangle (x1, y1) (x2, y2) = ((inMin x1 x2) <= x && x <= (inMax x1 x2)) && ((inMin y1 y2) <= y && y <= (inMax y1 y2))
I want to know if a point is in Rectangle but i got the next error: The constructor `Rectangle' should have 2 arguments, but has been given none. Why? How I should fix it?
In order to "unpack" the Rectangle, then you write Rectange between parenthesis:
inPoints :: Point -> Points -> Bool
inPoints (x, y) (Rectangle (x1, y1) (x2, y2)) = --- …
-- &uparrow; parenthesis &uparrow;
We thus perform pattern matching to obtain the points of the Rectangle. You can not use Rectange itself as a patern.
The expression inPoints (x, y) Rectangle (x1, y1) (x2, y2), no matter if it appears in a pattern left of the =, or right of it, parses as
(((inPoints (x,y))
Rectangle)
(x1,y1))
(x2,y2)
i.e. Rectangle is passed as an argument all by itself, and then (x1,x2) and (x2,y2) are passed as additional, separate arguments.
That's not completely absurd: in an expression, Rectange is just a function Point -> Point -> Points, and functions can be passed as function arguments just like any other values. For example you could define something like
unionBuilt :: (Point -> Point -> Points) -> [Point] -> Points
unionBuilt f (x₀:x₁:xs) = Union (f x₀ x₁) (unionBuilt xs)
unionBuilt f ... = ...
and that could then legitimately be called like
unionBuilt Rectangle [(1,2),(3,4)]
But in a pattern match, all constructors must be fully applied, i.e. if you pattern match on Rectangle then it must always come with two patterns for the containing points (even if you're not interested in them; then you need to use a blank pattern). This generally requires wrapping it in parentheses
So what you want is
inPoints (x,y) (Rectangle (x₁,y₁) (x₂,y₂)) = ...
Like most parentheses in Haskell expressions, these are only needed if the precedence rules don't already establish this way of parsing. In particular, if you had defined your function as an infix operator, then you would have been fine, and don't actually need any parentheses at all (except for the tuples):
(∈) :: Point -> Points -> Bool
(x, y) ∈ Rectangle (x₁, y₁) (x₂, y₂)
= inMin x₁ x₂ <= x && x <= inMax x₁ x₂
&& inMin y₁ y₂ <= y && y <= inMax y₁ y₂
This is because prefix function application, including constructors like Rectangle, always binds more tightly than infix operator application.

How to enforce type relation and constraints when defing data type

In the following code:
data Point = Point { x :: Int,
leftHeight :: Int,
rightHeight :: Int}
data Rectangle = Rec Point Point
rec1 = Rec p1 p2
There are several constraints when creating Rec such as:
x p1 < x p2
(leftHeight p1 ) should always be zero
(rightHeight p2 ) should always be zero
rightHeight p1 == leftHeight p2
Is there a way to enforce these constraints at type level?
Because I'm using QuickCheck to generate some sample Rec but these contraints make QuickCheck very slow to generate random samples.
edit: I've solved the slow QuickCheck issue. But anyway still curious if such constraint can be expressed in Haskell
To point out the obvious, the standard way of enforcing these constraints at type level would be to define your Rectangle differently:
data Rectangle = Rec
{ x1 :: Int
, x2 :: Int
, height :: Int
}
This enforces all constraints except "x1 < x2". You can use smart destructors to recreate the rectangle's Point "fields":
point1 :: Rectangle -> Point
point1 (Rec x1 _ h) = Point x1 0 h
point2 :: Rectangle -> Point
point2 (Rec _ x2 h) = Point x2 h 0
and define a smart constructor (which can also enforce the "x1 < x2" constraint):
rect :: Point -> Point -> Rectangle
rect (Point x1 0 h1) (Point x2 h2 0) | h1 == h2 && x1 < x2 = Rec x1 x2 h1
rect _ _ = error "bad rectangle"
Seriously, this really is the best way to enforce constraints at the type level in Haskell!

Haskell 2D points distance and length

-- (edit)
-- Punkt = Point
-- Streckenzug = Polygonal chain
-- distanz = distance
-- laenge = length
-- (/edit)
data Punkt = Punkt
{ x :: Float
, y :: Float
}
p1 (x1, x2) =(x1,x2)
p2 (y1, y2) =(y1,y2)
data Streckenzug = Streckenzug {
streckenzug :: [Punkt..]
}
distanz :: Punkt -> Punkt -> Float
distanz (x1,y1) (x2,y2) = sqrt (x' * x' + y' * y')
where
x'= x1-x2
y'= y1-y2
laenge :: Streckenzug -> Float
laenge (x:xs) = if length Streckenzug < 2
then Streckenzug
else sum([distanz p1 p2 | (p1,p2) <- xs ] )
Could somebody tell me why I am getting the parse error on Streckenzug?
The errors that Haskell puts out aren't really helpful.
We have the data Punkt which shall be a point in a two dimensional coordinateesystem
and the data Streckenzug which is a list of points
later on the functions distanz and laenge (length) shall give us the as the sum between adjacent points .
The errors that GHC produces are most certainly helpful. Let's go through them one by one.
Firstly, I get no parse error whatsoever, as long as I remove the spurious indentation at the start. Instead, I get this error:
main.hs:11:17: error:
Not in scope: type constructor or class ‘Punkt..’
No module named ‘Punkt’ is imported.
Looking at the relevant line, I see you've written Punkt.. for no reason. This means nothing. This should just be Punkt. here is the correction, with better indentation.
data Streckenzug = Streckenzug {
streckenzug :: [Punkt] -- Correction here
}
When I fix this, the errors change. Let's go to the next:
main.hs:15:9: error:
• Couldn't match expected type ‘Punkt’
with actual type ‘(Float, Float)’
Looking at the relevant line, I see that you're not matching on Punkt, but actually on (Float, Float)s. This is trivial to fix. Here is the solution, with better indentation:
distanz :: Punkt -> Punkt -> Float
distanz pkt1 pkt2 = sqrt (x' * x' + y' * y') -- Correction here
where
x'= x pkt1 - x pkt2
y'= y pkt1 - y pkt2 -- Note the adjustment here.
Please understand that a Punkt is not simply a tuple of floats; it's treated seperately by the compiler.
Unfortunately, I would try to correct your function laenge, but I cannot at all work out what you mean by it – the types are completely broken, and your intention is unclear. I would recommend learning from the above mistakes and trying again.
All in all, however, the following file works:
data Punkt = Punkt
{ x :: Float
, y :: Float
}
data Streckenzug = Streckenzug {
streckenzug :: [Punkt]
}
distanz :: Punkt -> Punkt -> Float
distanz pkt1 pkt2 = sqrt (x' * x' + y' * y')
where
x'= x pkt1 - x pkt2
y'= y pkt1 - y pkt2
The functions p1 and p2 are completely useless and so I've removed them; not only are they identical, but also are both of type p1, p2 :: (a,b) -> (a,b), in other words p1 = p2 = id.

Running out of memory with recusion in Haskell

Yesterday I finally decided to start learning Haskell. I started scanning through tutorials, but quickly decided practical exercises would be more beneficial. Therefore I proceeded to port a python script of mine which supposedly simulates gravity into Haskell. To my surprise it actually worked and the generated values match those of python.
I realize the implementation is probably absolutely terrible. The horrible lack of performance does not bother me so much, but what bothers me is that I keep running out of memory when attempting to run the simulation for a longer period of time. Is this because the implementation is inherently flawed or can it be made to work?
I have tried to construct the main loop with three different approaches: "iterate", a recursive function (I read about tail recursion, but didn't manage to make it work) and with a more experimental recursive do function. The functions in question are named simulation, test and test2. I compiled the program with option "-O2".
Why does the program run out of memory, and what can I do to prevent that?
Not so relevant parts of the code:
import System.Environment
import Data.List (tails)
import System.CPUTime
import Text.Printf
import Control.Exception
gConst = 6.674e-11
data Vector = Vector2D Double Double | Vector3D Double Double Double deriving (Show)
deltaVector :: Vector -> Vector -> Vector
deltaVector (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x2 - x1) (y2 - y1)
deltaVector (Vector3D x1 y1 z1) (Vector3D x2 y2 z2) = Vector3D (x2 - x1) (y2 - y1) (z2 - z1)
data Position = Position Vector deriving (Show)
data Velocity = Velocity Vector deriving (Show)
distance2DSquared (Vector2D deltaX deltaY) = deltaX ** 2 + deltaY ** 2
distance3DSquared (Vector3D deltaX deltaY deltaZ) = (distance2DSquared $ Vector2D deltaX deltaY) + deltaZ ** 2
distance vector = sqrt (distance3DSquared $ vector)
force vector mass1 mass2 = gConst * (mass1 * mass2) / (distance3DSquared vector)
acceleration force mass = force / mass
vectorComponentDivide (Vector2D x y) c = Vector2D (x/c) (y/c)
vectorComponentDivide (Vector3D x y z) c = Vector3D (x/c) (y/c) (z/c)
vectorComponentMultiply (Vector2D x y) c = Vector2D (x*c) (y*c)
vectorComponentMultiply (Vector3D x y z) c = Vector3D (x*c) (y*c) (z*c)
vectorComponentAdd (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1+x2) (y1+y2)
vectorComponentAdd (Vector3D x1 y1 z1) (Vector3D x2 y2 z2) = Vector3D (x1+x2) (y1+y2) (z1+z2)
invertedVector (Vector2D x1 y1) = Vector2D (-x1) (-y1)
invertedVector (Vector3D x1 y1 z1) = Vector3D (-x1) (-y1) (-z1)
normalizedVector :: Vector -> Vector
normalizedVector vector = vectorComponentDivide vector $ distance vector
velocity vel0 mass1 mass2 vector deltaT =
vectorComponentMultiply (vectorComponentAdd vel0 (vectorComponentMultiply (normalizedVector vector) (acceleration (force vector mass1 mass2) mass1))) deltaT
data Actor = Actor String Vector Vector Double deriving (Show)
earth = Actor "Object1" (Vector3D 0 0 0) (Vector3D 0 0 0) 10
moon = Actor "Object2" (Vector3D 10 0 0) (Vector3D 0 0 0) 10
actors = [earth, moon]
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [ [] ]
combinations n xs = [ y:ys | y:xs' <- tails xs
, ys <- combinations (n-1) xs']
updateVelocity [(Actor name1 position1 velocity1 mass1),(Actor name2 position2 velocity2 mass2)] =
[(Actor name1 position1 a mass1),(Actor name2 position2 b mass2)]
where a = velocity velocity1 mass1 mass2 vector deltaT
b = velocity velocity2 mass2 mass1 (invertedVector vector) deltaT
vector = deltaVector position1 position2
deltaT = 1
updatePosition [(Actor name1 position1 velocity1 mass1),(Actor name2 position2 velocity2 mass2)] =
[Actor name1 (vectorComponentAdd position1 velocity1) velocity1 mass1, Actor name2 (vectorComponentAdd position2 velocity2) velocity2 mass2]
Relevant parts:
update list = map updatePosition (map updateVelocity list)
simulation state n = do
if n == 0
then do
print state
return ()
else do
let newState = update state
simulation newState $! (n-1)
test list n = iterate update list !! n
test2 list 0 = list
test2 list n = (test2 (update list) (n-1))
time :: IO t -> IO t
time a = do
start <- getCPUTime
v <- a
end <- getCPUTime
let diff = (fromIntegral (end - start)) / (10^12)
printf "Computation time: %0.3f sec\n" (diff :: Double)
return v
main :: IO ()
main = do
let combo = combinations 2 actors
putStrLn "Hello World!"
let n = 1000000
print n
--time $ print (test combo n)
time $ simulation combo n
_ <- getLine
putStrLn "BAI"
I believe laziness harms your code: your code builds large thunks (unevaluated expressions) which lead to OOM.
For instance, iterate is (in)famous for leading to large thunks, when you access the resulting list in the middle without forcing the previous list elements. More precisely
iterate f x !! n
is bad, since it will build the expression f (f (f ...(f x))) before really performing any work. We want to evaluate every list element before accessing the next one. This could be dome by a custom !! function:
(!!!) :: [a] -> Int -> a
[] !!! _ = error "!!!: out of range"
(x:_ ) !!! 0 = x
(x:xs) !!! n = seq x (xs !!! pred n)
Now we can use iterate f a !!! n without large thunks building up.
This has the same problem:
simulation state n = do
if n == 0
then do
print state
return ()
else do
let newState = update state
simulation newState $! (n-1)
It will build large update (update (update ...)) thunks without evaluating them. A possible fix could be
...
(simulation $! newState) $! (n-1)
However, keep in mind that in your case newState is a list (of lists!). In such case, seq or $! will only demand the list to be evaluated as far as its first cell constructor -- just enough to check whether the list is empty or not. This "forcing" might be enough or not for your purposes.
There is a library function named deepSeq which will force the full list, if really needed (use Hoogle to find the docs).
Summing up: lazy evaluation has its benefits and its downsides. It usually allows for more efficiency, e.g. sometimes providing constant space list processing without the need of writing carefully crafted functions. It also allows infinite lists tricks which are handy. However, it can also cause unwanted thunks to stick around for too long, wasting memory. So, in those cases, programmers have some burden put on them. Especially when one is used to strict semantics, these issues can be scary at first (we've been there!).

"Overloaded" value constructors

In "Making Our Own Types and Typeclasses" they give the following piece of code :
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
surface :: Shape -> Float
surface (Circle _ r) = pi * r ^ 2
surface (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
nudge :: Shape -> Float -> Float -> Shape
nudge (Circle (Point x y) r) a b = Circle (Point (x+a) (y+b)) r
nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = Rectangle (Point (x1+a) (y1+b)) (Point (x2+a) (y2+b))
main = do
print (surface (Circle (Point 0 0) 24))
print (nudge (Circle (Point 34 34) 10) 5 10)
As it stands the pattern matching against constructors is getting quite cluttered at the point
nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = ....
Had we defined the Shape type as :
data Shape = Circle Point Float | Rectangle Float Float Float Float deriving (Show)
Then even though we lose a bit of clarity into the nature of the type, the patten matching looks less cluttered, as can be seen below :
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Float Float Float Float deriving (Show)
surface :: Shape -> Float
surface (Circle _ r) = pi * r ^ 2
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)
nudge :: Shape -> Float -> Float -> Shape
nudge (Circle (Point x y) r) a b = Circle (Point (x+a) (y+b)) r
nudge (Rectangle x1 y1 x2 y2) a b = Rectangle (x1+a) (y1+b) (x2+a) (y2+b)
main = do
print (surface (Circle (Point 0 0) 24))
print (nudge (Circle (Point 34 34) 10) 5 10)
My question is whether it is possible to have both
Rectangle Point Point
and
Rectangle Float Float Float Float
in the same piece of code (i.e. a sort of "overloading" of value constructors), so that we can do something like :
...
surface (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
...
nudge (Rectangle x1 y1 x2 y2) a b = Rectangle (x1+a) (y1+b) (x2+a) (y2+b)
where the "..." denotes the same as in the code above. Also are there any other tricks to make the notation a bit more compact at the "nudge (Rectangle...." point? Thanks
You could possibly use type classes to make a function behave as both Point -> Point -> Rectangle and Float -> Float -> Float -> Float -> Rectangle, but I wouldn't advocate it. It will be to much trouble for the gain. I don't think there's anyway you could make such an overloaded name usable in pattern matching anyway.
The way I see it, if you're only ever going to be using Point values by deconstructing them and operating on the raw Float values, then you're not really getting that much out of it, so you could resolve your problem by getting rid of it entirely.
But you're missing a golden opportunity to implement a function to adjust a point directly!
For starters I would make an Offset type to hold your a and b values. Then you make a function adjust :: Offset -> Point -> Point to do the combining. And then your nudge doesn't even need to understand the internal structure of a Point to do its job!
For example (Disclaimer: I haven't actually compiled this)1:
data Point = Point Float Float deriving (Show)
data Offset = Offset Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
adjust :: Point -> Offset -> Point
adjust (Point x y) (Offset ox oy) = Point (x + ox) (y + oy)
nudge :: Shape -> Offset -> Shape
nudge (Circle c r) o = Circle (adjust c o) r
nudge (Rectangle p1 p2) o = Rectangle (adjust p1 o) (adjust p2 o)
And similarly there could be a whole family of operations on Point and Offset. For example offsetFrom :: Point -> Point -> Offset could be useful in your surface function. I once went overboard and used type classes to implement a family of operators (|+|, |*|, etc IIRC) which allowed various things to be combined (for example, you can add a Point and an Offset in either order to get a Point, you can add and subtract Offsets but not Points, you can multiply Offsets by scalars but not Points, etc). Not sure whether it was worth it in the end, but it made my code look like my maths a little more!
With your current code you're effectively implementing all operations on Point again every time you need them (including the same adjustment operation twice in the same equation in nudge, which is my take on why it looks quite so bad).
1 There's a certain argument to be made for making functions like adjust and nudge have signatures where the "main" thing being operated on comes last, so adjust :: Offset -> Point -> Point and nudge :: Offset -> Shape -> Shape. This can come in handy because then partially applying adjust gives you a "point transformer" with type Point -> Point, and similarly you can partially apply nudge to get a "shape transformer" with type Shape -> Shape.
This helps when you have a collection of points or shapes and you want to apply the same transformation to all of them, for example:
data Shape = Polygon [Point]
adjust :: Offset -> Point -> Point
adjust (Offset ox oy) (Point x y) = Point (x + ox) (y + oy)
nudge :: Offset -> Shape -> Shape
nudge o (Polygon ps) = Polygon (map (adjust o) ps)
And generally "transformers" with type Something -> Something are just useful things to have on your main data structures. So whenever you have a function that combines some auxiliary data with a Something to produce a new Something, it'll often turn out to be useful to put the Something as the last argument, so you have another easy source of transformer functions.
One option would be to use view patterns. Let me give you a short example:
{-# LANGUAGE ViewPatterns #-}
data Point = Point Float Float
data Shape = Circle Point Float | Rectangle Point Point
rectangleAsPoints :: Shape -> Maybe (Point,Point)
rectangleAsPoints (Rectangle a b) = Just (a,b)
rectangleAsPoints _ = Nothing
rectangleFromPoints :: Point -> Point -> Shape
rectangleFromPoints = Rectangle
rectangleAsCoords :: Shape -> Maybe (Float,Float,Float,Float)
rectangleAsCoords (Rectangle (Point x y) (Point a b)) = Just (x,y,a,b)
rectangleAsCoords _ = Nothing
rectangleFromCoords :: Float -> Float -> Float -> Float -> Shape
rectangleFromCoords a b c d = Rectangle (Point a b) (Point c d)
surface (rectangleAsPoints -> Just (Point x1 y1, Point x2 y2)) =
(abs $ x2 - x1) * (abs $ y2 - y1)
surface (Circle _ r) = pi * r ^ 2
nudge (rectangleAsCoords -> Just (x1,y1,x2,y2)) a b =
rectangleFromCoords (x1+a) (y1+b) (x2+a) (y2+b)
nudge (Circle (Point x y) r) a b = Circle (Point (x+a) (y+b)) r
For consistency's sake I implemented both views of rectangles as functions. This way the actual implementation of the Rectangle type can remain hidden.
Note how you can mix normal pattern matching and view patterns.
What you want is't possibile. For the purposes of pattern matching you could use ViewPatterns as a poor-mans replacement for multiple constructors and make a single function to ease construction:
{-# LANGUAGE ViewPatterns #-}
-- Your pattern match aid
unRectangle :: Shape -> Maybe (Float, Float, Float, Float)
unRectangle (Rectangle (Point x1 y1) (Point x2 y2)) = Just (x1,y1,x2,y2)
unRectangle _ = Nothing
-- your construction aid
rectangle :: Float -> Float -> Float -> Float -> Shape
rectangle x y u v = Rectangle (Point x y) (Point u v)
surface (unRectangle -> Just (x1,y1,x2,y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
...
nudge (unRectangle -> Just (x1,y1,x2,y2)) = rectangle (x1+a) (y1+b) (x2+a) (y2+b)

Resources