如何用scalaz组成应用程序的功能

par*_*tic 11 validation scala scalaz applicative

学习Scalaz 6时,我正在尝试编写类型安全的读者返回验证.这是我的新类型:

type ValidReader[S,X] = (S) => Validation[NonEmptyList[String],X]
type MapReader[X] = ValidReader[Map[String,String],X]
Run Code Online (Sandbox Code Playgroud)

我有两个函数为int和字符串(*)创建地图阅读器:

def readInt( k: String ): MapReader[Int] = ...
def readString( k: String ): MapReader[String] = ...
Run Code Online (Sandbox Code Playgroud)

给出以下地图:

val data = Map( "name" -> "Paul", "age" -> "8" )
Run Code Online (Sandbox Code Playgroud)

我可以写两个读者来检索姓名和年龄:

val name = readString( "name" )
val age = readInt( "age" )

println( name(data) ) //=> Success("Paul")
println( age(data) )  //=> Success(8)
Run Code Online (Sandbox Code Playgroud)

一切正常,但现在我想组成两个读者来构建一个Boy实例:

case class Boy( name: String, age: Int )
Run Code Online (Sandbox Code Playgroud)

我最好的看法是:

  val boy = ( name |@| age ) {
    (n,a) => ( n |@| a ) { Boy(_,_) }
  }
  println( boy(data) ) //=> Success(Boy(Paul,8))
Run Code Online (Sandbox Code Playgroud)

它按预期工作,但表达方式很尴尬,有两个级别的应用程序构建器.有没有办法,让以下语法工作?

  val boy = ( name |@| age ) { Boy(_,_) }
Run Code Online (Sandbox Code Playgroud)

(*)完整且可运行的实现:https://gist.github.com/1891147


更新:这是我在尝试上面的行或Daniel建议时得到的编译器错误消息:

[error] ***/MapReader.scala:114: type mismatch;
[error]  found   : scalaz.Validation[scalaz.NonEmptyList[String],String]
[error]  required: String
[error]   val boy = ( name |@| age ) { Boy(_,_) }
[error]                                    ^
Run Code Online (Sandbox Code Playgroud)

huy*_*hjl 5

这个怎么样?

val boy = (name |@| age) {
  (Boy.apply _).lift[({type V[X]=ValidationNEL[String,X]})#V]
}
Run Code Online (Sandbox Code Playgroud)

或使用类型别名:

type VNELStr[X] = ValidationNEL[String,X]

val boy = (name |@| age) apply (Boy(_, _)).lift[VNELStr]
Run Code Online (Sandbox Code Playgroud)

这基于控制台上的以下错误消息:

scala> name |@| age apply Boy.apply
<console>:22: error: type mismatch;
 found   : (String, Int) => MapReader.Boy
 required: (scalaz.Validation[scalaz.NonEmptyList[String],String], 
            scalaz.Validation[scalaz.NonEmptyList[String],Int]) => ?
Run Code Online (Sandbox Code Playgroud)

所以我只是Boy.apply采取了所需的类型.