2014-02-24 44 views
4

Play的JSON library包括FunctorInvariant Functor播放JSON InvariantFunctor

我見過Functor前:

trait Functor[M[_]] extends Variant[M] { 

    def fmap[A, B](m: M[A], f: A => B): M[B] 

} 

但是,從概念上講,它爲什麼要爲InvariantFunctor提供兩種功能f1f2

trait InvariantFunctor[M[_]] extends Variant[M] { 

    def inmap[A, B](m: M[A], f1: A => B, f2: B => A): M[B] 

} 

回答

11

this answer我給的,爲什麼Writes是不是仿函數,也就是爲什麼如果我們有一個Writes[A]和功能A => B我們不能創造同樣的方式Writes[B]一個快速的解釋,我們可以同Reads

當我在回答說明,Writes不是一般的(協)函子,但它是一個逆變函子,這意味着,如果我們有一個Writes[A]和功能B => A,我們可以創建Writes[B]

Format涵括既ReadsWrites的功能,這意味着它既不是仿函數也不是逆變函子,但它是一個不變的算符(和它的真正的唯一一種與你會碰到一個不變的函子實例在Play中)。

要明白爲什麼會是這樣,假設我們有以下兩種類型:

case class Foo(i: Int, s: String) 
case class Bar(s: String, i: Int) 

並假設我們已經有了一個Format實例Foo

import play.api.libs.json._ 
import play.api.libs.functional.syntax._ 

implicit val fooFormat = Json.format[Foo] 

但是,不管是什麼原因我們不能用Bar以同樣的方式創建一個 - 我們想從Foo的那個中得到它。這是不夠的,我們要懂得從Foo,反之亦然創建Bar,但如果我們可以是雙向的,我們可以使用Format不變函子:

implicit val barFormat = fooFormat.inmap[Bar](
    foo => Bar(foo.s, foo.i), 
    bar => Foo(bar.i, bar.s) 
) 

這是因爲我們能想到的Format作爲一種雙向管道,允許我們投入JsValue並取出一些A,或放入該A並取出JsValue。如果我們想要將雙向管道Format[A]轉換成雙向管道Format[B],我們需要雙方適配器(即,A => BB => A)。