2016-11-08 1 views
1

Je suis en train de convertir cet exemple Applicative validation syntax en Scalaz 7 + Shapeless 2,0syntaxe de validation Applicative scalaz + informes 2.0

//for jupyter-scala kernel 
//classpath.add("org.scalaz" %% "scalaz-core" % "7.2.7") 
//classpath.add("com.chuusai" %% "shapeless" % "2.3.2") 

case class Foo(a: Int, b: Char, c: String) 

D'abord la syntaxe Scalaz

import scalaz._ 
import Scalaz._ 

type ErrorsOr[A] = ValidationNel[String, A] 
type Validator[A] = String => ErrorsOr[A] 

val checkA: Validator[Int] = (s: String) => 
    try s.toInt.success catch { 
    case _: NumberFormatException => "Not a number!".failureNel 
} 

val checkB: Validator[Char] = (s: String) => 
    if (s.size != 1 || s.head < 'a' || s.head > 'z') { 
    "Not a lower case letter!".failureNel 
    } else s.head.success 

val checkC: Validator[String] = (s: String) => 
    if (s.size == 4) s.success else "Wrong size!".failureNel 


def validateFoo(a: String, b: String, c: String) = 
    (checkA(a) |@| checkB(b) |@| checkC(c))(Foo.apply _) 

println(validateFoo("ab", "cd", "ef")) 
//Failure(NonEmpty[Not a number!,Not a lower case letter!,Wrong size!]) 
println(validateFoo("42", "cd", "ef")) 
//Failure(NonEmpty[Not a lower case letter!,Wrong size!]) 

def validateFoo2(a: String, b: String, c: String):Validation[NonEmptyList[String], Foo] = 
    checkC(c) <*> (checkB(b) <*> (checkA(a) map (Foo.apply _).curried)) 

println(validateFoo2("42", "cd", "ef")) 
//Failure(NonEmpty[Not a lower case letter!,Wrong size!]) 

Jusqu'à présent, si bon, maintenant en informes 2,0

import shapeless._ 
import shapeless.ops.hlist._ 
import shapeless.ops.function._ 
import shapeless.poly._ 
import shapeless.syntax.std.function._ 

object applier extends Poly2 { 
    implicit def ap[F[_]: Applicative, H, T <: HList, R]: 
    Case2.Aux[applier.type, F[(H :: T) => R], F[H], F[T => R]] = 
    at[F[(H :: T) => R], F[H]](
     (f, fa) => fa <*> f.map(hf => (h: H) => (t: T) => hf(h :: t)) 
    ) 
} 

class Lifter[F[_]: Applicative] { 
    def lift[G, H, A <: HList, M <: HList, R](g: G)(implicit 
    hlG: FnToProduct.Aux[G, A => R], 
    mapped: Mapped.Aux[A, F, M], 
    unH: FnFromProduct.Aux[M => F[R], H], 
    folder: LeftFolder.Aux[M, F[A => R], applier.type, F[HNil => R]] 
) = unH((m: M) => folder(m, hlG(g).point[F]).map(_(HNil))) 
} 

def into[F[_]: Applicative] = new Lifter[F] 

val liftedFoo = into[ErrorsOr] lift (Foo.apply _) 

def validateFooGeneric(a: String, b: String, c: String) = 
    liftedFoo(checkA(a), checkB(b), checkC(c)) 

println(validateFooGeneric("42", "cd", "ef")) 
//Failure(NonEmpty[Not a lower case letter!,Wrong size!]) 

maintenant, le dernier bit

def validate[F[_], G, H, V <: HList, I <: HList, M <: HList, A <: HList, R] 
    (g: G)(v: V)(implicit 
    hlG: FnToProduct.Aux[G, A => R], 
    zip: ZipApply.Aux[V, I, M], 
    mapped: Mapped.Aux[A, F, M], 
    unH: FnFromProduct.Aux[I => F[R], H], 
    folder: LeftFolder.Aux[M, F[A => R], applier.type, F[HNil => R]], 
    appl: Applicative[F] 
) = unH((in: I) => folder(zip(v, in), hlG(g).point[F]).map(_(HNil))) 

Tous compilation mais quand on tente de l'utiliser, par exemple:

val validateFooShapeless = validate(Foo.apply _)(checkA :: checkB :: checkC :: HNil) 

Je reçois une erreur

could not find implicit value for parameter mapped: shapeless.ops.hlist.Mapped.Aux[A,F,M] 
validate(Foo.apply _)(checkA :: checkB :: checkC :: HNil) 
        ^ 

Toutes les idées, les pointeurs seraient appréciés

Répondre

0

Vous avez besoin SI-2712 amélioration pour la recherche implicite de fonctionner correctement sur le type lambdas (par exemple, Validator[?]). Mise à jour Scala à 2.11.11+ ou 2.12.2+ et ajoutez ce qui suit à votre build.sbt:

scalacOptions ++= Seq("-Ypartial-unification") 

Pour 2.10.x, il y a un compiler plugin, que vous pouvez activer avec la ligne suivante dans build.sbt :

addCompilerPlugin("com.milessabin" % "si2712fix-plugin_2.10.6" % "1.2.0")