2016-04-08 7 views
3

私は最近スカラーのタグなしタイプの箱なしについて聞いたことがあります。私はそれがどのように機能するかを知ろうとしていましたが、scalazの実装に問題があったことを指摘していますquestionです。だから今、私は思ったんだけど箱なしのタグ付きのタイプは安全ですか?

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

trait Kilogram 
trait Meter 
type Kg = Double @@ Kilogram 
type M = Double @@ Meter 

def bmi(mass: Kg, height: M): Double = mass/pow(height, 2) 

:その後、私は私のような何かができるオリジナルのアイデアを、と考え

def bmi(mass: Double @@ Kg, height: Double @@ M): Double = 
    Tag.unwrap(mass)/pow(Tag.unwrap(height), 2) 

:修正の結果の一つは、明示的なアンラップにタグ付けされたタイプを持っていました以前のscalazで見つかった問題がそのアプローチに固有であるのか、単純な実装でも消去、配列またはvarargsに問題がある可能性があります。私はまだスカラを学んでいるので、私の理解はタイプシステムであり、私自身はそれを理解できませんでした。

答えて

0

型安全性の観点からは安全ではありません。 T @@ UTのサブタイプであり、Tのインスタンスが偶発的であっても必要な場合はT @@ Uのインスタンスを使用することができます。以下を考慮してください

type Tagged[U] = { type Tag = U } 
type @@[T, U] = T with Tagged[U] 
object Tag { 
    def apply[@specialized A, T](a: A): A @@ T = a.asInstanceOf[A @@ T] 
} 

trait Compare[A] { def compare(a1: A, a2: A): Int } 

def useCompare[A: Compare](l: List[A]): Option[A] = 
    l.foldLeft(Option.empty[A])((xs, x) => 
    xs.fold(Some(x))(xxs => 
     if (implicitly[Compare[A]].compare(xxs, x) <= 0) Some(xxs) 
     else Some(x))) 

implicit def intCompare: Compare[Int] = new Compare[Int] { 
    def compare(a1: Int, a2: Int): Int = 
    a1.compareTo(a2) 
} 

trait Max 
implicit def intCompareMax: Compare[Int @@ Max] = new Compare[Int @@ Max] { 
    def compare(a1: Int @@ Max, a2: Int @@ Max): Int = 
    a1.compareTo(a2) * -1 
} 

scala> val listInts: List[Int] = List(1, 2, 3, 4) 
listInts: List[Int] = List(1, 2, 3, 4) 

scala> val min = useCompare(listInts) 
min: Option[Int] = Some(1) 

scala> val listIntMaxs: List[Int @@ Max] = listInts.map(Tag[Int, Max]) 
listIntMaxs: List[@@[Int,Max]] = List(1, 2, 3, 4) 

scala> val max = useCompare(listIntMaxs) 
max: Option[@@[Int,Max]] = Some(4) 

OK、すべてがクールです、そうですか?このため、T @@ Uが存在します。私たちは新しい型を作り、新しい型のクラスを定義できるようにしたいと考えています。残念ながら、同僚が来て、有効なリファクタリングを実行して誤ってビジネスロジックを壊してしまっても、すべてがOKではありません。この場合

scala> val max = useCompare(listIntMaxs ::: List.empty[Int]) 
max: Option[Int] = Some(1) 

おっと

List[+A]タイプパラメータの共分散と組み合わせるサブタイプの使用は、バグを引き起こしました。 List[Int @@ Max]は、List[Int]が必要な場合はどこでも置換できます。

+0

これは事実です。同僚は、::: List.empty [Int @@ Max] 'にすべきだとはっきりしています。しかし、ボックス化されていないタグ付きのタイプのためにバグではなく、単純なサブタイプ化もそれを引き起こすので、私はしばらくの間別のものを探すつもりです。 – andrepnh

+0

'::: List.empty [Int]'の代わりに:: :: List.empty [Int @@ Max] 'を追加しても、バグは発生しません。私はあなたがここで何が起こっているのか理解していないかもしれないと思う。この問題は、サブタイプを使用して新しいタイプを生成して、タイプ・クラスを再定義するために発生します。シンプルなサブタイプ化もそれを引き起こすことは間違いありませんが、これはまさに問題です。上の例で 'class MaxInt extends Int'を定義してから' Int @@ Max'を 'MaxInt'に置き換えることができるとしましょう。これは本質的に同じことです。 – drstevens

+0

あなたはbmiの例ですが、このパターンを使用する理由の良い例ではありません。ソースに含まれているサンプルを参照してください。私は 'Max'から私の例をモデル化しましたhttps://github.com/scalaz/scalaz/blob/series/7.3.x/example/src/main/scala/scalaz/example/TagUsage.scala#L76-L79 – drstevens

関連する問題