2014-04-15 8 views
8

object Sized içinde ("shapeless/sized.scala" içinde), maalesef statik denetim sağlamayan unapplySeq var. tuple Seçenek geri yerine unapply yöntem olup olmadığınıEksik Sized.unapply

Sized(1, 2, 3) match { case Sized(x, y) => ":(" } 

daha iyi olur, ve başlığın somut şekil Ölçekli örneğinin büyüklüğüne göre oluşturulmuştur: Örnek kodu için aşağıdaki MatchError ile zamanında başarısız olur. Örneğin: Eğer durum önceki kod snippet'inde

Sized(1) => x 
Sized(1, 2) => (x, y) 
Sized(1, 2, 3) => (x, y, z) 

constructor cannot be instantiated to expected type ile derlemek için başarısız olur.

object Sized için unapply'u uygulamama yardım edin. Bu yöntem zaten herhangi bir yerde uygulandı mı?

Şimdiden teşekkürler!

cevap

5

Bu kesinlikle mümkündür (en azından'un 23'den az olduğu Sized için), ancak düşünebildiğim tek yaklaşım (makrolama, vb.) Dağınıktır.

import shapeless._, Nat._0 
import scala.collection.generic.IsTraversableLike 

trait SizedToHList[R, N <: Nat] extends DepFn1[Sized[R, N]] { 
    type Out <: HList 
} 

object SizedToHList { 
    type Aux[R, N <: Nat, Out0 <: HList] = SizedToHList[R, N] { type Out = Out0 } 

    implicit def emptySized[R]: Aux[R, Nat._0, HNil] = new SizedToHList[R, _0] { 
    type Out = HNil 
    def apply(s: Sized[R, _0]) = HNil 
    } 

    implicit def otherSized[R, M <: Nat, T <: HList](implicit 
    sth: Aux[R, M, T], 
    itl: IsTraversableLike[R] 
): Aux[R, Succ[M], itl.A :: T] = new SizedToHList[R, Succ[M]] { 
    type Out = itl.A :: T 
    def apply(s: Sized[R, Succ[M]]) = s.head :: sth(s.tail) 
    } 

    def apply[R, N <: Nat](implicit sth: SizedToHList[R, N]): Aux[R, N, sth.Out] = 
    sth 

    def toHList[R, N <: Nat](s: Sized[R, N])(implicit 
    sth: SizedToHList[R, N] 
): sth.Out = sth(s) 
} 

Sonra bu dönüşümü kullanan bir çıkarıcı nesneyi tanımlayabilirsiniz: Sonra

import ops.hlist.Tupler 

object SafeSized { 
    def unapply[R, N <: Nat, L <: HList, T <: Product](s: Sized[R, N])(implicit 
    itl: IsTraversableLike[R], 
    sth: SizedToHList.Aux[R, N, L], 
    tupler: Tupler.Aux[L, T] 
): Option[T] = Some(sth(s).tupled) 
} 

Ve: Öncelikle bize HList s'ye ölçekli koleksiyonları dönüştürmek yardımcı olacağız bir tür sınıf gerekir

scala> val SafeSized(x, y, z) = Sized(1, 2, 3) 
x: Int = 1 
y: Int = 2 
z: Int = 3 

Ama:

scala> val SafeSized(x, y) = Sized(1, 2, 3) 
<console>:18: error: wrong number of arguments for object SafeSized 
     val SafeSized(x, y) = Sized(1, 2, 3) 
        ^
<console>:18: error: recursive value x$1 needs type 
     val SafeSized(x, y) = Sized(1, 2, 3) 
        ^

İstenildiği gibi.