在Haskell中表示的OO类

时间:2014-02-20 20:57:48

标签: oop haskell

ħ!

假设我有一个抽象类Robot,其中包含一些像'position'和'weight'这样的attributs。这个抽象类实现了三个方法:'take','drop'和'move',但也有一个抽象方法'makeAction'。然后我有两个名为'TRobot'和'FRobot'的子机器人。基本上,TRobot和FRobot将实现'makeAction'方法,但不会重新实现'take','drop'和'move'。

我的问题是你如何在Haskell中做到这一点。

我从数据类型开始:

data Robot = Robot {position :: Char, weight :: Int}


编辑:

但是如果机器人是TRo​​bot或FRobot,我希望函数'take','move'和'drop'(take :: Box - > Robot - > Robot)表现相同。

但是,功能

makeAction :: Robot -> Action
无论Robot是TRobot还是FRobot,

应该有不同的实现。

感谢您的帮助。

5 个答案:

答案 0 :(得分:15)

我有<在这里插入面向对象的设计>。如何在非OO语言(如Haskell)中实现它?

呃...这不是一个好主意。退一步并解释你实际上想要实现的可能会好得多。 Haskell需要一种完全不同的思考软件设计的方式。在不知道你真正想做什么的情况下,很难确切地知道实现它的最佳方式是什么。

特别是:两种机器人实际上有何不同?它们如何相似?

可能您只想构建单个数据类型的构造函数(正如您所编写的),move函数对每个函数的行为都不同,take / drop函数那不在乎。或者您可能只需要一个构造函数,并且该字段指出它是哪种机器人类型。或者您可能真的想要两个完全独立的类型。如果不了解你想做什么,就很难说。

答案 1 :(得分:7)

在Haskell中有一些很多方法可以做到这一点,但你必须首先理解传统的“类”并不直接对应于任何Haskell结构。

你可以很容易地做到这样的事情:

data Robot = Robot {
    position :: Char,
    weight :: Int,
    makeAction :: Robot -> String
}

此处,makeAction是包含TRobotFRobot类型的不同功能的字段。有很多更复杂的方法可以做到这一点,比如类型类,GADT,组合等等,但这会让你开始。

键入类版本

这是一种不同的方式,这更复杂。

这是一个普通的类型版本:

-- The robot type is expressed using a type parameter (called "a")
data Robot a = Robot {
    position :: Char,
    weight :: Int
}

-- All robot types have their own "makeAction" function
class RobotType a where
    makeAction :: Robot a -> String

data TRobot
instance RobotType TRobot where
    makeAction robot = ...

data FRobot
instance RobotType FRobot where
    makeAction robot = …

请注意,Robot TRobotRobot FRobot 不同类型,因此如果您需要通用机器人类型,则必须使用存在类型:

data AnyRobot = forall a. RobotType a => AnyRobot (Robot a)

基本上,因为我们在类型系统中存储TRobot和FRobot之间的差异,我们需要存在类型以允许我们在运行时访问这些差异(因为类型在编译时被删除)。

答案 2 :(得分:4)

Haskell没有与OO语言相同的子类型。通常,如果需要这种子类型多态,则使用具有更高阶函数的数据类型作为字段。在这种情况下,它看起来并不是必需的。

以下是我将如何处理它:

data RobotType = TRobot | FRobot
data Robot = Robot {
    robotType :: RobotType
   ,position  :: Char
   ,weight    :: Int
}

答案 3 :(得分:2)

正如其他人所说的那样,从命令式OO语言中继承子类并不能直接转换为Haskell。定义特定示例的一种特殊方法是:

data Robot = Robot {
    position   :: Char,
    weight     :: Int
    makeAction :: -- Your function signature
}

makeTRobot :: Char -> Int -> Robot
makeTRobot p w = Robot { position = p,
                         weight = w,
                         makeAction = -- TRobot's action function }

答案 4 :(得分:1)

您正在尝试subtype polymorphism,这是在OO语言中执行此类操作的主要方式,但Haskell不支持此操作。

相反,Haskell使用typeclass polymorphism完成了大致相同的事情。如果您以前从未听说过此消息,我建议您阅读thisthis

由于我实际上想回答你的问题,你得到你正在寻找的行为的方式是这样的:

  1. 创建一个类似于抽象类的类型类,该抽象类定义类型必须实现的最小行为才能包含在此类型类中:

    class Robot r where
        position :: r -> Char
        weight :: r -> Int
        makeAction :: -- ?? You didn't say.
    
  2. 然后让每个类型成为该类型类的实例:

    data FRobot = FRobot { frPosition :: Char, frWeight :: Int }
    
    instance Robot FRobot where
        position = frPosition
        weight = frWeight
        makeAction = -- Whatever you wanted.
    
  3. 然后为你的其他类型做同样的事情。完成此操作后,您可以在类型签名中使用Robot r => r -> ...,并且可以使用任何类型的Robot。如果您不想实现某种方法,可以将其定义为errorundefined,但要注意这是不安全和不良行为。

    编辑:如果你想让makeAction为不同的机器人拥有不同的类型......你可能会被简化为重复,因为没有办法轻易地将其放入类型系统中。如果您向我们提供更多信息,我可能会提出更具体的建议。