Reputation: 35
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?
Upvotes: 1
Views: 853
Reputation: 120751
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.
Upvotes: 2
Reputation: 477543
In order to "unpack" the Rectangle
, then you write Rectange
between parenthesis:
inPoints :: Point -> Points -> Bool
inPoints (x, y) (Rectangle (x1, y1) (x2, y2)) = --- …
-- ↑ parenthesis ↑
We thus perform pattern matching to obtain the points of the Rectangle
. You can not use Rectange
itself as a patern.
Upvotes: 4