获取 Haskell 来区分类型同义词
Getting Haskell to Distinguish Type Synonyms
我喜欢 Haskell 类型同义词的想法,因为它们允许区分共享底层表示的抽象数据类型。不幸的是,当我写一个像
这样的程序时
data Vector a = Vec a a
-- Some definitions here about (+) and (*) for Vector ...
type Position = Vector Float
type Velocity = Vector Float
type Time = Float
step :: Position -> Velocity -> Time -> Position
step p v dt = p + v*dt
p :: Position
p = Vec 0.0 0.0
v :: Velocity
v = Vec 1.0 1.0
p' = step v p 0.01
这是完全有效的 Haskell 代码,尽管 v
和 p
在错误的位置。我想加强类型同义词之间的区别,这样它们仍然共享底层表示,但在函数应用中不被接受为彼此。这可能吗?
newtype
可能是您想要的,或者至少是我们拥有的最好的。与 type
一样,它为现有类型定义了一个新名称,并且运行时表示将是相同的。不像type
(但像data
),它们在类型检查时被认为是不同的,并且有一个新的数据构造函数。
所以你可能有这样的代码:
newtype Position = Position (Vector Float)
p :: Position
p = Position (Vec 0 0)
您可以将 Vector
设为 phantom type,如下所示:
data Vector t a = Vec a a
data Pos
data Vel
type Position = Vector Pos Float
type Velocity = Vector Vel Float
现在,您可以像往常一样定义 Position
和 Velocity
的实例:
p :: Position
p = Vec 0.0 0.0
v :: Velocity
v = Vec 1.0 1.0
但是,它不允许您互换使用它们:
type Time = Float
step :: Position -> Velocity -> Time -> Position
step p v dt = p + v*dt -- you might have to change this definition
p' = step v p 0.01 -- won't compile
您还可以使用 DataKinds
和 KindSignatures
:
使事情更精确
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
data VectorType = Pos | Vel
data Vector (t :: VectorType) a = Vec a a
type Position = Vector Pos Float
type Velocity = Vector Vel Float
希望对您有所帮助。
我喜欢 Haskell 类型同义词的想法,因为它们允许区分共享底层表示的抽象数据类型。不幸的是,当我写一个像
这样的程序时data Vector a = Vec a a
-- Some definitions here about (+) and (*) for Vector ...
type Position = Vector Float
type Velocity = Vector Float
type Time = Float
step :: Position -> Velocity -> Time -> Position
step p v dt = p + v*dt
p :: Position
p = Vec 0.0 0.0
v :: Velocity
v = Vec 1.0 1.0
p' = step v p 0.01
这是完全有效的 Haskell 代码,尽管 v
和 p
在错误的位置。我想加强类型同义词之间的区别,这样它们仍然共享底层表示,但在函数应用中不被接受为彼此。这可能吗?
newtype
可能是您想要的,或者至少是我们拥有的最好的。与 type
一样,它为现有类型定义了一个新名称,并且运行时表示将是相同的。不像type
(但像data
),它们在类型检查时被认为是不同的,并且有一个新的数据构造函数。
所以你可能有这样的代码:
newtype Position = Position (Vector Float)
p :: Position
p = Position (Vec 0 0)
您可以将 Vector
设为 phantom type,如下所示:
data Vector t a = Vec a a
data Pos
data Vel
type Position = Vector Pos Float
type Velocity = Vector Vel Float
现在,您可以像往常一样定义 Position
和 Velocity
的实例:
p :: Position
p = Vec 0.0 0.0
v :: Velocity
v = Vec 1.0 1.0
但是,它不允许您互换使用它们:
type Time = Float
step :: Position -> Velocity -> Time -> Position
step p v dt = p + v*dt -- you might have to change this definition
p' = step v p 0.01 -- won't compile
您还可以使用 DataKinds
和 KindSignatures
:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
data VectorType = Pos | Vel
data Vector (t :: VectorType) a = Vec a a
type Position = Vector Pos Float
type Velocity = Vector Vel Float
希望对您有所帮助。