[英]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: 这个结构的属性是:
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.
本文档描述了必须在堆上分配对象的一些情况,因此我假设在这些情况下,从对象访问底层值会有一些运行时开销。
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等同于
newtype
和data
之间没有语义差异。 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
例如
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.