2014-10-19 2 views
1

Скажем, у меня есть тип, который содержит координаты различных объектов, определенных как:Pattern Matching с типами в Haskell

type Point = (Int, Int) 

    data Object = A Point 
       | B Point 
       | C Point 

Я хочу создать функцию, которая будет проверять для перекрытия объектов, как и

checkOverlap:: Object -> Point -> Bool 

Я хочу определить только одну функцию, которая будет работать для всех объектов, не указывая «checkOverlap (A point) (x, y)», «checkOverlap (B point) (x, y)» и т. Д.

Я столкнулся с проблемой, но единственным решением, которое я смог найти, является добавление промежуточного типа, который собирал бы все разные объекты, чтобы вы могли сопоставлять шаблоны для этого типа. Однако, поскольку это домашнее задание, мне не разрешено изменять большие куски кода для размещения этого нового типа.

Есть ли другой способ? Возможно, даже не с шаблоном. Просто кажется, что плохое программирование должно копировать одну и ту же функцию несколько раз.

+0

Вы хотите использовать модельные стекла; затем сопоставлять каждому объекту список «точек»; затем определите экземпляры этого typeclass для каждого объекта, а затем ваша функция checkOverlap может использовать ограничение типа, например: 'checkOverlap :: (HasPoints ob) => obj -> Point -> Bool'. –

ответ

5

Вы можете использовать синтаксис записи, если вы позволили изменить определение 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 

Если вы не можете изменить определение и извлечение точек является общей задачей, вы могли бы просто добавьте getPoint в качестве дополнительной функции. Вы можете использовать case для этого, если вы не хотите писать getPoint несколько раз:

getPoint :: Object -> Point 
getPoint obj = case obj of 
       A pt -> pt 
       B pt -> pt 
       C pt -> pt 

Если вы не хотите, дополнительные функции, но все же хочу только одну версию checkOverlap, вы можете переместить case в 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 
+0

Я думаю, что 'getPoint', определенный с помощью сопоставления с образцом, является наилучшим и наиболее естественным решением, учитывая критерии (я склонен держаться подальше от записей с типом суммы). – alternative

0

Рассмотрит изменение объектного определения типа:

data ObjTy = A | B | C 

data Object = Obj ObjTy Point 

checkOverlap:: Object -> Point -> Bool 
checkOverlap (Obj _ (x,y)) (u,v) = ... 
+0

Вероятно, не разрешено: _ «Однако, поскольку это домашнее задание, мне не разрешено модифицировать большие куски кода для размещения этого нового типа». _ – Zeta

1

Как и в моих коммах ent, вот способ с ценами:

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) 
+2

В этом классе нет смысла, вы определяете его только для Obj, так почему бы не просто «point :: Obj -> Point»? – alternative

+0

@alternative, который также будет работать. –