20

Haskell では、コンパイラがエイリアスされた型とエイリアスされていない型の間の参照を許可しないような方法で型をエイリアスすることが可能であると私は信じています。このスタック オーバーフローの質問によれば、Haskell のnewtypeように使用できます。

newtype Feet = Feet Double
newtype Cm   = Cm   Double

whereFeetとは Double 値のように動作しますが、値と値Cmを乗算しようとすると、コンパイラ エラーが発生します。FeetCm

編集: ベンはコメントで、Haskell での上記の定義では不十分であると指摘しました。関数が定義されていない新しい型になりますFeetCmもう少し調査を行ったところ、次のことが機能することがわかりました。

newtype Feet = Feet Double deriving (Num)
newtype Cm   = Cm   Double deriving (Num)

これにより、既存の型から派生した新しい型が作成されますNum( switch: を使用する必要があります-XGeneralizedNewtypeDeriving)。もちろん、これらの新しい型はShowEq、 などの他の型から派生することでさらに価値が高くなりますが、これは を正しく評価するために必要な最小限のものですCm 7 * Cm 9

Haskell と Scala の両方typeに があります。これは単に既存の型に別名を付け、Scala で次の例のような無意味なコードを許可します。

type Feet = Double
type Cm = Double

val widthInFeet: Feet = 1.0
val widthInCm: Cm = 30.48

val nonsense = widthInFeet * widthInCm

def getWidthInFeet: Feet = widthInCm

newtypeこれが私が思っていることをすると仮定すると、Scalaには同等のものがありますか?

4

4 に答える 4

14

別のオプションは、値クラスを使用することです。これらは、コンパイル時に生の型への直接アクセスに変換される基になる型の周りにラッパーを作成し、クラスのメソッドは関連するコンパニオン オブジェクトの静的呼び出しに変換されます。例えば:

class CM(val quant : Double) extends AnyVal {
  def +(b : CM) = new CM(quant + b.quant)
  def *(b : Int) = new CM(quant * b)
}
于 2012-11-15T10:23:10.327 に答える
9

ええ、scala で Unboxed Tagged Types として知られるものを使用しています。

Tagged は次のように定義されます。

type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]

これにより、このようなことができます

sealed trait Feet

def Feet[A](a: A): A @@ Feet = Tag[A, Feet](a)
Feet: [A](a: A)scalaz.@@[A,Feet]

scala> val mass = Feet(20.0)
mass: scalaz.@@[Double,Feet] = 20.0

scala> 2 * mass
res2: Double = 40.0

CMも追加

sealed trait CM

def CM[A](a: A): A @@ CM = Tag[A, CM](a)
CM: [A](a: A)scalaz.@@[A,CM]

scala> val mass = CM(20.0)
mass: scalaz.@@[Double,CM] = 20.0

乗算をフィートのみに制限したい場合は、型クラス型の乗算関数を書くことができます

trait Multiply[T] { self =>
   def multiply(a: T, b: T): T
}
implicit val footInstance = new Multiply[Feet] {
   def multiply(a: Feet, b: Feet): Feet = Feet(a * b)
}
implicit val cmInstance = new Multiply[CM] {
  def multiply(a: CM, b: CM): CM = CM(a * b)
}

def multiply[T: Multiply](a: T, b: T): T = {
  val multi = implicitly[Multiply[T]]
  multi.multiply(a,b)
} 

その後、次のことができます

multiply(Feet(5), Feet(10)) // would return Feet(50)

これはScalaができる最善のことです

ボックス型の詳細については、 http: //eed3si9n.com/learning-scalaz-day3 をご覧 ください。

于 2012-11-15T01:30:31.517 に答える
0

為に

val widthInCm: Cm = 30.48

def getWidthInFeet: Feet = widthInCm

、単純に次のように定義FeetCmます。

type Feet <: Double
type Cm <: Double

にアップキャストしない限り、仕事をしますDouble。自分で見てください:

def getWidthInFeet: Feet = widthInCm

Error:(1, 28) type mismatch;
 found   : widthInCm.type (with underlying type Cm)
 required: Feet
    def getWidthInFeet: Feet = widthInCm

副作用は、インスタンスを取得するためにDouble値をCmまたはFeet明示的にダウンキャストする必要があることです。

val widthInCm: Cm = 30.48.asInstanceOf[Cm]

また、型情報を失うことなく操作を行うことはできませんDouble(したがって、常にダウンキャストする必要があります)。

于 2019-10-17T15:26:18.070 に答える