2016-12-09 47 views
2

具體值給出:構建列表與在編譯時

case class Foo(x: BigDecimal)

我想,在編譯時,構建一個List[Foo]每個Foo必須有5一個BigDecimal值。

所以,我希望下面的代碼進行編譯:

type Foo5Only = ??? 

val foos5: List[Foo5Only] = List(Foo(5), Foo(5)) 

但是,我期望下無法編譯:

val bad: List[Foo5Only] = List(Foo(42))

我猜測,一個shapeless單身類型可能很有用,但我實際上並沒有理解它。

注 - 我對這個問題沒有興趣,導致使用EitherOption

+0

需要BigDecimal嗎? (否則,你可能可以使用'Nat'和參數化'Foo') –

+0

@MichaelZajac - 是的,'Nat'會工作,謝謝。對於我自己的學習,Singleton類型是否適用於此 - 作爲「Nat」的替代方案? –

回答

1

除了使用無形的'Nat類型,你也可以使用單身類型。不幸的是Scala的內置列表類型具有協方差它得到的類型安全的方式,而是用一個簡單的手工製作的列表類型似乎工作:

import shapeless.syntax.singleton._ 

sealed trait Lst[T] 
case class Nil[T]() extends Lst[T] 
case class Cons[T](head : T, tail : Lst[T]) extends Lst[T] 

def list[T](t : T) : Lst[T] = { 
    Cons(t, Nil()) 
} 

// OK 
val foos5 = Cons(5.narrow, list(5.narrow)) 

// Compile-time type mismatch error. 
val foos6 = Cons(42.narrow, list(5.narrow)) 

您或許能夠與一些宏的Elid的narrow小號 - 可能,但這超出了我的能力。