ãã®èšäºã§ã¯ãã«ããŽãªçè«ãšScalaã®é£è§£ãªèšèªã¡ã«ããºã ã䜿çšããã«ã2ã€ã®éèŠãªæŠå¿µãæ€èšããŸãã
- å ±å€ãã¡ã³ã¯ã¿ãŒ
- ã³ã³ãã©ããªã¢ã³ããã¡ã³ã¯ã¿ãŒ
- ææ°ïŒäžå€ïŒãã¡ã³ ã¯ã¿ãŒ ã BiFunctor ã ProFunctor
- Applicative Functor ã Arrow ã Monad / Co-Monad
- ã¢ããå€æåš ã ã¯ã©ã€ã¹ãª ã èªç¶å€æ
ã«ããŽãªãŒçšèªã®èµ·æºã«ã€ããŠèª¬æããã«ããŽãªãŒæœè±¡åã®å®è£ ã«ãããèšèªã¡ã«ããºã ã®åœ¹å²ã瀺ããScalaæšæºã©ã€ãã©ãªãŒããã®ããã€ãã®å ±å€ïŒ Option ã Try ã Future ã List ã Parser ïŒããã³åå€ïŒãã¡ã³ãã£ã³ã° ã Equiv ïŒãã¡ã³ã¯ã¿ãŒãæ€èšããŸãã
ãã«ããŽãªã·ãªãŒãºãã®æåã®èšäºïŒ
- Scalaã®FPïŒãã¡ã³ã¯ã¿ãŒãšã¯ïŒ
- Scalaã®FPïŒInvariant Functor
Scalaãæ°åŠãé¢æ°åããã°ã©ãã³ã°ã®äžçãããã«è©³ããç¥ãããå Žåã¯ã Scala for Java Developersãªã³ã©ã€ã³ã³ãŒã¹ããè©Šããã ããïŒãããª+ãã¹ããäŸ¡æ Œã®ããã25ïŒ ïŒïŒã
- æœè±¡åã®èšèªã¡ã«ããºã ã«ã€ããŠ
- ã«ããŽãªãŒçè«ãšHaskellã«ã€ããŠ
- å ±å€ãã¡ã³ã¯ã¿ãŒãšã¯
- å ±å€ãã¡ã³ã¯ã¿ãŒã®äŸ
- å ±å€é¢æ°ïŒã¢ã€ãã³ãã£ãã£æ³
- å ±å€ãã¡ã³ã¯ã¿ãŒïŒåææ³
- å ±å€ãã¡ã³ã¯ã¿ãŒïŒæé©åã«äœ¿çš
- åå€ãã¡ã³ã¯ã¿ãŒãšã¯
- åå€ãã¡ã³ã¯ã¿ãŒã®äŸ
- åå€é¢æ°ïŒã¢ã€ãã³ãã£ãã£æ³
- åå€ãã¡ã³ã¯ã¿ãŒïŒåææ³
- 次ã¯ïŒ
æœè±¡åã®èšèªã¡ã«ããºã ã«ã€ããŠ
åºæ¬çã«æ°ããããã°ã©ãã³ã°èšèªãžã®æ²¡å ¥ã«ã¯ã以äžã®åŠç¿ãå«ãŸããŸãã
- æ°ããã¿ã€ãã®æœè±¡åã®ããã®èšèªã¡ã«ããºã ã
- ãããã®ã¿ã€ãã®æœè±¡åã䜿çšãããå žåçãªã€ãã£ãªã /ãã¿ãŒã³ã
äŸïŒOOPã¯ãã¯ã©ã¹ãã€ã³ã¹ã¿ã³ã¹ãç¶æ¿ãããªã¢ãŒãã£ãºã ãã«ãã»ã«åãå§ä»»ã...ããã³GoFèšèšãã¿ãŒã³ã®æŠå¿µã調æ»ããŸãããã®èšèšãã¿ãŒã³ã§ã¯ããã®ãããªããŸããŸãªæœè±¡åã¡ã«ããºã ããã¹ãŠäœ¿çšãããŸãã
ç§ã®æèŠã§ã¯ã移è¡Java => Scalaã®äž»ãªåé¡ã¯ãããã°ã©ããŒãæ°ããæœè±¡åã¡ã«ããºã ïŒããé«ãçš®é¡ã®ãžã§ããªãã¯ããã¹äŸååãåã¯ã©ã¹ããã¯ããªã©ïŒãåŠç¿ããªãããšã§ãã ã
ãããŠããæœè±¡åã®å¯Ÿè±¡ãïŒãã¡ã³ã¯ã¿ãŒãã¢ãããã¢ãã€ããåŸå±åãªã©ïŒã®è©±ãå§ãŸããšããã«ãçŸä»£æ°åŠïŒã«ããŽãªãŒçè«ãæœè±¡ä»£æ°ãæ°çè«çåŠïŒã®çè«å®¶ãçŸãã ãããŒããããã¹ãŠã®ããŒã¹ãã²ã£ããè¿ããŸããã ããã°ã©ããŒã®èŠ³ç¹ããã¯ãæ°åŠè ã¯ãã°ãã°ãã«ããŽãªãŒã®å°æ¥ã®èšŒäººæŽŸ/åã®ãã¢ãããŒçè«/æ§æã®èšç®ã®çä¿¡è ã®ããã«æ¯ãèããŸãïŒãç§ãã¡ã®èšèªã§ããšèšã£ãŠããã°ã©ãã³ã°ã®åéããå ·äœçãªäŸãäžããã®ã§ã¯ãªãã圌ãã¯æœè±¡æ°åŠã®èŠ³ç¹ãã泚ãã§ã圌ãã®è人ãåç §ããŸãããã¹ã
ãã®èšäºã§ã¯ããã¡ã³ã¯ã¿ãŒïŒå ±å€ããã³åå€ïŒã¯ãã«ããŽãªãŒçè«ã«é Œããã«åºæ¬çãªScalaã®ç¹åŸŽã®ã¿ã«åºã¥ããŠåæãããŸãã ããé«ãçš®é¡ã® åã¯ã©ã¹ãšãžã§ããªãã¯ã¯äœ¿çšãããŸããïŒããšãã°ã Scalazã©ã€ãã©ãªã®äœæè ã¯ã scala.scalaz.Functor + scala.scalaz.Contravariant ãCatsïŒ scala.cats.Functor + cats.functor.Contravariant ãAlgebirdïŒ comã twitter.algebird.Functor ïŒã å€ãã®å Žåãã€ãã£ãªã ã®å ±å€ãã¡ã³ã¯ã¿ãŒãšåå€ãã¡ã³ã¯ã¿ãŒã«å¯Ÿå¿ããåã®ååã§ã¯ãçç¥åïŒãã¡ã³ã¯ã¿ãŒãšåå€ïŒã䜿çšãããããšã«æ³šæããŠãã ããã
äžè¬çã«ãScalaã®é¢æ°åããã°ã©ãã³ã°ïŒL2ãL3ã¬ãã«ïŒã¯ãJavaã«å¯ŸããŠããã€ãã®æ¹åã®ãªãã»ããã§ãïŒ3ã€åç §ïŒã ããã«ããªãã»ããã¯4ã€ã®ãã³ã³ããŒãã³ããã«ãã£ãŠåæã«ç¹åŸŽä»ããããŸãã
- æ°ããããã°ã©ãã³ã°ãã³ãã¬ãŒã/ã€ãã£ãªã /çç ã
- ãããã®ã€ãã£ãªã ãå®è£ ããããã®Scalaã®æ°ããèšèªãšã³ãžã³ã
- èšèªã¡ã«ããºã ã«åºã¥ãã€ãã£ãªã ã®å®è£ ãåããæ°ããScalaã©ã€ãã©ãªã
- ã€ãã£ãªã ã®éèŠãªã¢ã€ãã¢ã®ãœãŒã¹ãšããŠæ©èœããæ°åŠã®æ°ããã»ã¯ã·ã§ã³ã
ããã«æ³šæããå¿ èŠããããŸã
- ã€ãã£ãªã ãåŠã¶ããšã¯å¿ é ã§ã ïŒããããFPã³ã¢ãã§ãïŒã
- æœè±¡åã®èšèªã¡ã«ããºã ã®åŠç¿-åå©çšã«é©ããã€ãã£ãªã ãå®è£ ããããã«å®çšŒåã¢ãŒãã§å¿ èŠã§ã ã
- å žåçãªScalaæ©èœã©ã€ãã©ãªã®ç 究- ã§ããã°ãæ¢ã«äœæãããããã°ãããã€ãã£ãªã ãåå©çšããããã®å®çšŒåã¢ãŒãã§ã
- æ°åŠã®é¢é£ã»ã¯ã·ã§ã³ãå匷ããããšã¯ãã€ãã£ãªã ãç解ããã䜿çšãããããããã«å¿ èŠã§ã¯ãããŸãã ã
å°ãªããšããã3ã€ã®ã·ããããåºå¥ã§ããŸããã«ããŽãªãŒã代æ°ãè«çïŒæ°åŠã®ã»ã¯ã·ã§ã³ã®ååã«ããïŒ
ã€ãã£ãªã FP | Scalaã®ã¢ | Scalaã©ã€ãã©ãª | æ°åŠã®ã»ã¯ã·ã§ã³ |
---|---|---|---|
å ±å€ãã¡ã³ã¯ã¿ãŒãé©çšãã¡ã³ã¯ã¿ãŒãã¢ãããç¢å° | åã¯ã©ã¹ãäžäœã®ãžã§ããªã㯠| ã¹ã«ã©ãºãç« | ã«ããŽãªãŒçè« |
äŸåãã¢ãäŸåé¢æ° | ãã¹äŸåå | 圢ã®ãªã | æ°åŠçè«ç |
ã¢ãã€ããã°ã«ãŒãããã£ãŒã«ãããªã³ã° | åã¯ã©ã¹ãäžäœã®ãžã§ããªã㯠| ã¢ã«ãžããŒããã¹ãã€ã¢ | ä»£æ° |
èŠããã«ïŒ
- äžäœçã®ãžã§ããªãã¯ã¯ ãåå©çšå¯èœãªæœè±¡åïŒå ±å€ãã¡ã³ã¯ã¿ãŒãªã©ïŒãæ§ç¯ããããã«äœ¿çšãããŸãã ãã®å ŽåãOOPã§ã¯ãå ç¥ã¿ã€ããéåžžäœæãããŸãã
- åã¯ã©ã¹ã¯ãã³ãŒãã«ãæœè±¡åãé©çšãããããã«äœ¿çšãããŸãïŒãŠãŒã¶ãŒã¯ã©ã¹ã¯å ±å€ãã¡ã³ã¯ã¿ã«ããªããŸããïŒã ãã®å ŽåãOOPã§ã¯ããããã¯éåžžãç¥å ã®æœè±¡åããç¶æ¿ãããŸãã
ç§ãã¡ã®äŸã§ã¯ãããé«ãking +åã¯ã©ã¹ã®ãžã§ããªãã¯ã䜿çšããªããããåå©çšã«é©åããŸããïŒãããŠãããã§ã®ãå€ãè¯ãOOPããªãã¯ãã¯ç¹ã«é©ããŠããŸããïŒã ããããåå©çšã®æºåãã§ããŠããªããŠãããã®äŸã¯ã€ãã£ãªã ã®æ¬è³ªããã瀺ããŠããŸãã
ã«ããŽãªãŒçè«ãšHaskellã«ã€ããŠ
20äžçŽåã°ã«ãæ°åŠã®æ°ããåéãçãŸããŸãã-ã«ããŽãªãŒçè«ïŒæ°åŠè èªèº«ããã°ãã°ãæœè±¡çãªãã³ã»ã³ã¹ããšåŒã¶ããšã«æ³šæããŠãã ããïŒã ã«ããŽãªçè«ã¯ãæ°åŠã®å€ãã®åºæ¬é åïŒéåè«ãããããžãŒãæ©èœåæãªã©ïŒã§åºã䜿çšãããŠããäžè¬çãªã¢ã€ãã¢/æ§é ããæ¥ãŠãããçŸåšããã¹ãŠã®æ°åŠã®åºç€/åºç€ã§ãããšäž»åŒµããŠããŸãïŒæ§ç¯ããéåè«ã®çŸ€éïŒ 20äžçŽåé ããã®æ°åŠïŒã
ããããéåè«ãéåèªäœïŒèŠçŽ ãéåã®æäœãéåã®ã«ãŒãã£ããªãã£ãæ§é ãæã€éåïŒé åºä»ãéåãéšåé åºéåïŒãªã©ïŒã«çŠç¹ãåãããŠããå Žåãéåã®ãããã³ã°ïŒéåããéåãžã®é¢æ°ïŒã¯èæ¯ã«ãããã«ããŽãªãŒçè«ã§ã¯ãåºç€ã¯ã«ããŽãªãŒã§ãããç°¡åã«èšãã°ã category = set + mappingsã§ãã ãããã³ã°ã¯é¢æ°ã®å矩èªã§ãïŒããæ£ç¢ºã«ã¯ããããã³ã°=åŒæ°ããå€ã«çŽæ¥ã移åãããæé ãæå®ããã«å€ã®ãã¡ã€ã³ã®èŠçŽ ã®å®çŸ©ã®ãã¡ã€ã³ã®èŠçŽ ã«å¯Ÿå¿ããããã³ã°=ããŒãã«ã§æå®ãããé¢æ°ããããã³ã°= fã®æå³ã®é¢æ°ã®ãå€éšã€ã³ã¿ãŒãã§ã€ã¹ã ïŒA => B ãå éšå®è£ ãïŒé¢æ°æ¬äœïŒãæå®ããã«ïŒãããã§ãé¢æ°èªäœã®ãããªåŒ·èª¿ã¯ãé¢æ°åããã°ã©ãã³ã°ã«ãšã£ãŠéåžžã«éèŠã§ããããšãããããŸãã
ãããã³ã°ã«éäžãããšãè±å¯ãªæ©èœçæœè±¡åïŒãã¡ã³ã¯ã¿ãŒãã¢ãããªã©ïŒãçºçãããããã®æœè±¡åã¯é¢æ°åããã°ã©ãã³ã°èšèªïŒHaskellã§æãæåãªå®è£ ïŒã«è»¢éãããŸããã Scalaã®å€æãïŒ2005幎ãã2010幎ïŒã¯Haskellã®å€æãïŒ1990幎ãã1995幎ïŒã«æ¯ã¹ãŠ15幎éçžæ®ºãããå€ãã®ããšã¯HaskellããScalaã«æ¢è£œã§è»¢éãããŸãã ãããã£ãŠãScalaããã°ã©ããŒã«ãšã£ãŠã¯ãã«ããŽãªãŒçè«èªäœã§ã¯ãªããã«ããŽãªãŒæœè±¡åã®äž»ãªãœãŒã¹ãšããŠHaskellã®å®è£ ãæ±ãããšãããéèŠã§ãã ããã¯ãã«ããŽãªãŒçè«=> Haskellã®è»¢éäžã«ãå€ãã®éèŠãªè©³çŽ°ãå€æŽãæ¶å€±ããŸãã¯è¿œå ããããšããäºå®ã«ãããã®ã§ãã ããã°ã©ããŒã«ãšã£ãŠéèŠã§ãããæ°åŠè ã«ãšã£ãŠã¯äºæ¬¡çãªãã®ã§ãã
移è¡ã®äŸã次ã«ç€ºããŸãã
- ã«ããŽãªãŒçè«ïŒ
- ãã¹ã±ã«ïŒ
- ScalaïŒScalazã©ã€ãã©ãªïŒ
å ±å€ãã¡ã³ã¯ã¿ãŒãšã¯
äžéšã®èè ã¯ã Covariant Functorãã³ã³ãããŒã«ããããšãæšå¥šããŠããŸã ïŒããæ£ç¢ºã«ã¯ãå ±å€Functorã¯ããããã³ã³ãããŒã®ååãã§ãïŒã ãã®æ¯phorãæãåºãããšããå§ãããŸãããå®çŸ©ã§ã¯ãªãæ¯preciselyãšããŠæ£ç¢ºã«æ±ããŸãã
Covariant Functorããèšç®ã³ã³ããã¹ããã§ããä»ã®äºº ã ããã¯çç£çãªã¢ãããŒãã§ãããã³ã³ã»ãããå®å šã«ãã¹ã¿ãŒãããæ倧éã«æŽ»çšãããããšããå Žåã«åœ¹ç«ã¡ãŸãã ä»ã®ãšããç¡èŠããŠãã ããã
ããã«ä»ã®äººã¯ããããæ§æçãªã¢ãããŒãããææ¡ããŠããŸãã Covariant Functorã¯ãç¹å®ã®ã¡ãœãããæã€ç¹å®ã®ã¿ã€ãã§ãã ã¡ãœããã¯ç¹å®ã®ã«ãŒã«ïŒ2ã€ïŒã«æºæ ããå¿ èŠããããŸãã
ãæ§æã¢ãããŒããã䜿çšããã³ã³ãã/ã¹ãã¬ãŒãžã®ã¡ã¿ãã¡ãŒã䜿çšããããšããå§ãããŸãã
ãæ§æçã¢ãããŒããã®èŠ³ç¹ããèŠããšãå ±å€ãã¡ã³ã¯ã¿ãŒã¯ã次ã®ã·ã°ããã£ãæã€ã¡ãœããïŒ mapãšåŒã¶ïŒãæã€åãã©ã¡ãŒã¿ãŒãæã€ä»»æã®åïŒ XãšåŒã¶ïŒãæã€åã§ãã
trait X[T] { def map(f: T => R): X[R] }
éèŠïŒãã®ç¹æ§ããç¶æ¿ããã®ã§ã¯ãªããé¡äŒŒã®ã¿ã€ããæ¢ããŸãã
ãæ§æçã¢ãããŒããã¯ãå€ãã®ã«ããŽãªæ§é ãäžè¬çãªã¹ããŒã ã«ãŸãšããããšãã§ãããšããç¹ã§åªããŠããŸã
trait X[T] { // covariant functor (functor) def map[R](f: T => R): X[R] // contravariant functor (contravariant) def contramap[R](f: R => T): X[R] // exponential functor (invariant functor) def xmap[R](f: (T => R, R => T)): X[R] // applicative functor def apply[R](f: X[T => R]): X[R] // monad def flatMap[R](f: T => X[R]): X[R] // comonad def coflatMap[R](f: X[T] => R): X[R] }
éèŠïŒããã«ç€ºãããŠããã¡ãœããã¯ãããã€ãã®æœè±¡åã«å¿ èŠãªãã®ïŒå ±å€/åå€/ææ°é¢æ°ïŒãšãä»ïŒé©çšé¢æ°ãã¢ãããã³ã¢ãïŒã«å¿ èŠãªã¡ãœããã®1ã€ã§ãã
å ±å€ãã¡ã³ã¯ã¿ãŒã®äŸ
æ¢ã«ScalaïŒãŸãã¯Java 8ïŒã§ããã°ã©ãã³ã°ãéå§ããŠãã人ã¯ãããã«å ±å€ãã¡ã³ã¯ã¿ãŒã§ããå€ãã®ãã³ã³ãããŒã¿ã€ããã«ååãä»ããããšãã§ããŸãã
ãªãã·ã§ã³
import java.lang.Integer.toHexString object Demo extends App { val k: Option[Int] = Option(100500) val s: Option[String] = k map toHexString }
ãŸãã¯äººçã«å°ãè¿ã
import java.lang.Integer.toHexString object Demo extends App { val k: Option[Int] = Map("A" -> 0, "B" -> 1).get("C") val s: Option[String] = s map toHexString }
ãè©Šããã ãã
import java.lang.Integer.toHexString import scala.util.Try object Demo App { val k: Try[Int] = Try(100500) val s: Try[String] = k map toHexString }
ãŸãã¯äººçã«å°ãè¿ã
import java.lang.Integer.toHexString import scala.util.Try object Demo extends App { def f(x: Int, y: Int): Try[Int] = Try(x / y) val s: Try[String] = f(1, 0) map toHexString }
æªæ¥
import java.lang.Integer.toHexString import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future object Demo extends App { val k: Future[Int] = Future(100500) val s: Future[String] = k map toHexString }
ãŸãã¯äººçã«å°ãè¿ã
import java.lang.Integer.toHexString import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future object Demo extends App { def calc: Int = (0 to 1000000000).sum val k: Future[Int] = Future(calc) val s: Future[String] = k map toHexString }
äžèŠ§
import java.lang.Integer.toHexString object Demo extends App { val k: List[Int] = List(0, 42, 100500) val s: List[String] = k map toHexString }
ããŒãµãŒ
import java.lang.Integer.toHexString import scala.util.parsing.combinator._ object Demo extends RegexParsers with App { val k: Parser[Int] = """(0|[1-9]\d*)""".r ^^ { _.toInt } val s: Parser[String] = k map toHexString println(parseAll(k, "255")) println(parseAll(s, "255")) } >> [1.4] parsed: 255 >> [1.4] parsed: FF
äžè¬ã«ãäŸãšããŠå€æãããšãã³ã³ãããšããŠã®å ±å€ãã¡ã³ã¯ã¿ãŒã®æ¯phorã¯æ©èœããŸãã æ¬åœã«
- ãªãã·ã§ã³-1ã€ã®èŠçŽ ã®ãã³ã³ããã®ããã«ããäœããååšããå¯èœæ§ãããïŒäžéšïŒãŸãã¯ããã§ãªãå¯èœæ§ãããïŒãªãïŒ
- è©ŠããŠã¿ãŠãã ãã-ããèŠçŽ ã«ãã³ã³ããã®ããã«ããã©ãã«ãããïŒæåïŒãŸãã¯ããã§ãªããããããŸããïŒå€±æãããæ£ç¢ºã«ã¯ãèŠçŽ ã®ä»£ããã«äŸå€ããããŸãïŒã
- æªæ¥-äœãããã§ã«ãããããããªããããããããã€ããŠãããããããªããäŸå€ãæ¢ã«ããããŸãã¯äŸå€ããããã€ãããŸãã¯æ±ºããŠãããã€ããªããã³ã³ããã®ãããªãèŠçŽ ã
- ãªã¹ã-0ãNåã®èŠçŽ ãããã³ã³ãã
- ããŒãµãŒã¯ããã§ã¯ããå°ãè€éã§ãäœããæ ŒçŽããããŠããŸãããããŒãµãŒã¯æååããããŒã¿ãæœåºããæ¹æ³ã§ãã ãã ããããŒãµãŒã¯ããŒã¿ãœãŒã¹ã§ããããã®ç¹ã§ã¯ã³ã³ãããŒã«äŒŒãŠããŸãã
å ±å€ãã¡ã³ã¯ã¿ãŒã¯ãç¹å®ã®ã·ã°ããã£ãæã€ã¡ãœããã®ååšã ãã§ãªãã2ã€ã®ã«ãŒã«ã®å±¥è¡ã§ããããŸãã ããã§ã®æ°åŠè ã¯éåžžã«ããŽãªãŒçè«ãåç §ãããããã®èŠåã¯ãã¡ã³ã¯ã¿ãŒãã«ããŽãªãŒæºååã§ãããšããäºå®ã®çµæã§ãããšèšããŸããã€ãŸããæ§é ãä¿æããã«ããŽãªãŒãžã®ã«ããŽãªãŒã®ãããã³ã°ã§ãïŒãããŠåäžç¢å°èŠçŽ ã¯ã«ããŽãªãŒæ§é ã®äžéšã§ãïŒæçåèŠåïŒããã³ç¢å°ã®æ§æèŠåïŒæ§ææ³ïŒïŒã
ãã®ã¢ãããŒãã¯ãäžè¬çã«ããã°ã©ãã³ã°ã§ã¯éçç£çã§ãã é¢æ°åããã°ã©ãã³ã°ã§ã¯ãæ©èœãç¶æããªããïŒéåžžã¯æé©åã®ç®çã§ïŒããã°ã©ã ãå€æããããã«ãããã2ã€ã®ã«ãŒã«ãå¿ èŠã§ããããšãèæ ®ããŠãã ããã
å ±å€é¢æ°ïŒã¢ã€ãã³ãã£ãã£æ³
å ±å€ã®æ¥œãããã¡ã³ã¯ã¿ãŒã®å Žåã次ã®ã«ãŒã«IdentityLaw.case0ïŒfunïŒãåäžã«å®è¡ããå¿ èŠããããŸã-IdentityLaw.case1ïŒfunïŒãšåãã§ãã
object IdentityLaw { def case0[T](fun: Functor[T]): Functor[T] = identity(fun) def case1[T](fun: Functor[T]): Functor[T] = fun.map(identity) }
ããã§ãidentityã¯Predef.scalaããã®å€æ çãªåäžæ§é¢æ°ïŒåäœé¢æ°ïŒã§ã
object Predef ... { def identity[A](x: A): A = x ... }
ããªãç°¡åã«-fun.mapïŒidentityïŒã¯ãã¡ã³ã¯ã¿ãŒå ã®äœãå€æŽãã¹ãã§ã¯ãããŸããã
ããã¯ãããŒãžã§ã³ãä¿åããåãã£ã¹ãã¬ã€ã§ããŒãžã§ã³ãå¢ããã³ã³ããããå ±å€ãã¡ã³ã¯ã¿ãŒã®äžäœã«å¯Ÿå¿ããªãããšãæå³ããŸã
// - class Holder[T](value: T, ver: Int = 0) { def map[R](f: T => R): Holder[R] = new Holder[R](f(value), ver + 1) }
衚瀺æäœã®åæ°ããã«ãŠã³ããããããïŒã¢ã€ãã³ãã£ãã£é¢æ°ã«ãã衚瀺ãïŒã
ãããããã®ãããªã³ãŒãã¯ãã¡ã³ã¯ã¿ãŒã®æåã®ã«ãŒã«ã«å¯Ÿå¿ããŠããŸãïŒ2çªç®ã®ã«ãŒã«ã«ã察å¿ããŠããŸãïŒã
// - class Holder[T](value: T, ver: Int = 0) { def map[R](f: T => R): Holder[R] = new Holder[R](f(value), ver) }
ããã§ã¯ãããŒãžã§ã³ã¯ããŒã¿ã«åçŽã«æ·»ä»ããã衚瀺æã«åžžã«ä»éããŸãã
å ±å€ãã¡ã³ã¯ã¿ãŒïŒåææ³
å ±å€ãã¡ã³ã¯ã¿ãŒ 'fun [T]'ããã³é¢æ° 'fïŒ'ããã³ 'g'ã®å Žåã次ã®ã«ãŒã«CompositionLaw.case0ïŒfunïŒãåäžã«å®è¡ããå¿ èŠããããŸã-CompositionLaw.case1ïŒfunïŒãšåãã§ãã
object Lawompose extends App { def case0[T, R, Q](fun: Functor[T], f: T => R, g: R => Q): Functor[Q] = (fun map f) map g def case1[T, R, Q](fun: Functor[T], f: T => R, g: R => Q): Functor[Q] = fun map (f andThen g) }
ã€ãŸããé¢æ°ãfãã§ã次ã«é¢æ°ãgãã§é çªã«è¡šç€ºãããä»»æã®ãã¡ã³ã¯ã¿ãŒã³ã³ãããŒã¯ãé¢æ°fãšgïŒf andThen gïŒã®æ°ããé¢æ°æ§æãäœæããããã1å衚瀺ããããšãšåçã§ãã
äŸãèããŠã¿ãŸãããã ã³ã³ãããŒã¯ãã°ãã°ãã¡ã³ã¯ã¿ãŒãšèŠãªãããããããã¡ã³ã¯ã¿ãŒãååž°çãªããŒã¿åïŒãã€ããªããªãŒåã³ã³ãããŒïŒã«ããŸãããã
sealed trait Tree[T] { def map[R](f: T => R): Tree[R] } case class Node[T](value: T, fst: Tree[T], snd: Tree[T]) extends Tree[T] { def map[R](f: T => R) = Node(f(value), fst map f, snd map f) } case class Leaf[T](value: T) extends Tree[T] { def map[R](f: T => R) = Leaf(f(value)) }
ããã§ãmapã¡ãœããïŒfïŒT => RïŒã¯ãé¢æ° 'f'ãåãªãŒããŸãã¯ããŒãïŒãªãŒããããŒãïŒã®ã¿ã€ã 'T'ã®èŠçŽ ã«é©çšããããŒãïŒããŒãïŒã®åå«ã«ååž°çã«äŒæããŸãã ã ããç§ãã¡ã¯
- ããªãŒæ§é ãä¿æãããŸã
- ãæšã«æãã£ãŠãããããŒã¿ã®å€ãå€åãã
ãããã³ã°äžã«ããªãŒã®æ§é ãå€æŽããããšãããšãäž¡æ¹ã®èŠåã«éåããŸãïŒIdentity LawãšComposition Lawã®äž¡æ¹ïŒã
ãã¡ã³ã¯ã¿ã§ã¯ãããŸããïŒåããŒãã®åå«ã衚瀺ãããšãã«ã¹ã¯ããããŸã
case class Node[T](value: T, fst: Tree[T], snd: Tree[T]) extends Tree[T] { def map[R](f: T => R) = Node(f(value), snd map f, fst map f) }
ãã¡ã³ã¯ã¿ã§ã¯ãããŸããïŒãã£ã¹ãã¬ã€ããšã«ããªãŒãæé·ããèãæã«å€ãããŸã
case class Leaf[T](value: T) extends Tree[T] { def map[R](f: T => R) = Node(f(value), Leaf(f(value)), Leaf(f(value))) }
ãã®ãããªïŒèª€ã£ãïŒãã€ããªããªãŒã®å®è£ ããã¡ã³ã¯ã¿ãŒãšããŠèŠããšãããŒã¿ã®è¡šç€ºãšãšãã«ãããªãŒã®æ§é ãå€æŽãã圢ã§mapã®äœ¿çšåæ°ãã«ãŠã³ãããŠããããšãããããŸãã ããã§ãã¢ã€ãã³ãã£ãã£ã«åå¿ããfãšgã®ããã€ãã®äœ¿çšæ³ã¯ãfãšgã®äœ¿çšæ³ãšã¯ç°ãªããŸãã
å ±å€ãã¡ã³ã¯ã¿ãŒïŒæé©åã«äœ¿çš
å ±å€ãã¡ã³ã¯ã¿ãŒã®å ¬çã®å©ç¹ã瀺ãäŸãèŠãŠã¿ãŸãããã
ãããã³ã°ãšããŠãæŽæ°äžã®ç·åœ¢é¢æ°ãèããŸã
case class LinFun(a: Int, b: Int) { def apply(k: Int): Int = a * k + b def andThen[A](that: LinFun): LinFun = LinFun(this.a * that.a, that.a * this.b + that.b) }
T => Rã®åœ¢åŒã®æãäžè¬çãªé¢æ°ã®ä»£ããã«ããããã®ãµãã»ããã䜿çšããŸããäžè¬çãªåœ¢åŒãšã¯ç°ãªããæ瀺çãªåœ¢åŒã§ç·åœ¢é¢æ°ã®æ§æãæ§ç¯ã§ãããããIntäžã®ç·åœ¢é¢æ°ã§ãã
ãã¡ã³ã¯ã¿ãšããŠãåçŽã«æŽæ°ã®ãªã¹ããé£çµããã¿ã€ãã®ååž°ã³ã³ããïŒIntïŒãæ€èšããŸã
sealed trait IntSeq { def map(f: LinFun): IntSeq } case class Node(value: Int, tail: IntSeq) extends IntSeq { override def map(f: LinFun): IntSeq = Node(f(value), tail.map(f)) } case object Last extends IntSeq { override def map(f: LinFun): IntSeq = Last }
ãããŠä»ããã¢
object Demo extends App { val seq = Node(0, Node(1, Node(2, Node(3, Last)))) val f = LinFun(2, 3) // k => 2 * k + 3 val g = LinFun(4, 5) // k => 4 * k + 5 val res0 = (seq map f) map g // slow version val res1 = seq map (f andThen g) // fast version println(res0) println(res1) } >> Node(17,Node(25,Node(33,Node(41,Last)))) >> Node(17,Node(25,Node(33,Node(41,Last))))
ç§ãã¡ã¯ã©ã¡ãã
- ãªã¹ãã®ãã¹ãŠã®èŠçŽ ã2åç¹°ãè¿ããŸãïŒ2åã¯ã¡ã¢ãªãééããŸãïŒ
- ç®è¡æŒç®ãå®è¡ããããã«2åïŒ*ããã³+ïŒ
ã³ã³ããžã·ã§ã³fããã³gãæ§ç¯ãã
- ãªã¹ãã®ãã¹ãŠã®èŠçŽ ã1åç¹°ãè¿ã
- ç®è¡æŒç®ã1åå®è¡ãã
åå€ãã¡ã³ã¯ã¿ãŒãšã¯
ç¹å®ã®ã·ã°ããã£ïŒæ¡ä»¶ä»ãã§mapãšåŒã°ããïŒãæã¡ãç¹å®ã®ã«ãŒã«ïŒ Identity Law ã Composition Law ïŒã«åŸãã¡ãœãããæã€ãã¹ãŠã®ã¯ã©ã¹Xã¯å ±å€ãã¡ã³ã¯ã¿ãŒãšåŒã°ããããšãæãåºãããŠãã ãã
trait X[T] { def map[R](f: T => R): X[R] }
åæ§ã«ãç¹å®ã®çœ²åãæã¡ãç¹å®ã®èŠåïŒãããã¯Identity Law ã Composition LawãšãåŒã°ããŸã ïŒãæã€ã¡ãœããïŒæ¡ä»¶ä»ãã§contramap ïŒãæã€ãã¹ãŠã®ã¯ã©ã¹Xã¯ãåå€ãã¡ã³ã¯ã¿ãŒãšåŒã°ããŸãã
trait X[T] { def contramap[R](f: R => T): X[R] }
ãã®æç¹ã§ãåœæãããªãŒããŒãåæ¢ããå ŽåããããŸãã åŸ ã£ãŠãã ããããã ãã Tãå«ãã³ã³ããããããé¢æ°fïŒT => RãååŸããå Žåã Rãå«ãã³ã³ãããååŸããæ¹æ³ã¯æããã§ãã é¢æ°ãã³ã³ããã«æž¡ããé¢æ°ãã³ã³ããå ã«æµžããèŠçŽ ãåé€ããã«é¢æ°ãé©çšããŸãã ãã ãã Tãå«ãã³ã³ãããæã¡ãé¢æ°fïŒR => Tãåãåãæ¹æ³ããéé ãã§é©çšããæ¹æ³ã¯å®å šã«ç解äžèœã§ãã
äžè¬çãªæ°åŠã§ã¯ããã¹ãŠã®é¢æ°ã«éé¢æ°ãããããã§ã¯ãªããéé¢æ°ãååšããå Žåã§ããããèŠã€ããäžè¬çãªæ¹æ³ã¯ãããŸããã ããã°ã©ãã³ã°ã§ã¯ã建èšçã«è¡åããå¿ èŠããããŸãïŒååšãäžææ§ãªã©ã§æ©èœããã ãã§ãªããæ§æãæ§ç¯ããŠå®è¡ããŸãïŒ-äœããã®æ¹æ³ã§é¢æ°fãæ§ç¯ããå¿ èŠããããŸãïŒR => Té¢æ°gïŒT => Rã³ã³ããã®å 容ïŒ
ãããŠãããã§ç§ãã¡ã®æ¯phorïŒå ±å€é¢æãã³ã³ããïŒãæ©èœããªãããšãããããŸãã çç±ãèŠãŠã¿ãŸãããã
ãã¹ãŠã®ã³ã³ããã«ã¯2ã€ã®æäœãå«ãŸããŸã
- put-ã³ã³ããã«ã¢ã€ãã ãå ¥ããŸã
- get-ã³ã³ããããã¢ã€ãã ãæœåºããŸã
ãã ããæ€èšãããŠããäŸïŒOptionãTryãFutureãListãParserïŒã«ã¯ãããçšåºŠgetã¡ãœããããããŸãããputã¡ãœããã¯ãããŸããïŒ Option / Try / Futureã§ã¯ãèŠçŽ ã¯ã³ã³ã¹ãã©ã¯ã¿ãŒïŒãŸãã¯ã³ã³ãããªã³ãªããžã§ã¯ãã®applyã¡ãœããïŒãŸãã¯äœããã®ã¢ã¯ã·ã§ã³ã®çµæãšããŠååŸãããŸãã Parser [T]-Tã®è¡ãããªãµã€ã¯ã«ããããããParserã«ã¯ãŸã£ããã¢ã¯ã»ã¹ã§ããŸãããParser[T]ã¯ã¹ãã¬ãŒãžã§ã¯ãªãTã®ãœãŒã¹ã§ãïŒ
ãããŠãããã«é metaã®èª€ãã®ç§å¯ããããŸãã
å ±å€ãã¡ã³ã¯ã¿ãŒã¯ã³ã³ãããŒã®ååã§ãã ããŒã¿ã®ååŸãæ åœããéšåã
ãã€ã¢ã°ã©ã ã«æããŠã¿ãŸããã
+ ------------------------- + | + ------ + T | R | | X [T] -----> fïŒT => R ----> | + ------ + | + ------------------------- +
ã€ãŸããå ±å€ãã¡ã³ã¯ã¿ãŒã®åºå£ã§ã¯ãã¿ã€ãTã®ããŒã¿èŠçŽ ã¯é¢æ°fïŒT => RãåŸ æ©ãããã®æ§æã¯ã Rã§å ¥åãããå ±å€ãã¡ã³ã¯ã¿ãŒã§ãã
ãã®å Žåãã¹ãã¬ãŒãžã³ã³ãããŒã§ã¯ãªãçç±ãæããã«ãªããŸãããäžè¬çãªIteratorããã³StreamããŒã¿ãœãŒã¹ãå ±å€ãã¡ã³ã¯ã¿ãŒã§ãã
???
???
æŠç¥çã«ã¯ãå ±å€ãã¡ã³ã¯ã¿ãŒã¯æ¬¡ã®ãšããã§ããå€æfãããã蟌ã¿ã ãŸããR=> T㯠ãåºåãã§ã¯ãªããå ¥åãã§ãã
+ ------------------------- + R | T + ------ + | -----> fïŒR => T -----> X [T] | | | + ------ + | + ------------------------- +
åå€ãã¡ã³ã¯ã¿ãŒã®äŸ
Scalaæšæºã©ã€ãã©ãªã§åå€ãã¡ã³ã¯ã¿ãŒã®äŸãæ€çŽ¢ããã«ã¯ãã³ã³ãããŒã¡ã¿ãã¡ãŒãå¿ããŠãåŒæ°ãšããŠããŒã¿ã®ã¿ãåãå ¥ããé¢æ°ã®çµæãè¿ããªã1ã€ã®åãã©ã¡ãŒã¿ãŒãæã€åãæ¢ãå¿ èŠããããŸãã
äŸã¯ã 泚æãšåçã§ã
äŸïŒ 泚æ
import scala.math.Ordering._ object Demo extends App { val strX: Ordering[String] = String val f: (Int => String) = _.toString val intX: Ordering[Int] = strX on f }
æååãçžäºã«æ¯èŒããæ¹æ³ãæã¡ãæŽæ°ãæååã«å€æããæ©èœãæã€ããšã§ãæ°å€ãæååãšããŠæ¯èŒããæ¹æ³ãæ§ç¯ã§ããŸãã
è¡ã«é¢ããç°¡åãªã³ã¡ã³ã
val strX: Ordering[String] = String
ãã®å Žåãjava.lang.Stringã§ã¯ãªããscala.math.Ordering.String
package scala.math trait Ordering[T] extends ... { trait StringOrdering extends Ordering[String] { def compare(x: String, y: String) = x.compareTo(y) } implicit object String extends StringOrdering ... }
onã¡ãœããã¯contramapã¡ãœããã§ã
package scala.math trait Ordering[T] extends ... { def on[R](f: R => T): Ordering[R] = new Ordering[R] { def compare(x: R, y: R) = outer.compare(f(x), f(y)) } ... }
äŸïŒ åç
import java.lang.String.CASE_INSENSITIVE_ORDER import scala.math.Equiv import scala.math.Equiv.{fromFunction, fromComparator} object Demo extends App { val strX: Equiv[String] = fromComparator(CASE_INSENSITIVE_ORDER) val f: (Int => String) = _.toString val intX: Equiv[Int] = fromFunction((x, y) => strX.equiv(f(x), f(y))) }
java.lang.String.CASE_INSENSITIVE_ORDERã³ã³ãã¬ãŒã¿ã¡ãœããã«åºã¥ããŠãæååæ¯èŒã¡ãœããïŒscala.math.Equizã®ç䟡é¢ä¿ïŒãæ§ç¯ããŠããŸãã
package java.lang; public final class String implements ... { public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { public int compare(String s1, String s2) {...} ... } ... }
fromComparatorã¡ãœããã䜿çšãã
object Equiv extends ... { def fromComparator[T](cmp: Comparator[T]): Equiv[T] = new Equiv[T] { def equiv(x: T, y: T) = cmp.compare(x, y) == 0 } ... }
ã³ã³ãã©ãããã¡ãœããã®ä»£ããã«ãfromFunctionã¡ãœããã«åºã¥ãé¢åãªæ§é ã䜿çšããŸã
object Equiv extends ... { def fromFunction[T](cmp: (T, T) => Boolean): Equiv[T] = new Equiv[T] { def equiv(x: T, y: T) = cmp(x, y) } ... }
åå€é¢æ°ïŒã¢ã€ãã³ãã£ãã£æ³
å ±å€ãã¡ã³ã¯ã¿ãŒã®å Žåã®ããã«ãåå€ãã¡ã³ã¯ã¿ãŒã¯ã眲åä»ãã®ã¡ãœããã«å ããŠã2ã€ã®ã«ãŒã«ã«åŸãå¿ èŠããããŸãã
æåã®èŠåïŒåäžæ§æ³åïŒã«ã¯ãåå€ãã¡ã³ã¯ã¿ãŒã®å ŽåãIdentityLaw.case0ïŒfunïŒã¯åäžã§ãªããã°ãªãããIdentityLaw.case1ïŒfunïŒã§ãªããã°ãªããŸãã
object IdentityLaw { def case0[T](fun: Contravariant[T]): Contravariant[T] = identity(fun) def case1[T](fun: Contravariant[T]): Contravariant[T] = fun.contramap(identity) }
ã€ãŸããåå€ãã¡ã³ã¯ã¿ãŒãšåäœé¢æ°ã®ãããã³ã°ã¯ãããå€æŽããŸããã
åå€ãã¡ã³ã¯ã¿ãŒïŒåææ³
2çªç®ã®ã«ãŒã«ïŒæ§ææ³ïŒã«ãããšãåå€ãã¡ã³ã¯ã¿ãŒ[T]ããã³é¢æ°fïŒQ => Rããã³gïŒR => Tã®ä»»æã®ãã¢ã®å Žåããã®ãã¢ã¯IdentityLaw.case1ïŒfunïŒãšåäžã®IdentityLaw.case0ïŒfunïŒã§ãªããã°ãªããŸãã
object CompositionLaw { def case0[Q, R, T](fun: Contravariant[T], f: Q => R, g: R => T): Contravariant[Q] = (fun contramap g) contramap f def case1[Q, R, T](fun: Contravariant[T], f: Q => R, g: R => T): Contravariant[Q] = fun contramap (f andThen g) }
ã€ãŸããé¢æ°ã®ãã¢ã«ããåå€ãã¡ã³ã¯ã¿ãŒã®é 次ãããã³ã°ã¯ãé¢æ°ã®æ§æïŒå転ïŒã«ãããŠããããããã³ã°ãšåçã§ãã
次ã¯ïŒ
å ±å€ããã³åå€ãã¡ã³ã¯ã¿ãŒã®æŠå¿µã¯ãé¢æ°åããã°ã©ãã³ã°ã«ãããã«ããŽãªçè«ããã®æœè±¡åã®äœ¿çšã«é¢ããçå£ãªç 究ã®åºçºç¹ã«ãããŸããïŒScalaã®çšèª-Catsã©ã€ãã©ãªã®Scalazã®äœ¿çšãžã®ç§»è¡ïŒã
è¿œå ã®æé ã¯æ¬¡ã®ãšããã§ãã
- å ±å€ããã³åå€ã®ãã¡ã³ã¯ã¿ãŒïŒBiFunctorãProFunctorãExponentialïŒInvariantïŒFunctorïŒã®æ§æã®ç 究
- ããç¹æ®ãªæ§é ïŒApplicative FunctorãArrowãMonadïŒã®ç 究ãããã¯ãèšç®ãå ¥åºåããšã©ãŒåŠçãç¶æ ã®å€åãæ±ãæ°ãããã©ãã€ã ããã§ã«å®éã«æ§æããŠããŸãã å°ãªããšãããã¹ãŠã®ã¢ããã¯å ±å€ãã¡ã³ã¯ã¿ãŒã§ããããšãææããŸãã
æ®å¿µãªãããèšäºã®ãµã€ãºã§ã¯ãäžåºŠã«ãã¹ãŠãäŒããããšã¯ã§ããŸããã
PSãã®èšäºãæåŸãŸã§èªãã 人ã®ããã« ã Scala for Java Developersã³ãŒã¹ãäŸ¡æ Œã®25ïŒ ã§æäŸããŠããŸãïŒãªã³ã¯ããã©ããã HABR-COVARIANT-FUNCTORã¯ãŒãã³ã䜿çšããŠãã ãã ïŒã å²åŒã¯ãŒãã³ã®æ°ã¯éãããŠããŸãïŒ