ħ!
假设我有一个抽象类Robot,其中包含一些像'position'和'weight'这样的attributs。这个抽象类实现了三个方法:'take','drop'和'move',但也有一个抽象方法'makeAction'。然后我有两个名为'TRobot'和'FRobot'的子机器人。基本上,TRobot和FRobot将实现'makeAction'方法,但不会重新实现'take','drop'和'move'。
我的问题是你如何在Haskell中做到这一点。
我从数据类型开始:
data Robot = Robot {position :: Char, weight :: Int}
编辑:
但是如果机器人是TRobot或FRobot,我希望函数'take','move'和'drop'(take :: Box - > Robot - > Robot)表现相同。
但是,功能
makeAction :: Robot -> Action
无论Robot是TRobot还是FRobot,应该有不同的实现。
感谢您的帮助。
答案 0 :(得分:15)
我有<在这里插入面向对象的设计>。如何在非OO语言(如Haskell)中实现它?
呃...这不是一个好主意。退一步并解释你实际上想要实现的可能会好得多。 Haskell需要一种完全不同的思考软件设计的方式。在不知道你真正想做什么的情况下,很难确切地知道实现它的最佳方式是什么。特别是:两种机器人实际上有何不同?它们如何相似?
可能您只想构建单个数据类型的构造函数(正如您所编写的),move
函数对每个函数的行为都不同,take
/ drop
函数那不在乎。或者您可能只需要一个构造函数,并且该字段指出它是哪种机器人类型。或者您可能真的想要两个完全独立的类型。如果不了解你想做什么,就很难说。
答案 1 :(得分:7)
在Haskell中有一些很多方法可以做到这一点,但你必须首先理解传统的“类”并不直接对应于任何Haskell结构。
你可以很容易地做到这样的事情:
data Robot = Robot {
position :: Char,
weight :: Int,
makeAction :: Robot -> String
}
此处,makeAction
是包含TRobot
和FRobot
类型的不同功能的字段。有很多更复杂的方法可以做到这一点,比如类型类,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 TRobot
和Robot 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完成了大致相同的事情。如果您以前从未听说过此消息,我建议您阅读this或this。
由于我实际上想回答你的问题,你得到你正在寻找的行为的方式是这样的:
创建一个类似于抽象类的类型类,该抽象类定义类型必须实现的最小行为才能包含在此类型类中:
class Robot r where
position :: r -> Char
weight :: r -> Int
makeAction :: -- ?? You didn't say.
然后让每个类型成为该类型类的实例:
data FRobot = FRobot { frPosition :: Char, frWeight :: Int }
instance Robot FRobot where
position = frPosition
weight = frWeight
makeAction = -- Whatever you wanted.
然后为你的其他类型做同样的事情。完成此操作后,您可以在类型签名中使用Robot r => r -> ...
,并且可以使用任何类型的Robot。如果您不想实现某种方法,可以将其定义为error
或undefined
,但要注意这是不安全和不良行为。
编辑:如果你想让makeAction为不同的机器人拥有不同的类型......你可能会被简化为重复,因为没有办法轻易地将其放入类型系统中。如果您向我们提供更多信息,我可能会提出更具体的建议。