6

アプリで Scalaz 7 Validation を使用しようとしています。しかし、|@|Applicative functor で失敗を合体させるのに問題があります。ここに私が持っているコードがあります:

type ValidationResult = ValidationNel[String, Unit]

def validate[A: ClassTag](instance: A, fieldNames: Option[Seq[String]] = None): ValidationResult = {
    val fields = classTag[A].runtimeClass.getDeclaredFields
    val fieldSubset = fieldNames match {
        case Some(names) => fields.filter { field => names.contains(field.getName) }
        case None => fields
    }
    fieldSubset.map {
        field => field.getAnnotations.toSeq.map {
            field.setAccessible(true)
            val (name, value) = (field.getName, field.get(instance))
            field.setAccessible(false)
            annotation => annotation match {
                case min: Min => minValidate(name, value, min.value())
                case size: Size => sizeValidate(name, value, size.min(), size.max())
            }
        }
    }.flatten[ValidationResult].foldLeft(().successNel[String])(_ |@| _)
}

および関数は単に を返しminValidateます。sizeValidateValidationResults

問題は、このコードがコンパイルされないことです。エラーメッセージは次のとおりです。

Type mismatch, expected F0.type#M[NotInferedB], actual: ValidationResult

それが何を意味するのかわかりません... Scalaにもっと型情報を与える必要がありますか?

私が達成しようとしているのは、すべてのフィールドが s の場合はそれを返し、それ以外の場合はすべてのs のsuccessNel組み合わせを返すことです。failureNel

|@|以前のバージョンの Scalaz から変更されましたか? 私が次のようなことをしても:

().successNel |@| ().successNel

同じエラーが発生します。

アップデート

Scalaz のソースを調べてみたところ、自分の+++やりたいことを実行しているように見える が見つかりました。

+++とはどう違い|@|ますか?

4

1 に答える 1

10

Scalaz の applicative builder syntax ( |@|) は、関数を applicative functor に「持ち上げる」方法を提供します。たとえば、次の結果が得られたとします。

val xs: ValidationNel[String, List[Int]] = "Error!".failNel
val ys: ValidationNel[String, List[Int]] = List(1, 2, 3).success
val zs: ValidationNel[String, List[Int]] = List(4, 5).success

リスト連結関数 ( ++) を次のValidationように持ち上げることができます。

scala> println((ys |@| zs)(_ ++ _))
Success(List(1, 2, 3, 4, 5))

scala> println((xs |@| ys)(_ ++ _))
Failure(NonEmptyList(Error!))

scala> println((xs |@| xs)(_ ++ _))
Failure(NonEmptyList(Error!, Error!))

この構文は少し奇妙です。たとえば、Haskell で関数をアプリカティブ ファンクターに持ち上げる方法とは非常に似ており、主に Scala のかなりばかげた型推論システムの裏をかくためにこのように設計されています。詳細については、こちらの回答またはブログ投稿をご覧ください。

奇妙な点の 1 つは、 xs |@| ysそれ自体では実際には何も意味しないということです。これは本質的に、関数に適用されるのを待っている引数リストであり、それがそのアプリカティブ ファンクターに持ち上げられ、それ自体に適用されます。

+++onValidationはより単純な種類のクリーチャーです — これは単にその型のインスタンスの加算演算です(ここで の代わりにSemigroupScalaz の半群演算子を同等に使用できることに注意してください)。半群型が一致する2 つの結果を与えると、もう 1 つの結果が得られますが、ひどいことではありません。|+|+++ValidationValidationApplyOps


補足として、この場合、 の半群の加算演算Validationは、 にリフトされた右側の半群演算と同じですValidation

scala> (xs |+| ys) == (xs |@| ys)(_ |+| _)
res3: Boolean = true

ただし、常にそうであるとは限りません (\/たとえば、半群がエラーを累積するが、アプリケーション ファンクターは累積しない場合はそうではありません)。

于 2013-07-18T01:16:05.187 に答える