日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

scala with cats 之 Contravariant Functors and Invariant Functors

發布時間:2024/3/13 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 scala with cats 之 Contravariant Functors and Invariant Functors 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Contravariant Functors

概述

Functor的意思是,如果有個F[A]和函數A=>B,那么就能得到一個F[B]。而Contravariant Functors的意思是,如果有個F[B],然后有個函數A => B,那我們就能得到一個F[A]。

用途

假如我們有個類型類,比如說

trait Semigroup[A]{def combine(x:A,y:A):A }

我們經常要定義各種實例,比如Semigroup[Int],Semigroup[String],比如Semigroup[Boolean]。這些都是cats內置的實例。如果我們自己有個類型Box,我們要自己定義Semigroup[Box]實例??墒亲约憾x實例實在太麻煩,能不能根據現有的實例轉化成新的實例呢?當然是是可以的。

示例

還是拿cats里面的例子講解。
先定義類型類,然后給個contramap實現:

trait Printable[A] {def format(value: A): Stringdef contramap[B](func: B => A): Printable[B] =new Printable[B] {def format(value: B): String =self.format(func(value))} }

理論上contramap并不是Printable本身的能力,其實應該屬于Contravariant[F[_]]的能力。所以單獨實現一個Contravariant[Printable]實例比較好,類似下面的Contravariant[Show]:

implicit val catsContravariantForShow: Contravariant[Show] = new Contravariant[Show] {def contramap[A, B](fa: Show[A])(f: B => A): Show[B] =show[B]((fa.show _).compose(f))}
  • 假設我們已經有兩個實例Printable[Int]和Printable[Boolean]
  • implicit val stringPrintable: Printable[String] =new Printable[String] {def format(value: String): String =s"'${value}'"}implicit val booleanPrintable: Printable[Boolean] =new Printable[Boolean] {def format(value: Boolean): String =if(value) "yes" else "no"}
  • 現在有個case class
  • // Box有個類型參數 final case class Box[A](value: A)

    3.定義Printable[Box[A]]的實例

    // 方法一 自己實現 implicit def boxPrintable[A](implicit p: Printable[A] ): Printable[Box[A]] =new Printable[Box[A]] {def format(box: Box[A]): String =p.format(box.value)} // 方法二 通過contramap方法實現,就不必每次都去寫很多模板代碼implicit def boxPrintable[A](implicit p: Printable[A]): Printable[Box[A]] =p.contramap[Box[A]](_.value)

    Invariant Functors

    概述

    Invariant Functors 說起來雖然神秘,但是在scala的領域確是非常的常見。很多數據庫的包,比如slick,quill等。經常我們要把scala程序里面定義的case class 轉為字符串寫到數據庫,還需要把數據庫里面的字符串轉為程序需要的case class。

    作為標準庫的設計者會明白,case class 是無限的,但是組成case class 的元素時有限的,就是 scala 的基本內置類型。而數據庫只需要和這些基本內置類型對接好就行了,用戶負責將case class 轉為基本內置類型。

    示例

    假設現在設計一個標志庫,和數據庫交互方法如下(轉成字符串就算寫入數據庫):

    def encode[A](value: A)(implicit c: Codec[A]): String =c.encode(value)def decode[A](value: String)(implicit c: Codec[A]): A =c.decode(value)

    抽象Codec[A]

    使用encode和decode,理論上能把任意的類型A寫入數據庫,也能把數據庫的數據讀成任意類型A,只需要提供類型A的Codec實例即可。Codec簽名如下:

    trait Codec[A] { self =>def encode(value: A): Stringdef decode(value: String): Adef imap[B](dec: A => B, enc: B => A): Codec[B] = {new Codec[B] {def encode(value: B): String =self.encode(enc(value))def decode(value: String): B =dec(self.decode(value))}} }

    添加內置實例

    前面說過,case class 是無限的,但是組成case class的元素是有限的,現在在標準庫中添加這些有限的內置示例。

    implicit val stringCodec: Codec[String] =new Codec[String] {def encode(value: String): String = valuedef decode(value: String): String = value}implicit val doubleCodec: Codec[Double] =stringCodec.imap[Double](_.toDouble, _.toString)implicit val intCodec: Codec[Int] =stringCodec.imap(_.toInt, _.toString)implicit val booleanCodec: Codec[Boolean] =stringCodec.imap(_.toBoolean, _.toString)

    用戶自己實現自己的case class 實例

    implicit def boxCodec[A](implicit c: Codec[A]): Codec[Box[A]] =c.imap[Box[A]](Box(_), _.value)

    將自己的實例寫入數據庫或者從數據庫讀出來(假設轉成字符串就算寫入數據庫)

    encode(Box(123.4)) // res13: String = "123.4" decode[Box[Double]]("123.4") // res14: Box[Double] = Box(123.4)

    總結

    以上是生活随笔為你收集整理的scala with cats 之 Contravariant Functors and Invariant Functors的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。