[SCALA] 분리 대 검증
SCALA분리 대 검증
나는 다음과 같은 서명을 가진 메소드를 작성한다고 가정 :
def parse(input: List[(String, String)]):
ValidationNel[Throwable, List[(Int, Int)]]
상기 입력 문자열의 각각의 쌍의 경우, 양쪽 부재의 정수로서 상기 제는 초보다 작은 것으로 해석 될 수 있다는 것을 확인해야한다. 그런 다음 올려 오류를 축적, 정수를 반환해야합니다.
우선 오류 유형을 정의 할 수 있습니다 :
import scalaz._, Scalaz._
case class InvalidSizes(x: Int, y: Int) extends Exception(
s"Error: $x is not smaller than $y!"
)
이제 다음과 같이 나는 나의 방법을 구현할 수 있습니다 :
def checkParses(p: (String, String)):
ValidationNel[NumberFormatException, (Int, Int)] =
p.bitraverse[
({ type L[x] = ValidationNel[NumberFormatException, x] })#L, Int, Int
](
_.parseInt.toValidationNel,
_.parseInt.toValidationNel
)
def checkValues(p: (Int, Int)): Validation[InvalidSizes, (Int, Int)] =
if (p._1 >= p._2) InvalidSizes(p._1, p._2).failure else p.success
def parse(input: List[(String, String)]):
ValidationNel[Throwable, List[(Int, Int)]] = input.traverseU(p =>
checkParses(p).fold(_.failure, checkValues _ andThen (_.toValidationNel))
)
또는 대안 :
def checkParses(p: (String, String)):
NonEmptyList[NumberFormatException] \/ (Int, Int) =
p.bitraverse[
({ type L[x] = ValidationNel[NumberFormatException, x] })#L, Int, Int
](
_.parseInt.toValidationNel,
_.parseInt.toValidationNel
).disjunction
def checkValues(p: (Int, Int)): InvalidSizes \/ (Int, Int) =
(p._1 >= p._2) either InvalidSizes(p._1, p._2) or p
def parse(input: List[(String, String)]):
ValidationNel[Throwable, List[(Int, Int)]] = input.traverseU(p =>
checkParses(p).flatMap(s => checkValues(s).leftMap(_.wrapNel)).validation
)
지금은 어떤 이유로 두 번째 (값을 검사)가 분리 문제 같은 느낌 동안 (쌍은 문자열로 구문 분석하는 것을 확인하는) 첫 번째 작업은 검증 문제처럼 나에게 느낌, 나는 (두 monadically를 구성 할 필요가처럼 느낀다 이는 내가) / ValidationNel 있기 때문에 Throwable를, _] 모나드 인스턴스가없는 \ 사용되어야 함을 시사한다.
내 첫 번째 구현, 나는 내내 ValidationNel을 사용하고 가짜의 flatMap의 일종으로 마지막에 접어. 제에서, 난 축적 또는 모나드 바인딩 에러해야하는지에 따라 적절 / 앞뒤로 ValidationNel과 \ 사이 반송. 그들은 동일한 결과를 생성합니다.
나는 실제 코드에서 두 가지 접근 방식을 사용했습니다, 아직 다른 이상 하나에 대한 선호도를 개발하지 않았습니다. 나는 뭔가를 놓치고 있습니까? 나는 하나는 다른 이상을 선호 하는가?
해결법
-
==============================
1.이것은 아마도 당신이 찾고있는 해답이 아니라 그냥 검증은 다음과 같은 방법을 가지고 발견
이것은 아마도 당신이 찾고있는 해답이 아니라 그냥 검증은 다음과 같은 방법을 가지고 발견
/** Run a disjunction function and back to validation again. Alias for `@\/` */ def disjunctioned[EE, AA](k: (E \/ A) => (EE \/ AA)): Validation[EE, AA] = k(disjunction).validation /** Run a disjunction function and back to validation again. Alias for `disjunctioned` */ def @\/[EE, AA](k: (E \/ A) => (EE \/ AA)): Validation[EE, AA] = disjunctioned(k)
내가 그들을 보았을 때 나는이 질문을 기억까지, 정말 자신의 유용성을 볼 수 없었다. 그들은 당신이 분리로 변환하여 적절한 결합을 할 수 있습니다.
def checkParses(p: (String, String)): ValidationNel[NumberFormatException, (Int, Int)] = p.bitraverse[ ({ type L[x] = ValidationNel[NumberFormatException, x] })#L, Int, Int ]( _.parseInt.toValidationNel, _.parseInt.toValidationNel ) def checkValues(p: (Int, Int)): InvalidSizes \/ (Int, Int) = (p._1 >= p._2) either InvalidSizes(p._1, p._2) or p def parse(input: List[(String, String)]): ValidationNel[Throwable, List[(Int, Int)]] = input.traverseU(p => checkParses(p).@\/(_.flatMap(checkValues(_).leftMap(_.wrapNel))) )
-
==============================
2.다음은 고양이에 대한 내 코드의 두 번째 버전의 아주 가까이 번역 한 것입니다 :
다음은 고양이에 대한 내 코드의 두 번째 버전의 아주 가까이 번역 한 것입니다 :
import scala.util.Try case class InvalidSizes(x: Int, y: Int) extends Exception( s"Error: $x is not smaller than $y!" ) def parseInt(input: String): Either[Throwable, Int] = Try(input.toInt).toEither def checkValues(p: (Int, Int)): Either[InvalidSizes, (Int, Int)] = if (p._1 >= p._2) Left(InvalidSizes(p._1, p._2)) else Right(p) import cats.data.{EitherNel, ValidatedNel} import cats.instances.either._ import cats.instances.list._ import cats.syntax.apply._ import cats.syntax.either._ import cats.syntax.traverse._ def checkParses(p: (String, String)): EitherNel[Throwable, (Int, Int)] = (parseInt(p._1).toValidatedNel, parseInt(p._2).toValidatedNel).tupled.toEither def parse(input: List[(String, String)]): ValidatedNel[Throwable, List[(Int, Int)]] = input.traverse(fields => checkParses(fields).flatMap(s => checkValues(s).toEitherNel).toValidated )
질문을 업데이트하려면,이 코드는 "나는 바인딩 축적 또는 모나드 에러 필요 여부에 따라 적절하게 앞뒤로 ValidatedNel와 어느 사이에 수신 거부"입니다.
나는이 질문을 이후 거의 6 년 동안, 고양이는 해결할 수있는 문제가 정확하게 문제를 내가로 실행중인 것을 (고양이 2.0.0 개선) 병렬 형 클래스를 발표했다 :
import cats.data.EitherNel import cats.instances.either._ import cats.instances.list._ import cats.instances.parallel._ import cats.syntax.either._ import cats.syntax.parallel._ def checkParses(p: (String, String)): EitherNel[Throwable, (Int, Int)] = (parseInt(p._1).toEitherNel, parseInt(p._2).toEitherNel).parTupled def parse(input: List[(String, String)]): EitherNel[Throwable, List[(Int, Int)]] = input.parTraverse(fields => checkParses(fields).flatMap(checkValues(_).toEitherNel) )
우리는 트래버스처럼 우리의 실용적 사업자의 파 버전을 전환하거나 우리가 축적 오류로 할 때 tupled하지만, 그렇지 않으면 우리 바인딩 모나드 우리를 제공 하나에있어 작업, 우리는 더 이상 전혀 인증 됨를 참조 할 수 있습니다.
from https://stackoverflow.com/questions/20065853/validation-versus-disjunction by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라 2.8에 대한 어떤 IDE? (0) | 2019.11.15 |
---|---|
[SCALA] 스칼라 선물에 의해 반환 된 액세스 값 (0) | 2019.11.15 |
[SCALA] 하지가 슬릭 3.0.0에있는 경우 삽입 (0) | 2019.11.15 |
[SCALA] 문자열에 FlatMap 대지도 (0) | 2019.11.15 |
[SCALA] 스칼라 2.10 반사, 나는 경우 클래스의 경우 클래스, 즉 필드 목록에서 필드 값을 추출 어떻게 (0) | 2019.11.15 |