我想写一个以Nat为参数的函数,如果这个nat不能被3整除,则只返回这个nat。
例如:
def myFunction[N <: Nat](n :N)(implicit ev: /* what do I put here that say not divible by 3 ? */): N = n
要做到这一点,我必须写一些东西,说&#34; N不能被_3&#34;或&#34;&#34; Mod.Aux [N,_3,_0]整除为空类型&#34;
我怎么能在无形状中做到这一点?
答案 0 :(得分:10)
在这种特殊情况下最简单的方法可能只是使用=:!=
(尽管请注意您需要一个新的类型参数):
import shapeless._, nat._, ops.nat.Mod
def myFunction[N <: Nat, R <: Nat](n: N)
(implicit mod: Mod.Aux[N, _3, R], neq: R =:!= _0) = n
更一般地说,将这种约束表达为类型类并不太难:
trait NotDivBy3[N <: Nat]
object NotDivBy3 {
implicit def notDivBy3[N <: Nat]: NotDivBy3[N] = new NotDivBy3[N] {}
implicit def notDivBy3Ambig[N <: Nat]
(implicit ev: Mod.Aux[N, _3, _0]): NotDivBy3[N] = unexpected
}
def myFunction[N <: Nat: NotDivBy3](n: N) = n
甚至更普遍:
trait DoesntHave[N <: Nat, Prop[_ <: Nat]]
object DoesntHave {
implicit def doesntHave[N <: Nat, Prop[_ <: Nat]]: DoesntHave[N, Prop] =
new DoesntHave[N, Prop] {}
implicit def doesntHaveAmbig[N <: Nat, Prop[_ <: Nat]]
(implicit ev: Prop[N]): DoesntHave[N, Prop] = unexpected
}
type Mod3Is0[N <: Nat] = Mod.Aux[N, _3, _0]
type NotDivBy3[N <: Nat] = DoesntHave[N, Mod3Is0]
def myFunction[N <: Nat: NotDivBy3](n: N) = n
这两个解决方案都使用与=:!=
相同的机制(即它们依赖于Scala编译器如果有两个不能优先考虑的候选者则无法找到隐含值的事实)。
我可能倾向于使用第二种方法,除非我发现我需要很多类似的约束,在这种情况下,第三种可能更干净。