11

Scalaz 6を学びながら、検証を返すタイプセーフなリーダーを作成しようとしています。これが私の新しいタイプです:

type ValidReader[S,X] = (S) => Validation[NonEmptyList[String],X]
type MapReader[X] = ValidReader[Map[String,String],X]

そして、intとstrings(*)のマップリーダーを作成する2つの関数があります。

def readInt( k: String ): MapReader[Int] = ...
def readString( k: String ): MapReader[String] = ...

次のマップがあるとします。

val data = Map( "name" -> "Paul", "age" -> "8" )

名前と年齢を取得するために2つのリーダーを作成できます。

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

println( name(data) ) //=> Success("Paul")
println( age(data) )  //=> Success(8)

Boyすべて正常に動作しますが、インスタンスを構築するために両方のリーダーを作成したいと思います。

case class Boy( name: String, age: Int )

私の最善の策は次のとおりです。

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

期待どおりに機能しますが、2つのレベルのアプリケーションビルダーでは表現が厄介です。次の構文を機能させる方法はありますか?

  val boy = ( name |@| age ) { Boy(_,_) }

(*)https://gist.github.com/1891147の完全で実行可能な実装


更新:上記の行またはダニエルの提案を試したときに表示されるコンパイラエラーメッセージは次のとおりです。

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

2 に答える 2

5

これはどう?

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

またはタイプエイリアスを使用:

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

val boy = (name |@| age) apply (Boy(_, _)).lift[VNELStr]

これは、コンソールの次のエラー メッセージに基づいています。

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]) => ?

Boy.applyそのため、必要なタイプを取るために持ち上げました。

于 2012-02-23T18:37:02.560 に答える
2

ReaderおよびValidation(半群 E を持つ) は両方とも Applicative であるため、それらの合成も Applicative であることに注意してください。scalaz 7 を使用すると、これは次のように表現できます。

import scalaz.Reader
import scalaz.Reader.{apply => toReader}
import scalaz.{Validation, ValidationNEL, Applicative, Kleisli, NonEmptyList}

//type IntReader[A] = Reader[Int, A] // has some ambigous implicit resolution problem
type IntReader[A] = Kleisli[scalaz.IdInstances#Id, Int, A]
type ValNEL[A] = ValidationNEL[Throwable, A]

val app = Applicative[IntReader].compose[ValNEL]

|@|これで、構成された Applicative に対して単一の操作を使用できます。

val f1 = toReader((x: Int) => Validation.success[NonEmptyList[Throwable], String](x.toString))
val f2 = toReader((x: Int) => Validation.success[NonEmptyList[Throwable], String]((x+1).toString))

val f3 = app.map2(f1, f2)(_ + ":" + _)

f3.run(5) should be_==(Validation.success("5:6"))
于 2012-08-11T07:56:46.213 に答える