如何在无形中你说证明是空类型(即假的)

时间:2014-07-20 18:32:03

标签: scala shapeless

我想写一个以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;

我怎么能在无形状中做到这一点?

1 个答案:

答案 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编译器如果有两个不能优先考虑的候选者则无法找到隐含值的事实)。

我可能倾向于使用第二种方法,除非我发现我需要很多类似的约束,在这种情况下,第三种可能更干净。