簡體   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