让Haskell区分类型同义词

让Haskell区分类型同义词,haskell,types,type-alias,type-synonyms,Haskell,Types,Type Alias,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 ->

我喜欢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

尽管
v
p
处于错误位置,但这是完全有效的Haskell代码。我想加强类型同义词之间的区别,这样它们仍然共享底层表示,但在函数应用程序中彼此不被接受。这可能吗?

newtype
可能是您想要的,或者至少是我们最好的。与
type
类似,它为现有类型定义了一个新名称,并且运行时表示形式将是相同的。与
类型
(但与
数据
)不同,它们在类型检查期间被认为是不同的,并且有一个新的数据构造函数

因此,您可能有如下代码:

newtype Position = Position (Vector Float)
p :: Position
p = Position (Vec 0 0)

您可以按如下方式制作
Vector
a:

data Vector t a=Vec a
数据位置
数据层
类型位置=矢量位置浮动
类型速度=矢量水平浮动
现在,您可以像通常一样定义
位置
速度
的实例:

p::位置
p=Vec 0.0.0
速度
v=Vec 1.0 1.0
但是,它不允许您互换使用它们:

type Time=Float
步骤:位置->速度->时间->位置
步骤p v dt=p+v*dt——您可能必须更改此定义
p'=步骤v p 0.01--不会编译
您还可以通过使用
数据种类
KindSignatures
使事情更加精确:

{-#语言数据类型}
{-#语言签名{-}
数据向量类型=位置|级别
数据向量(t::VectorType)a=Vec a
类型位置=矢量位置浮动
类型速度=矢量水平浮动

希望对您有所帮助。

您应该使用
newtype
而不是
type
@Shersh来回答问题,请使用“发布您的答案”按钮,评论是为了要求澄清或建议对问题的改进。@Shersh这不是借口。挑战的一部分是写合适的评论,让大家投票。@amalloy,有时候你可以在几秒钟内写一条评论(比如Shersh的评论),帮助OP解决问题。但在那个时候,人们可能无法写出正确的答案。如果将上述评论作为一个答案,可能不会受到欢迎。@dfeur是的,我知道这是一个想法,但我不认为这是值得鼓励的。一些很容易用七个字的评论来回答的问题也会很快得到真正的答案——在这种情况下,在评论“答案”后两分钟就得到了彻底的答案。我宁愿我们得到一个真正的答案,而这样的评论的出现阻碍了回答,因为“OP已经被帮助了”。我认为现在更常见的是,一个类型的构造函数有一个或多个幻像参数,而不是说它是一个幻像类型。我相信我看到了一个类似的C++解决方案。不幸的是,它不像我希望的那样优雅(特别是因为它不能应用于在导入库中定义的数据类型),但仍然有用。