简体   繁体   中英

Determine if `Nat mod 5 = 0` at Compile-Time in Scala

This answer demonstrates how to write a function, in Idris, to determine if a Nat mod 5 = 0 at compile-time:

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

Tests:

*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

How can such a function be written in Scala (I'm assuming with shapeless )?

Provide a proof (value) that 0 is 0 mod 5, then provide proof that (N + 5) mod 5 is 0 given proof the N mod 5 is 0:

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

With Shapeless it is pretty straightforward.

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)
                 ^

Integers get converted to a Nat by some macro, so they have to be literals and can't get too big without the compiler blowing up. The ToInt typeclass is used for converting the Nat back to an Int .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM