Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying validation from HList to a case class

In attempting to do validation with application functors (Monad to catch multiple exceptions (not just fail on single)), I came across a hard limit in scalaz that disallows more than 14 functors, so a helpful comment from here (https://github.com/scalaz/scalaz/issues/504#issuecomment-23626237) navigated me to use HLists instead of applicative functors

Now it works perfectly fine (after having to manually put in this sequence file from here since its not in maven https://github.com/typelevel/shapeless-contrib/blob/master/scalaz/main/scala/sequence.scala?source=c)

My question is, and I know this is possible, how would you go about automatically instantiating the case class Foo(i:Int,s:String) without having to manually match the pattern with a case, only to just reapply the parameters again

Essentially I want to do something like this

  case class Foo(i:Int,s:String)

  implicit def TwoFoo = Iso.hlist(Foo.apply _, Foo.unapply _)

  val someFoo = sequence(
      1.successNel[Int] ::
      "2".successNel[String] ::
      HNil
  ).map { Foo.apply _} // Note this doesn't work

  someFoo match {
    case Success(a) => println(a)
    case Failure(a) => {
      println("failure")
      println(a)
    }
  }
like image 960
mdedetrich Avatar asked Mar 23 '23 14:03

mdedetrich


1 Answers

First for a minor point: the type parameter for successNel is the error type, not the success type, so it needs to be the same across all the arguments to sequence.

So we can write the following (assuming our errors are strings):

import shapeless._, contrib.scalaz._
import scalaz._, syntax.validation._

case class Foo(i: Int, s: String)

implicit val fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)

val valHList = sequence(1.successNel[String] :: "2".successNel[String] :: HNil)

This gives us an Int :: String :: HNil inside a validation. Now we can use our isomorphism:

scala> valHList.map(fooIso.from)
res0: scalaz.Validation[scalaz.NonEmptyList[String],Foo] = Success(Foo(1,2))

No need to deconstruct the list and apply the Foo constructor manually.

like image 63
Travis Brown Avatar answered Apr 13 '23 20:04

Travis Brown