2015/07/23

[ScaVa->Scala] Scalaz Validation與Either(Disjunction)的另個選擇 - Scalactic Or

前言

之前寫過了Scalaz的Either(Disjunction)與Validation兩篇,今天老闆看到我的blog後,跟我說"寫一下Scalactic啊!",所以我就來寫了!!

Scalactic

Scalactic這個東西,是從ScalaTest發展出來的,為了能方便直接"單獨"使用在Production的環境,當然ScalaTest裡面有包含了完整的Scalactic,如果你有使用ScalaTest的話,可以直接使用Scalactic。

至於Scalaz和Scalactic的差異,細節可以參考這個影片(Comparing Functional Error Handling in Scalaz and Scalactic),簡單來說,有些觀念上的不同(沒有誰對誰錯),想讓使用上更明暸簡單,不用分Disjunction和Validation兩種型態,提供更單純的型態,而且在描述上可以更直覺。

概念上大自整理如下:

Or與其子類別Good與Bad

sealed abstract class Or[+G, +B] extends AnyRef

final case class Good[+G, +B](g: G) extends Or[G, B] with Product with Serializable

final case class Bad[+G, +B](b: B) extends Or[G, B] with Product with Serializable

Or就像是Either或Disjunction,因為Scalactic直接定義了Good和Bad,所以比Scala原生的Either用起來簡單,也比Disjunction看起來清楚。

而且Or的Bad子類別可以讓你累積errors,就像是Scalaz的Validation的功能一樣,比較有趣的是,開發的人覺得左邊的才是Good,右邊的是Bad,跟Scalaz的Validation相反。(分明就是讓大家用習慣後很難換去用另一種嘛!!!)

Every與其子類別One與Many

sealed abstract class Every[+T] extends PartialFunction[Int, T]

final case class One[+T](loneElement: T) extends Every[T] with Product with Serializable

final case class Many[+T](firstElement: T, secondElement: T, otherElements: T*) extends Every[T] with Product with Serializable

Every是一個有順序性的、不可修改的、不能是空的元素的集合,One是繼承他,但裡面只有一個值,Many也繼承他,而裡面是兩個以上的值。

這裡的定義,其實就是為了讓Or裡的Bad可以是單一值與多值,就像是Validation中的accumulating errors的實作Non-Empty-List一樣,不過Scalactic是把這兩種合在一起(都叫Every),而不像Scalaz的Validation與ValidationNel(其實是Validation[NonEmptyList[E]])是兩種不同的型態。

Validation與其子類別Pass與Fail

sealed trait Validation[+E] extends AnyRef

object Pass extends Validation[Nothing] with Product with Serializable

case class Fail[E](error: E) extends Validation[E] with Product with Serializable

在使用Scalaz的Validation或是Either時,在用for或filter的時候,我們會不知道他是什麼型態,所以寫起來還要去判斷型態再來處理,這樣其實蠻麻煩的。

而Scalactic在使用Or型態的for或是filter的時候,讓你透過Closure在裡面可以回傳Pass或是Fail。可以把Validation想像成是Option,而Pass其實是None,Fail的時候才有值,這樣用起來不是更簡單嗎?

Accumulation

這裡面實作了accumulating errors的一些方法,包含了withGood, when, combined, validatedBy, zip,就是幫你把上面提到的Or, Every, Validation做轉換、或混在一起用的時候的工具。
以下是使用Scalactic試寫的一段HTTP Request參數驗證 (亂寫的,邏輯不要太認真,主要是看用法)


參考資料


張貼留言

My World