如何在Haskell中模拟对象身份的概念

0 投票
2 回答
645 浏览
提问于 2025-04-15 16:22

我正在考虑用Haskell设计一个类似Python的面向对象语言的解释器。现在我遇到的一个问题是关于对象身份的概念。如果我们看看Python的id(object)函数,它的定义是返回一个对象的“身份”。这个身份是一个整数(或者长整数),在对象的生命周期内是唯一且不变的。也就是说,两个生命周期不重叠的对象可能会有相同的id()值。(实现说明:这个身份实际上是对象的地址。)

那么,在Haskell中实现这样的概念一般应该怎么做呢?

2 个回答

3

这个问题的答案取决于你打算如何实现那些你想要获取ID的对象。如果两个变量包含相同的对象,那它们看起来会是什么样子呢?你基本上需要在变量中存储对“可变”对象的引用,关键在于你到底是怎么做到这一点的。如果你只是把简单的值直接赋给变量名,那么一个变量的变化就不会在另一个变量中反映出来,这样就没有对象的身份了。

所以,变量需要保存对对象当前值的引用。可以这样理解:

data VariableContent = Int | String | ObjRef Int | ...
data ObjStore = ObjStore [(Int, Object)]
data ProgramState = ProgramState ObjStore VariableStore ...

在这里,每个 ObjRef 都指向 ObjStore 中的一个值,这个值可以通过存储在 ObjRef 中的 Int ID 来访问。而这个 Int 就是 id(object) 函数应该返回的内容。

总的来说,id 函数是非常依赖于你如何实际实现对象引用的。

4

我假设你的解释器会在一个叫做 State 的状态管理中运行。这个状态可能包含一些活跃的对象和其他相关信息。你可以做的是,跟踪一个可用的(未使用的)id 列表(用 Int 表示),并给每个 Object 加上一个 Int,也就是它的 id。这个 id 是从可用的 id 列表中取出来的,并在创建时分配给它。因此,不会有两个 Object 实例拥有相同的 id

注意我提到的是 Int。你可以选择 Integer,但这样可能效率会降低。使用 Int 的话,你需要在对象被销毁时,把它的 id 重新放回可用的 id 列表中(否则你最终会用完可用的 id)。所以我想象的情况是这样的:

data Object a = Obj Int a

instance Eq (Object a) where
  Obj i _ == Obj j _ = i == j

type InterpreterState a = State [Int] a

createObject :: a -> InterpreterState (Object a)
createObject a = do
  (i:is) <- get 
  put is
  return $ Obj i a 

destroyObject :: Object a -> InterpreterState ()
destroyObject (Obj i a) = do
  modify (i:)

(注意,InterpreterState 在你的情况下会复杂得多,而 createObjectdestroyObject 应该会把对象添加到或从状态中移除。但这不是重点。)

撰写回答