在Haskell中实现这个OO概念

sta*_*ser 4 haskell

我需要帮助将OO概念转换为Haskell.

想象一Vehicle类和CarTruck亚类,具有driveOneMile一个返回双表示使用的总燃料的方法.每次调用driveOneMile也会改变车辆的内部状态.

这是我到目前为止在Haskell中所做的事情(因为在Haskell中没有实例变量,似乎我必须创建自己的"状态"类型):

type CarState = (Double,Double)
initialCarState = (0,0)

driveCarOneMile :: CarState -> (Double,CarState) --Double: total fuel used
driveCarOneMile s = ...


--the internal state of trucks is more complex. needs three Doubles
type TruckState = (Double,Double,Double)
initialTruckState = (0,0,0)

driveTruckOneMile :: TruckState -> (Double,TruckState)
driveTruckOneMile s = ...
Run Code Online (Sandbox Code Playgroud)

以类似的方式,我可以构建其他车辆及其"驱动"功能.

这就是我开车两次的方式:

fuelFor2Miles = fst $ driveCarOneMile $ snd $ driveCarOneMile initialCarState
Run Code Online (Sandbox Code Playgroud)
  1. 我这样做了吗?
  2. 如果没有,你会如何纠正它?
  3. 我如何使用上述(或您的纠正方式)收集许多汽车,卡车和其他车辆的集合,每次驾驶10次,并获得相应的[双]燃料总量列表?(在OO中,这将是一个简单的问题,即将车辆扔进一个列表,在每个车辆上调用方法10次,并将使用的总燃料放入新的列表中.)

dup*_*ode 8

Haskell中的类与OO类完全不同,并且使用它们就像在大多数情况下编写OO代码一样,使事情变得比它们应该更复杂.特别是,一旦你开始考虑以"OO"的形式"收集许多汽车,卡车和其他车辆的集合",你就可以直接沿着兔子洞(正如Haskell Antipattern:Existential Typeclass所指出的那样).

您可能根本不需要一个班级来模拟您的不同类型的车辆.你可以定义

data Vehicle = Car CarState | Truck TruckState
Run Code Online (Sandbox Code Playgroud)

然后

driveOneMile :: Vehicle -> (Double, Vehicle)
Run Code Online (Sandbox Code Playgroud)

使用模式匹配来区分不同的车辆.

即使你真的需要更像类的东西(例如你正在编写一个库并希望用户提供自己的车辆),这并不一定意味着你需要异构集合.您可以给出Vehicle一个构造函数并向其中添加与类方法相对应的字段,以便该类成为一个类型,并且类实例成为值(这是反模式文章所倡导的方法).您可能还有一个Vehicle带有toGeneralVehicle :: a -> GeneralVehicle方法的类,并且具有根据GeneralVehicle类型定义的通用行为.

PS:签名背后的想法TruckState -> (Double,TruckState)是声音.事实上,我会说你不小心发现了这种State类型!State只是一个方便的抽象,使状态传递管道隐含.如果您很好奇,请查找有关Statemonad的问题和教程.