Il modo più semplice in questo caso particolare è probabilmente solo per utilizzare =:!=
(anche se nota che è necessario un nuovo parametro del tipo):
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
Più in generale, non è troppo difficile esprimere questo tipo di vincolo come una classe tipo:
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
O anche, più in generale:
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
Entrambe queste soluzioni utilizzano lo stesso meccanismo di =:!=
(ad es. si basano sul fatto che il compilatore Scala non riuscirà a trovare un valore implicito se ha due candidati che non può dare la priorità).
Probabilmente tenderei ad andare con il secondo approccio, a meno che non trovassi che avevo bisogno di molti vincoli come questo per lo stesso tipo, nel qual caso il terzo potrebbe essere più pulito.
Grazie è esattamente quello che volevo. (E ho imparato un sacco di cose nuove in poche righe :)) – Molochdaa
Dio, non provo nemmeno a indovinare chi risponderà più alle domande relative alla magia del tipo. Scorro verso il basso e dico a me stesso "oh, @TravisBrown. va bene.' – tkroman