2017-02-17 7 views
4

첫 번째 오류가 발생한 후에 유효성 검사가 중지되도록 아래에 유효성 검사 함수를 작성하려고합니다. 반환 유형 three은 다른 기능과 다릅니다. 이 코드를 컴파일하기 위해 어떤 모나드 변환기를 사용해야합니까?어떤 Monad Transformer를 사용할 수 있습니까?

import scalaz._ 
import Scalaz._ 
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 


def one(a : String): Disjunction[Int, String] = 
    a == "one" match { 
    case true => \/-("one") 
    case false => -\/(2) 
    } 

def two(a : String): Disjunction[Int, String] = 
    a == "two" match { 
    case true => \/-("two") 
    case false => -\/(3) 
    } 

def three(a : String): Future[Disjunction[Int, String]] = 
    Future (a == "three") map { 
    case true => \/-("three") 
    case false => -\/(4) 
    } 

def validate(a : String) = for { 
    e1 <- one(a) 
    e2 <- two(a) 
    e3 <- EitherT(three(a)) 
} yield (e1 |+| e2 |+| e3) 

컴파일 오류 :이 같은 상황에서 취할 수있는 두 가지 일반적인 방법이 있습니다

Error:(27, 7) type mismatch; 
found : scalaz.EitherT[scala.concurrent.Future,Int,String] 
required: scalaz.\/[?,?] 
    e3 <- EitherT(three(a)) 
    ^
Error:(66, 7) type mismatch; 
found : scalaz.EitherT[scala.concurrent.Future,Int,String] 
required: scalaz.\/[?,?] 
    e3 <- EitherT(three(a)) 
    ^
+1

'미래'또는 '기다림'에서 '3'의 결과로 '1'과 '2'를 모두 감싸지 않는 이유는 무엇입니까? –

+0

당신은'EitherT' 모나드 변압기를보고 싶습니다. 세번째'<'는'String'을 리턴하지 않고,'Disjunction'을 당신에게주고 싶습니다. 처음 두 개는' 문자열 ')의 일부입니다. –

+0

@EndeNeu EitherT를 시도했지만 여전히 컴파일 오류가 발생합니다. 컴파일 오류와 함께 업데이트 된 질문을 참조하십시오. 전에 DisjunctionT를 사용하고 있었는데 (이것은 EitherT의 래퍼 일뿐입니다) 동일한 결과가 있습니다. –

답변

6

. 첫 번째 방법은 모든 메서드가 작업 할 것으로 알고있는 스택 (이 경우 EitherT[Future, Int, ?])을 반환하거나 각 메서드가 고유 한 효과를 가장 정확하게 캡처하는 형식을 반환하도록 할 수 있습니다. 당신이 그들을 작곡 할 때 적절하게 얻으십시오.

첫 번째 방법은 사용법이 어떻게 보이는지 정확히 알면 구문 론적으로 편리하게 만들 수 있지만 후자의 방법은 더 유연하며 내 의견으로는 일반적으로 더 나은 선택입니다. 귀하의 경우는 다음과 같이 보일 것입니다 : 다음

import scalaz._, Scalaz._ 
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

def one(a: String): Disjunction[Int, String] = (a == "one").either("one").or(2) 
def two(a: String): Disjunction[Int, String] = (a == "two").either("two").or(3) 

def three(a: String): EitherT[Future, Int, String] = EitherT(
    Future(a == "three").map(_.either("three").or(4)) 
) 

def validate(a: String) = for { 
    e1 <- EitherT.fromDisjunction[Future](one(a)) 
    e2 <- EitherT.fromDisjunction[Future](two(a)) 
    e3 <- three(a) 
} yield (e1 |+| e2 |+| e3) 

그리고 :

scala> validate("one").run.foreach(println) 
-\/(3) 

scala> validate("x").run.foreach(println) 
-\/(2) 

을 어떤 이유로 당신이 한 경우에는 for -comprehension에서 사용하고 싶었 오래된 Future 일반, 당신을 .liftM[EitherT[?[_], String, ?]]으로 EitherT[Future, String, A]으로 들어갈 수 있습니다.

(가 성공하지 못할 것이기 때문에), 문자열 "one"에 동일하지 않을 수 있습니다 (이 방법은 아마 정말 유용하지 않습니다 것을 동시에 "two""three"을 참고하지만, 적어도 구성은 운동한다 .)

더 일반적으로 모나드 변압기 스택을 선택하는 방법에 대한

: 당신은 그냥 내부의 유형을 설정, Future[Disjunction[Int, ?]] 구체적으로, Future는 모나드 변압기가없는이 경우 EitherT[Future, Int, ?] 등이되도록 (이것은 암벽 횡단 아니다 및 차단하지 않고 FutureT을 구현하는 것은 불가능합니다. 따라서 어쨌든 내부로 이동해야합니다.