简体   繁体   English

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

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

The Haskell programming language has a concept of newtypes : If I write newtype Foo = Foo (Bar) , then a new type Foo is created that is isomorphic to Bar , ie there are bijective conversions between the two. Haskell编程语言有一个newtypes的概念:如果我写newtype Foo = Foo (Bar) ,那么创建一个与Bar同构的新类型Foo ,即两者之间存在双射转换。 Properties of this construct are: 这个结构的属性是:

  • The two types are completely separate (ie the compiler will not allow you to use one where the other is expected, without using the explicit conversions). 这两种类型是完全独立的(即编译器不允许您使用另一种类型,而不使用显式转换)。
  • They share the same representation. 他们有相同的代表性。 In particular, the conversion functions have a run-time cost of zero and return ”the same object” on the heap. 特别是,转换函数的运行时成本为零,并在堆上返回“相同的对象”。
  • Conversion is only possible between such types and cannot be mis-used, ie type safety is preserved. 转换只能在这些类型之间进行,并且不能被误用,即保留类型安全性。

What other programming languages provide this feature? 还有哪些编程语言提供此功能?

One example seems to be single-value-structs in C when used with record accessors/constructors only. 当与记录访问器/构造器一起使用时,一个示例似乎是C中的单值结构。 Invalid candidates would be single-valued-structs in C when used with casts, as the casts are not checked by the compiler, or objects with a single member in Java, as these would not share the same representation. 当与强制转换一起使用时,无效候选者将是C中的单值结构,因为编译器不会检查强制转换,或者Java中具有单个成员的对象,因为它们不会共享相同的表示。

Related questions: Does F# have 'newtype' of Haskell? 相关问题: F#是否具有Haskell的“新类型”? (No) and Does D have 'newtype'? (不) D是否有'newtype'? (not any more). (不再)。

Frege has this, though, unlike in Haskell there is no extra keyword. 不过, Frege有这个,不像Haskell那样没有额外的关键字。 Instead, every product type with just one component is a newtype. 相反,只有一个组件的每种产品类型都是新类型。

Example: 例:

data Age = Age Int

Also, all langugaes that have nominal typing and allow to define a type in terms of another should have this feature. 此外,所有具有标称类型且允许根据另一个定义类型的languga都应该具有此功能。 For example Oberon, Modula-2 or ADA. 例如Oberon,Modula-2或ADA。 So after 所以之后

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

one couldn't confuse an age and some other quantity. 一个人不能混淆年龄和其他数量。

I believe Scala's value classes satisfy these conditions. 我相信Scala的价值等级满足这些条件。

For example: 例如:

case class Kelvin(k: Double) extends AnyVal

Edit: actually, I'm not sure that conversions have zero overhead in all cases. 编辑:实际上,我不确定转换在所有情况下都是零开销。 This documentation describes some cases where allocation of objects on the heap is necessary, so I assume in those cases there would be some runtime overhead in accessing the underlying value from the object. 文档描述了必须在堆上分配对象的一些情况,因此我假设在这些情况下,从对象访问底层值会有一些运行时开销。

Go has this: 去吧

If we declare 如果我们宣布

 type MyInt int var i int var j MyInt 

then i has type int and j has type MyInt. 然后我有类型int和j类型MyInt。 The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion. 变量i和j具有不同的静态类型,虽然它们具有相同的基础类型,但如果没有转换,它们就不能相互分配。

"The same underlying type" means that the representation in memory of a MyInt is exactly that of an int . “相同的底层类型”意味着MyInt内存中的表示正是int Passing a MyInt to a function expecting an int is a compile-time error. MyInt传递给期望int的函数是编译时错误。 The same is true for composite types, eg after 复合类型也是如此,例如之后

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

you can't pass a bar to a function expecting a foo ( test ). 你不能将一个bar传递给一个期望foo测试 )的函数。

Mercury is a pure logic programming language, with a type system similar to Haskell's. Mercury是一种纯逻辑编程语言,类型系统类似于Haskell。

Evaluation in Mercury is strict rather than lazy, so there would be no semantic difference between Mercury's equivalents of newtype and data . Mercury中的评估是严格的而不是懒惰的,因此Mercury等同于newtypedata之间没有语义差异。 Consequently any type which happens to have only one constructor with only one argument is represented identically to the type of that argument, but still treated as the same type; 因此,恰好只有一个构造函数只有一个参数的任何类型都与该参数的类型相同,但仍被视为相同的类型; effectively "newtype" is a transparent optimisation in Mercury. 有效的“newtype”是Mercury中的透明优化。 Example: 例:

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

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

:- type synonym == wrapped.

The representation of wrapper will be identical to that of wrapped but is a distinct type, as opposed to synonym which is simply another name for the type wrapped . 的表示wrapper将等同于的wrapped ,但是一种独特的类型,而不是synonym这简直是该类型的另一个名称wrapped

Mercury uses tagged pointers in its representations. Mercury在其表示中使用带标记的指针。 1 Being strict and being allowed to have different representations for different types, Mercury generally tries to do away with boxing where possible. 1严格并且被允许对不同类型有不同的表示,水星通常会尽可能地消除拳击。 eg 例如

  • To refer to a value of an "enum-like" type (all nullary constructors) you don't need to point to any memory so you can use a whole word's worth of tag bits to say which constructor it is and inline that in the reference 要引用“enum-like”类型的值(所有nullary构造函数),您不需要指向任何内存,因此您可以使用整个单词的标记位来说明它是哪个构造函数并在参考
  • To reference a list you can use a tagged pointer to a cons cell (rather than a pointer to a structure which itself contains the information about whether it is nill or a cons cell) 要引用列表,您可以使用指向cons单元格的标记指针(而不是指向结构的指针,该结构本身包含有关是否为nill或cons单元格的信息)
  • etc 等等

The "newtype" optimization is really just one particular application of that general idea. “newtype”优化实际上只是该一般概念的一个特定应用。 The "wrapper" type doesn't need any memory cells allocated above what is already holding the "wrapped" type. “包装器”类型不需要在已经保持“包装”类型的上方分配任何存储器单元。 And since it needs zero tag bits, it can also fit any tags in the reference to the "wrapped" type. 由于它需要零标签位,因此它也可以适应“包装”类型的引用中的任何标签。 Therefore the whole reference to the "wrapped" type can be inlined into the reference to the wrapper type, which ends up being indistinguishable at runtime. 因此,对“包装”类型的整个引用可以内联到对包装器类型的引用中,这最终在运行时无法区分。


1 The details here may only apply to the low level C compilation grades. 1此处的详细信息可能仅适用于低级别C编译等级。 Mercury can also compile to "high level" C or to Java. Mercury也可以编译为“高级”C或Java。 There's obviously no bit fiddling going on in Java (though as far as I know the "newtype" optimization still applies), and I'm just less familiar with the implementation details in the high level C grades. 在Java中显然没有任何小问题(尽管我知道“newtype”优化仍然适用),而我对高级C级别的实现细节不太熟悉。

Rust has always allowed you to make single-field types, but with the recently stabilized repr(transparent) attribute you can now be confident that the type created will have the exact data layout as the wrapped type, even across FFI and such. Rust总是允许你创建单字段类型,但是使用最近稳定的repr(transparent)属性,您现在可以确信创建的类型将具有精确的数据布局作为包装类型,甚至可以跨FFI等。

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

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

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