2017-02-18 93 views
5

我有以下的驗證邏輯:如何使用申請功能應用

def one(a : String) : Validation[String, Int] = 
    if (a == "one") { 
     Success(1) 
    } else { 
     Failure("Not One") 
    } 

    def two(a : String) : Validation[String, Int] = 
    if (a == "two") { 
     Success(2) 
    } else { 
     Failure("Not Two") 
    } 

    def validate (a : String) = (one(a) |@| two(a)){_ + _} 

按照Scalaz文檔:

/** 
    * DSL for constructing Applicative expressions. 
    * 
    * `(f1 |@| f2 |@| ... |@| fn)((v1, v2, ... vn) => ...)` is an alternative to `Apply[F].applyN(f1, f2, ..., fn)((v1, v2, ... vn) => ...)` 
    * 
    * `(f1 |@| f2 |@| ... |@| fn).tupled` is an alternative to `Apply[F].applyN(f1, f2, ..., fn)(TupleN.apply _)` 
    * 
    * Warning: each call to `|@|` leads to an allocation of wrapper object. For performance sensitive code, consider using 
    *   [[scalaz.Apply]]`#applyN` directly. 
    */ 

如何轉換的驗證功能使用apply2

回答

4

Validate的類型構造函數需要兩個參數,但Apply只能由arity one的類型構造函數進行參數化。你需要一種稱爲拉姆達特招這使我們能夠討好的類型定義:

def validate(a : String) = Apply[({type λ[Int] = Validation[String, Int]})#λ].apply2(one(a), two(a)){_ + _} 
+0

是的,我注意到應用正在採取一個元數的類型構造,但由於偶然驗證需要兩個。 –

+1

是的..這是一個常見的技巧,非常醜陋,但這就是現在的做法。基本上你創建了一個臨時類型(lambda類型),它接受一個參數,這就是'Apply'所需要的,它創建了一個帶有兩個泛型類型的新類型,然後你使用#來應用該類型(現在就好了採取我們剛剛創建的)。請注意,我將這兩種類型硬編碼爲String和Int。查看例如[this](http://like-a-boss.net/2014/09/27/type-lambda-in-scala.html)或[this](https://blog.adilakhter.com/2015/02/18 /施加-scalas型的λ/)。 – slouc