【问题标题】:Pattern Matching with Types in HaskellHaskell 中类型的模式匹配
【发布时间】:2014-10-19 00:14:41
【问题描述】:

假设我有一个类型,其中包含定义为的各种对象的坐标:

   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)”等。

我已经用谷歌搜索了这个问题,但我能找到的唯一解决方案是添加一个中间类型,该类型将收集所有不同的对象,以便您可以对该类型进行模式匹配。然而,由于这是一个家庭作业,我不允许修改大块代码来适应这种新类型。

还有其他方法吗?甚至可能没有模式匹配。不得不多次复制同一个函数似乎是糟糕的编程。

【问题讨论】:

  • 你想使用类型类;然后将每个对象关联到一个“点”列表;然后为每个对象定义此类型类的实例,然后您的checkOverlap 函数可以使用类型约束,例如:checkOverlap :: (HasPoints ob) => obj -> Point -> Bool

标签: haskell types pattern-matching


【解决方案1】:

如果允许更改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 作为附加功能。如果不想多次写getPoint,可以使用case

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

【讨论】:

  • 我认为使用模式匹配定义的getPoint 是给定标准的最佳和最自然的解决方案(我倾向于远离 sum 类型的记录)。
【解决方案2】:

考虑更改您的对象类型定义:

data ObjTy = A | B | C

data Object = Obj ObjTy Point

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

【讨论】:

  • 可能不允许:“但是,由于这是一个家庭作业,我不允许修改大块代码以适应这种新类型。”
【解决方案3】:

在我的评论中,这是一种使用类型类的方法:

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)

【讨论】:

  • 这里的typeclass完全没有意义,你只是为Obj定义它,那为什么不直接point :: Obj -> Point呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多