kawaiinekochan
kawaiinekochan

Reputation: 212

Pattern Matching with Types in Haskell

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

Answers (3)

Noon Silk
Noon Silk

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

user2407038
user2407038

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

Zeta
Zeta

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

Related Questions