Sono nuovo di informi e ho provato a praticare una programmazione a livello di tipo. Ho preso Problem #1 from Project Euler come prima sfida.Codice senza forma di Scala per Project Eulero # 1
ho iniziato scrivendo regolare codice Scala:
object ProjectEuler1 {
def e1(limit: Int) = (1 until limit).foldLeft(0) {
case (acc, x) if x % 3 * x % 5 == 0 => acc + x
case (acc, _) => acc
}
val out = e1(10)
assert(out == 23)
}
Poi, mi si avvicinò con questo lavoro implementazione informe utilizzando poly
:
object ProjectEuler1Shapeless extends App {
import shapeless._
import nat._
import ops.nat._
import poly._
import test.typed
trait eLP extends Poly1 {
implicit def default[A <: Nat] = at[A] { _ => _0 }
}
object e extends eLP {
implicit def match3[A <: Nat](implicit ev: Mod.Aux[A, _3, _0]) = at[A](identity)
implicit def match5[A <: Nat](implicit ev: Mod.Aux[A, _5, _0]) = at[A](identity)
}
object sum extends Poly2 {
implicit def sum[A <: Nat, B <: Nat, Z <: Nat](implicit s: Sum.Aux[A, B, Z],
z: Witness.Aux[Z]) =
at[A, B] { (_, _) => z.value }
}
type _23 = Succ[_22]
val l = _1 :: _2 :: _3 :: _4 :: _5 :: _6 :: _7 :: _8 :: _9 :: HNil
val out = l.map(e).foldLeft(_0)(sum)
typed[_23](out)
}
successiva, ho voluto cambiare la funzione in modo che io non è necessario creare manualmente un elenco. Invece accetta un "limite" come argomento come il normale codice di scala. Mi sono inventato questo:
object ProjectEuler1Shapeless2 extends App {
import shapeless._
import nat._
import ops.nat._
import test.typed
class E1[I <: Nat, N <: Nat]
trait ELP0 {
implicit def default[I <: Nat, M <: Nat] = new E1[I, _0]
}
trait ELP1 extends E1LP0 {
implicit def match3[A <: Nat](implicit ev: Mod.Aux[A, _3, _0]) = new E1[A, A]
implicit def match5[A <: Nat](implicit ev: Mod.Aux[A, _5, _0]) = new E1[A, A]
}
object E1 extends E1LP1 {
implicit def combine[I <: Nat, L <: Nat, M <: Nat](implicit e1: E1[I, L],
m: E1[Succ[I], M],
sum: Sum[L, M]) =
new E1[Succ[Succ[I]], sum.Out]
}
def e1[N <: Nat](limit: Nat)(implicit e: E1[limit.N, N], w: Witness.Aux[N]): N = w.value
val f1 = e1(1)
typed[_0](f1)
val f2 = e1(2)
typed[_0](f2)
val f3 = e1(3)
typed[_3](f3) // Does not compile!
}
Sono rimasto bloccato qui. Il compilatore mi sta dicendo che ha trovato _0
. Immagino che stia raccogliendo l'istanza da def default
.
Qualche consiglio su come posso risolvere questo problema? Ho la sensazione che la mia strategia per risolvere questo problema potrebbe essere un po 'strana anche. Ogni suggerimento su come posso rendere questo codice informe più idiomatico è molto apprezzato.
La mia strategia originale era di creare un hylomorphism. Ho notato che c'è uno unfold example in the shapeless git ma la sua complessità mi sfugge al momento.
Questo è bello. Esattamente quello che volevo ed estremamente educativo. Una grande lezione su come modellare il tuo pensiero con Shapeless. Userò sicuramente questa risposta come riferimento per affrontare i problemi futuri. – beefyhalo
Impossibile 'sumN' usare' P' e 'Succ [P]' al posto di 'Succ [P]' e 'Succ [Succ [P]]' o c'è qualcosa che mi manca? – beefyhalo
@beefyhalo Ah, è possibile, stavo scrivendo mentre ero in conferenza oggi. –