在Scala中的Compile-Time确定`nat mod 5 = 0`

时间:2016-04-12 02:35:01

标签: scala shapeless idris

这个enter image description here演示了如何在Idris中编写函数来确定编译时是否Nat mod 5 = 0

onlyModBy5 : (n : Nat) -> {auto prf : n `modNat` 5 = 0} -> Nat
onlyModBy5 n = n

试验:

*Test> onlyModBy5 5
5 : Nat
*Test> onlyModBy5 10
10 : Nat
*Test> onlyModBy5 11
(input):1:12:When checking argument prf to function Main.onlyModBy5:
        Can't find a value of type 
                1 = 0

如何在Scala中编写这样的函数(我假设使用shapeless)?

2 个答案:

答案 0 :(得分:2)

提供0为0 mod 5的证明(值),然后提供证明(N + 5)mod 5为0,证明N mod 5为0:

https://gist.github.com/stew/4074742#file-fizzbuzz-scala-L81-L90

答案 1 :(得分:2)

使用Shapeless非常简单。

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_77).
Type in expressions for evaluation. Or try :help.

scala> import shapeless._
import shapeless._

scala> import ops.nat._
import ops.nat._

scala> type _5 = Succ[Succ[Succ[Succ[Succ[_0]]]]]
defined type alias _5

scala> def onlyModBy5(n: Nat)(implicit ev: Mod.Aux[n.N, _5, _0], toInt: ToInt[n.N]) = toInt()
onlyModBy5: (n: shapeless.Nat)(implicit ev: shapeless.ops.nat.Mod.Aux[n.N,_5,shapeless._0], implicit toInt: shapeless.ops.nat.ToInt[n.N])Int

scala> onlyModBy5(0)
res0: Int = 0

scala> onlyModBy5(25)
res1: Int = 25

scala> onlyModBy5(47)
<console>:20: error: could not find implicit value for parameter ev: shapeless.ops.nat.Mod.Aux[nat_$macro$6.N,_5,shapeless._0]
       onlyModBy5(47)
                 ^

整数被一些宏转换为Nat,所以它们必须是文字,如果没有编译器爆炸就不能变得太大。 ToInt类型类用于将Nat转换回Int