繁体   English   中英

什么编程语言有类似Haskell的`newtype`

[英]What programming languages have something like Haskell’s `newtype`

Haskell编程语言有一个newtypes的概念:如果我写newtype Foo = Foo (Bar) ,那么创建一个与Bar同构的新类型Foo ,即两者之间存在双射转换。 这个结构的属性是:

  • 这两种类型是完全独立的(即编译器不允许您使用另一种类型,而不使用显式转换)。
  • 他们有相同的代表性。 特别是,转换函数的运行时成本为零,并在堆上返回“相同的对象”。
  • 转换只能在这些类型之间进行,并且不能被误用,即保留类型安全性。

还有哪些编程语言提供此功能?

当与记录访问器/构造器一起使用时,一个示例似乎是C中的单值结构。 当与强制转换一起使用时,无效候选者将是C中的单值结构,因为编译器不会检查强制转换,或者Java中具有单个成员的对象,因为它们不会共享相同的表示。

相关问题: F#是否具有Haskell的“新类型”? (不) D是否有'newtype'? (不再)。

不过, Frege有这个,不像Haskell那样没有额外的关键字。 相反,只有一个组件的每种产品类型都是新类型。

例:

data Age = Age Int

此外,所有具有标称类型且允许根据另一个定义类型的languga都应该具有此功能。 例如Oberon,Modula-2或ADA。 所以之后

type age = integer;      {* kindly forgive syntax errors *}

一个人不能混淆年龄和其他数量。

我相信Scala的价值等级满足这些条件。

例如:

case class Kelvin(k: Double) extends AnyVal

编辑:实际上,我不确定转换在所有情况下都是零开销。 文档描述了必须在堆上分配对象的一些情况,因此我假设在这些情况下,从对象访问底层值会有一些运行时开销。

去吧

如果我们宣布

 type MyInt int var i int var j MyInt 

然后我有类型int和j类型MyInt。 变量i和j具有不同的静态类型,虽然它们具有相同的基础类型,但如果没有转换,它们就不能相互分配。

“相同的底层类型”意味着MyInt内存中的表示正是int MyInt传递给期望int的函数是编译时错误。 复合类型也是如此,例如之后

type foo struct { x int }
type bar struct { x int }

你不能将一个bar传递给一个期望foo测试 )的函数。

Mercury是一种纯逻辑编程语言,类型系统类似于Haskell。

Mercury中的评估是严格的而不是懒惰的,因此Mercury等同于newtypedata之间没有语义差异。 因此,恰好只有一个构造函数只有一个参数的任何类型都与该参数的类型相同,但仍被视为相同的类型; 有效的“newtype”是Mercury中的透明优化。 例:

:- type wrapped
    --->    foo(int)
    ;       bar(string).

:- type wrapper ---> wrapper(wrapped).

:- type synonym == wrapped.

的表示wrapper将等同于的wrapped ,但是一种独特的类型,而不是synonym这简直是该类型的另一个名称wrapped

Mercury在其表示中使用带标记的指针。 1严格并且被允许对不同类型有不同的表示,水星通常会尽可能地消除拳击。 例如

  • 要引用“enum-like”类型的值(所有nullary构造函数),您不需要指向任何内存,因此您可以使用整个单词的标记位来说明它是哪个构造函数并在参考
  • 要引用列表,您可以使用指向cons单元格的标记指针(而不是指向结构的指针,该结构本身包含有关是否为nill或cons单元格的信息)
  • 等等

“newtype”优化实际上只是该一般概念的一个特定应用。 “包装器”类型不需要在已经保持“包装”类型的上方分配任何存储器单元。 由于它需要零标签位,因此它也可以适应“包装”类型的引用中的任何标签。 因此,对“包装”类型的整个引用可以内联到对包装器类型的引用中,这最终在运行时无法区分。


1此处的详细信息可能仅适用于低级别C编译等级。 Mercury也可以编译为“高级”C或Java。 在Java中显然没有任何小问题(尽管我知道“newtype”优化仍然适用),而我对高级C级别的实现细节不太熟悉。

Rust总是允许你创建单字段类型,但是使用最近稳定的repr(transparent)属性,您现在可以确信创建的类型将具有精确的数据布局作为包装类型,甚至可以跨FFI等。

#[repr(transparent)]
pub struct FooWrapper(Foo);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM