當我們需要定義一些對應高階類型進行相互類型轉換的操作函數時,我們發現scala語言並不提供能定義這種函數的支持。舉例來說:如果我們希望定義一個函數把對於任何T值的Option[T]轉換成List[T]的話,我們可能這樣定義: 1 def toList[T](opt: Option[T]): List
當我們需要定義一些對應高階類型進行相互類型轉換的操作函數時,我們發現scala語言並不提供能定義這種函數的支持。舉例來說:如果我們希望定義一個函數把對於任何T值的Option[T]轉換成List[T]的話,我們可能這樣定義:
1 def toList[T](opt: Option[T]): List[T] = opt.toList
2 //> toList: [T](opt: Option[T])List[T]
3 val hOptFun = toList _ //> hOptFun : Option[Nothing] => List[Nothing] = <function1>
看看hOptFun的類型:Option[Nothing] => List[Nothing], 即我們無法對T的類型進行限定。如果我們使用hOptFun:
1 hOptFun(None) //> res0: List[Nothing] = List()
2 //hOptFun(Some(10)) //type mismatch; found : Int(10) required: Nothing
3 //hOptFun(Some("hi")) //type mismatch; found : String("hi") required: Nothing
結果是無法正常使用hOptFun。這就證明瞭scala是不支持高階類型轉換函數的。一個可行的方法是通過一個特殊類來實現高階類型轉換,這就是scalaz的NaturalTransformation類型的主要功能。scalaz的NaturalTransformation類型是這樣定義的:scalaz/NaturalTransformation.scala
/** A universally quantified function, usually written as `F ~> G`,
* for symmetry with `A => B`.
*
* Can be used to encode first-class functor transformations in the
* same way functions encode first-class concrete value morphisms;
* for example, `sequence` from [[scalaz.Traverse]] and `cosequence`
* from [[scalaz.Distributive]] give rise to `([a]T[A[a]]) ~>
* ([a]A[T[a]])`, for varying `A` and `T` constraints.
*/
trait NaturalTransformation[-F[_], +G[_]] {
self =>
def apply[A](fa: F[A]): G[A]
...
我們只需要實現apply就行了:
1 val optionToListTrans = new (Option ~> List) {
2 def apply[T](opt: Option[T]): List[T] = opt.toList
3 } //> optionToListTrans : scalaz.~>[Option,List] = Exercises.naturaltransform$$an
4 //| onfun$main$1$$anon$1@2d554825
5 optionToListTrans(None) //> res1: List[Nothing] = List()
6 optionToListTrans(Some("hi")) //> res2: List[String] = List(hi)
7 optionToListTrans.apply(3.some) //> res3: List[Int] = List(3)
從optiontoListTrans.apply可以看出我們實際上直接調用了那個按我們要求實現的apply方法。換句話說:如果我們需要把F[A]與G[A]對應,我們可以通過實現apply的方式來表達它們具體的對應方式,這個apply方法就可以實現高階類型的相互轉換。