2013-06-04 3 views
2

Невозможно понять, можно ли написать что-то подобное с помощью Scalaz 7. Я попытался выразить себя комментариями внутри блока кода.Как использовать аппликативные функторы для объединения проверки Scalaz

def validate1(p: String) = ValidationNel[String, Value] = ... 
def validate2(p: String) = ValidationNel[String, Value] = ... 

validateCombination(p1: String, p2: String) = { 
    // I would like to write something like 
    (validate1(p1) |@| validate2(p2)) { (v1, v1) => 
    // And validate the combinations here and return successNel of failNel 
    } 
} 

def validate(p1: String, p2: String, p3: String) = { 
    (validateCombination(p1, p2) |@| validate1(p3)) { (v1, v2, v3) => 
    // Notice the three parameters I want to have here 
    } 
} 

Я просто в конечном итоге с различными типами запутанных ошибок компиляции в validateCombinations или только 2 параметры для аппликативном функтора я получаю внутри функции Validate, один из них типа ValidationNel [...].

ответ

6

Вы можете использовать .flatMap(identity) в методе validateCombination производить ValidationNel[String, (Value, Value)] и pattern matching в методе validate так:

def validateCombination(p1: String, p2: String): ValidationNel[String, (Value, Value)] = { 
    // I would like to write something like 
    (validate1(p1) |@| validate2(p2)) { (v1, v1) => 
    (v1, v2).successNel[String] 
    }.flatMap(identity) 
} 

def validate(p1: String, p2: String, p3: String) = { 
    (validateCombination(p1, p2) |@| validate1(p3)) { case ((v1, v2), v3) => 
    // Notice the three parameters I want to have here 
    } 
} 

flatMap (идентичность)

Обычно используется метод flatten на вложенные контейнеры, чтобы получить M[T] от M[M[T]]. Он работает на Future, Option, Try, коллекциях и т. Д.

В данном случае type M[T] = ValidationNel[String, T].

Я не знаю, почему нет никакого метода flatten в Validation, но вы всегда можете использовать flatMap(identity) вместо flatten.

матч

Как Ben Jamesnoted, flatMap на Validation сомнительна. Вы всегда можете использовать match вместо него:

(validate1(p1) |@| validate2(p2)) { (v1, v1) => 
    (v1, v2).successNel[String] 
} match { 
    case Success(s) => s 
    case Failure(f) => Failure(f) 
} 

шаблону

соответствие шаблона является общим способом борьбы с кортежами. Например, это полезно для метода foldLeft, например foldLeft(1 -> 2){ case ((a, b), c) => ??? }.

Если вы обнаружили, что используете геттеры _N на Tuple, вам, вероятно, следует использовать соответствующий шаблон.

для понимания

Как Daniel C. Sobralnoted для понимания может быть проще для понимания.

Вы можете использовать его в вашем методе validate так:

def validate(p1: String, p2: String, p3: String) = { 
    for{ 
    (v1, v2) <- validateCombination(p1, p2) // pattern matching 
    v3 <- validate1(p3) 
    } yield ??? // Your code here 
} 

Она включает в себя сопоставление с образцом без case ключевого слова.

Обратите внимание, что для понимания вызовов flatMap на validateCombination(p1, p2), так что вы будете потеряны сообщения об ошибках validate1(p3) в случае validateCombination(p1, p2) является Failure. Наоборот, |@| собирает все сообщения об ошибках с обеих сторон.

+0

Хотя я бы использовал это для понимания - это легче понять, имхо. –

+0

'Validation' не имеет сглаживания, потому что он не предназначен для монады. Фактически метод 'flatMap' сомнительный. Но есть методы для выполнения операций над эквивалентом '\ /' проверки и преобразования назад, например. 'v.disjunctioned (_. flatten)' –

+0

@ DanielC.Sobral: вы имеете в виду «для понимания вместо' | @ | '"? Я думал, что нужно держать '| @ |' нетронутым. Спасибо за предложение. Не возражаете, я добавлю это к моему ответу? – senia

Смежные вопросы