【发布时间】:2010-03-02 13:11:03
【问题描述】:
我正在尝试重新学习系统分析。我有很多面向对象的思想,但我无法在 Haskell 中找到等价物。
一个虚构的系统由救护站、救护车和船员组成。 (它已经变成对象了。)所有这些状态都可以封装在一个大的 SystemState 类型中。 SystemState [车站] [救护车] [船员]。然后我可以创建接受 SystemState 并返回新 SystemState 的函数。
module AmbSys
( version
, SystemState
, Station
, Ambulance
, Crew
) where
version = "0.0.1"
data SystemState = SystemState [Station] [Ambulance] [Crew] deriving (Show)
data Station = Station { stName :: String
, stAmbulances :: [Ambulance]
} deriving (Show)
data Ambulance = Ambulance { amCallSign :: String
, amStation :: Station
, amCrew :: [Crew]
} deriving (Show)
data Crew = Crew { crName :: String
, crAmbulance :: Ambulance
, crOnDuty :: Bool
} deriving (Show)
这是我创建一些数据的 ghci 会话。
*AmbSys> :load AmbSys
[1 of 1] Compiling AmbSys ( AmbSys.hs, interpreted )
Ok, modules loaded: AmbSys.
*AmbSys> let s = Station "London" []
*AmbSys> let a = Ambulance "ABC" s []
*AmbSys> let s' = Station "London" [a]
*AmbSys> let c = Crew "John Smith" a False
*AmbSys> let a' = Ambulance "ABC" s [c]
*AmbSys> let s'' = Station "London" [a']
*AmbSys> let system_state = SystemState [s''] [a'] [c]
*AmbSys> system_state
SystemState [Station {stName = "London", stAmbulances = [Ambulance {amCallSign = "ABC",
amStation = Station {stName = "London", stAmbulances = []}, amCrew = [Crew
{crName = "John Smith", crAmbulance = Ambulance {amCallSign = "ABC",
amStation = Station {stName = "London", stAmbulances = []}, amCrew = []},
crOnDuty = False}]}]}] [Ambulance {amCallSign = "ABC", amStation = Station {
stName = "London", stAmbulances = []}, amCrew = [Crew {crName = "John Smith",
crAmbulance = Ambulance {amCallSign = "ABC", amStation = Station {stName = "London",
stAmbulances = []}, amCrew = []}, crOnDuty = False}]}] [Crew {crName = "John Smith",
crAmbulance = Ambulance {amCallSign = "ABC", amStation = Station {stName = "London",
stAmbulances = []}, amCrew = []}, crOnDuty = False}]
您已经可以在这里看到几个问题:
- 我无法创建一致的 SystemState - 一些值是“旧”值,例如 s 或 s',而不是 s''。
- 许多对“相同”数据的引用都有单独的副本。
我现在可以创建一个函数,它接受一个 SystemState 和一个船员姓名,它返回一个新的 SystemState,其中船员是“下班”。
我的问题是我必须找到并更改救护车中的机组人员以及 SystemState 中的机组人员(相同的副本)。
这对于小型系统是可能的,但实际系统有更多的链接。它看起来像一个 n 平方问题。
我非常清楚我正在以面向对象的方式考虑系统。
如何在 Haskell 中正确创建这样的系统?
编辑:感谢大家的回答,也感谢 reddit 上的各位 http://www.reddit.com/r/haskell/comments/b87sc/how_do_you_manage_an_object_graph_in_haskell/
我现在的理解似乎是我可以在 Haskell 中做我想做的事情。不利的一面是,对象/记录/结构图似乎不是 Haskell 中的“第一类”对象(就像它们在 C/Java/等中一样),因为缺少必要的引用。这只是一个权衡 - Haskell 中的一些任务在语法上更简单,而 C 中的一些任务更简单(并且更不安全)。
【问题讨论】: