Reputation: 212
Say I have a type that contains coordinates of various objects defined as:
type Point = (Int, Int)
data Object = A Point
| B Point
| C Point
I want to create a function that would check for overlap of objects, like so
checkOverlap:: Object -> Point -> Bool
I want to define just one function that would work for all objects, without having to specify "checkOverlap (A point) (x,y)", "checkOverlap (B point) (x,y)" and so on.
I've googled the problem but the only solution I was able to find is to add an intermediate type that would gather all of the different objects so that you can pattern match on that type. However since this is a homework exercise, I'm not allowed to modify large chunks of code to accommodate this new type.
Is there any other way? Maybe not even with pattern matching. It just seems like bad programming having to copy the same function multiple times.
Upvotes: 2
Views: 2532
Reputation: 55172
As in my comment, here's a way with typeclasses:
type Point = (Int, Int)
data Obj = A Point | B Point | C Point
class HasPoint p where
point :: p -> Point
instance HasPoint (Obj) where
point (A p) = p
point (B p) = p
point (C p) = p
checkOverlap :: (HasPoint ob) => ob -> Point -> Bool
checkOverlap ob otherPoint =
undefined
where
myPoint = point ob
somethingA = checkOverlap (A (1,1)) (1,1)
somethingB = checkOverlap (B (1,1)) (1,1)
Upvotes: 1
Reputation: 14623
Consider changing your object type definition:
data ObjTy = A | B | C
data Object = Obj ObjTy Point
checkOverlap:: Object -> Point -> Bool
checkOverlap (Obj _ (x,y)) (u,v) = ...
Upvotes: 1
Reputation: 105965
You can use record syntax if you're allowed to change the definition of Object
:
type Point = (Int, Int)
data Object = A { getPoint :: Point, ... }
| B { getPoint :: Point, ... }
| C { getPoint :: Point, ... }
checkOverlap :: Object -> Point -> Bool
checkOverlap obj pt = doSomething (getPoint obj) pt
If you're not allowed to change the definition and the extraction of points is a common task, you could simply add getPoint
as an addtional function. You can use case
for this if you don't want to write getPoint
several times:
getPoint :: Object -> Point
getPoint obj = case obj of
A pt -> pt
B pt -> pt
C pt -> pt
If you don't want an additional function, but still want only one version of checkOverlap
, you can move the case
into checkOverlap
:
checkOverlap :: Object -> Point -> Bool
checkOverlap obj pt = let opt = case obj of {A a -> a; B b -> b; C c -> c}
in -- use opt and pt
Upvotes: 5