翻蚳è
ã«ããã¡ã¢ã Scalaã®å°æ¥ã®ããŒãžã§ã³ïŒãDon GiovanniãïŒã¯ããŠããªã³åã®ãµããŒããçºè¡šããŸããã Shapelessã®äœæè
ãšããŠçããµãŒã¯ã«ã§åºãç¥ãããŠããMiles Sabinã¯ã ãã® 2011幎ã®èšäºã§ãä»ããçµåã¿ã€ããäœæããæ¹æ³ã瀺ããŠããŸãã
UPD ãã®èšäºã§ç޹ä»ãããŠããã¢ãããŒãã§ã¯ãå®éã®ã¿ã€ãã®çµ±åãååŸããããšã¯ã§ãããããã«ãã³ã³ãã€ã«æéã«å€§ããªåœ±é¿ãäžããå¯èœæ§ããããŸãã ãŸããèšäºã§äœ¿çšãããŠãã亀差ã®ã¿ã€ãïŒ A with B
ïŒã¯ã坿æ§ã®æ§è³ªããªããããåŸæ¥ã®ãã®ãšã¯ç°ãªããŸãã ãããã®åé¡ããã®ä»ã®åé¡ã解決ããDottyãã€ããããããžã§ã¯ãã®è©³çްã¯ãEPFLã®Scalaã³ã³ãã€ã©ãŒã®éçºè
ã§ããDmitry Petrashko darkdimius ã«ããçŽ æŽããããã¬ãŒã³ããŒã·ã§ã³ã«èšèŒãããŠããŸããScalaã«ã¯éåžžã«è¡šçŸåè±ããªåã·ã¹ãã ããããŸãã ãã ããïŒå°ãªããšãããªããã£ããšããŠïŒåæãããŠãããã¹ãŠã®èŠçŽ ãå«ãŸããŠããããã§ã¯ãããŸããã ãã®ã«ããŽãªã«è©²åœããæ¬åœã«äŸ¿å©ãªã¿ã€ããããã€ããããŸãããããã¯ãé«ã©ã³ã¯ïŒé«ã©ã³ã¯ïŒããã³ååž°æ§é ã¿ã€ãã®å€æ
æ§é¢æ°ã®ã¿ã€ãã§ãã ããããæ¬¡ã®æçš¿ã§ãããã«ã€ããŠè©³ãã説æããŸãã仿¥ã¯ãScalaã§ãŠããªã³åãäœæããæ¹æ³ã玹ä»ããŸãã 説æã®éçšã§ãCurry-Howardååã«ããã€ãã®å
ãåœãŠããããç®çã«äœ¿çšããæ¹æ³ã瀺ããŸãã

ããã§ã¯ãæå§ãã«ããŠããªã³åãšã¯äœã§ããïŒ ãŠããªã³ã®ã¿ã€ãã¯ãå€ãã®ç¹ã§ããªããæåŸ
ãããã®ã§ãã2ã€ïŒãŸãã¯ãã以äžããã ãç§ã¯2ã€ã ãã«å¶éããŸãïŒã¿ã€ãã®ãŠããªã³ã§ãã ãã®ã¿ã€ãã®å€ã«ã¯ãçµåãããåã¿ã€ãã®ãã¹ãŠã®å€ãå«ãŸããŸãã ãããæå³ããããšã¯ãäŸãçè§£ããã®ã«åœ¹ç«ã¡ãŸãããæåã«è¡šèšæ³ãå°å
¥ããŸãã ããã«æããã«ãªãçç±ãããæäœèšå·ORïŒ
T âš U
U
ããŠãã¿ã€ã
T
ãš
U
åéåãæžãçããŸã
T âš U
ãããã£ãŠã
Int
åãš
String
åã®çµåã¯ã
Int
ãšããŠèšè¿°ãããŸãã ãã®ã¿ã€ãã®ãŠããªã³ã®å€ã«ã¯ã
Int
ã¿ã€ãã®ãã¹ãŠã®å€ãš
String
ã¿ã€ãã®ãã¹ãŠã®å€ãå«ãŸããŸãã
ããããããã¯å
·äœçã«ã©ãããæå³ã§ããïŒ ã€ãŸããScalaã§ãã®ãããªåãçŽæ¥è¡šçŸã§ããã°ãããšãã°æ¬¡ã®ããã«æžãããšãã§ããŸãã
def size(x: Int âš String) = x match { case i: Int => i case s: String => s.length } size(23) == 23
èšãæãããšã
size
ã¡ãœããã¯ã
Int
åãŸãã¯
String
åïŒãã®ãµãã¿ã€ã
Null
ããã³
Nothing
ãå«ãïŒã®åŒæ°ãåãå
¥ãããã以å€ã¯åãå
¥ã
Nothing
ã
ãã®ã¿ã€ãã®ããŒã«ã䜿çšããããšãšæšæºã®
Either
ã䜿çšããããšã®éãã匷調ããããšãéèŠã§ãã ååãšããŠç¥ããã
Either
ããµãã¿ã€ãããµããŒãããªãèšèªã®ãŠããªã³åã«é¡äŒŒããŠããŸãã
Either
ã䜿çšããŠäŸãæžãæãããšã次ã®ããã«ãªããŸãã
def size(x: Either[Int, String]) = x match { case Left(i) => i case Right(s) => s.length } size(Left(23)) == 23
Either[Int, String]
ã®å
Either[Int, String]
ã¯ããŠããªã³å
Int âš String
ã¢ãã«åã§ããŸããããã¯ãããããšå€ã®éã«å¯Ÿå¿ïŒååïŒãããããã§ãã ãã ããEtherã¿ã€ãã¯ãããã¯ã¹åãããŠããªãåã·ã¹ãã ããªããã£ããšããŠã§ã¯ãªããããã¯ã¹åããã衚çŸã®è¿œå ã¬ã€ã€ãŒã§ããããšã«ãã£ãŠãããéæããããšã¯çµ¶å¯Ÿã«æããã§ãã
Either
ãããåªãããã®ãäœæã§ããŸã
Either
ïŒ ããã±ãŒãžã³ã°ãå¿
èŠãšãããäºæ³ããããã¹ãŠã®éçä¿èšŒã䜿çšããã«ãScalaã§ãŠããªã³åãè¡šãæ¹æ³ãèŠã€ããããšãã§ããŸããïŒ
ã§ããããšã¯ããã£ãŠããŸãããçµæã«è³ãéäžã§ã
Curry-Howardååã䜿çšããŠ1次ã®è«çãè¿åããå¿
èŠããããŸãã ãã®ååã¯ãåã·ã¹ãã å
ã®åéã®é¢ä¿ã¯ãè«çã·ã¹ãã å
ã®ã¹ããŒãã¡ã³ãéã®é¢ä¿ã®ã€ã¡ãŒãžãšèŠãªãããšãã§ããããšã瀺ããŠããŸãïŒéãåæ§ã§ãïŒã 話ããŠããåã·ã¹ãã ãšéžæããè«çã·ã¹ãã ã«å¿ããŠããã®ã¹ããŒãã¡ã³ããããŸããŸãªæ¹æ³ã§è§£éã§ããŸããã説æã§ã¯ã»ãšãã©ã®è©³çްãç¡èŠããç°¡åãªäŸã«çŠç¹ãåœãŠãŸãã
Scalaã®ãããªãµãã¿ã€ããæã€åã·ã¹ãã ã®ã³ã³ããã¹ãã§ã«ãªãŒãã¯ãŒãååã瀺ããŸãã 亀差ã®ã¿ã€ãïŒ
A with B
ïŒãšè«çç©ïŒ
A â§ B
ïŒã®éã«å¯Ÿå¿ãããããšã«æ°ä»ããããããŸããã ç§ã®ä»®å®çãªã¿ã€ãã®çµ±äžïŒ
A âš B
ïŒãšè«ççåé¢ïŒäžèšã§ç€ºåãããããã«AâšBïŒ; ãµãã¿ã€ãïŒ
A <: B
ïŒãšè«çç嫿ïŒ
A â B
ïŒã®éã æ¬¡ã®è¡šã®å·Šã®åã«ã¯ãScalaã§å®è¡ããããµãã¿ã€ãã®é¢ä¿ããããŸãïŒãã ããèšèªã§çŽæ¥è¡šçŸãããªãå
±çšäœåã®å ŽåïŒã
â
ã ãããã®å Žåãããã®ãããªçœ®æã¯è«ççã«æ£ããåŒãæäŸããŸãã
ïŒAãšBïŒ<ïŒA | ïŒAâ§BïŒâA |
ïŒAãšBïŒ<ïŒB | ïŒAâ§BïŒâB |
A <ïŒïŒAâšBïŒ | AâïŒAâšBïŒ |
B <ïŒïŒAâšBïŒ | BâïŒAâšBïŒ |
ã«ãªãŒ-ãã¯ãŒãååã®æ¬è³ªã¯ãæ©æ¢°çãªçœ®æããã»ã¹ãåžžã«æ£ããããšã§ã-æ£ããåã®åŒã¯åžžã«æ£ããè«çåŒã«æžãæããããéã®å Žåãåæ§ã§ãã ãããŠããã¯ãçµåãåé¢ã嫿ã®ããã ãã«è¡ãããŸããã ãŸããåŠå®ïŒä»æ¥ã®èæ
®äºé
ã§éèŠãªæäœïŒãäžè¬æ§ãšååšã®éæå®åãå«ãè«çåŒãžã®å¯Ÿå¿ãäžè¬åããããšãã§ããŸãã
åŠå®ã®è¿œå ã¯ãç§ãã¡ã«ãšã£ãŠäœãæå³ããŸããïŒ 2ã€ã®ã¿ã€ãã®çµã¿åããïŒã€ãŸãã
A with B
ïŒã«ã¯ãåæã«
A
ãš
B
ã®äž¡æ¹
A
ã€ã³ã¹ã¿ã³ã¹ã§ããå€ããããŸãã åæ§ã«ãã¿ã€ã
A
åŠå®ïŒ
¬[A]
ãšæžãïŒã«ã¯ãã¿ã€ã
A
ã€ã³ã¹ã¿ã³ã¹ã§ã¯ãªãå€ãå¿
èŠã§ãããšä»®å®ã§ããŸã
A
åŠå®ã¯Scalaèšèªã§çŽæ¥è¡šçŸããããšãã§ããŸããããããã§ã¯ãªããšä»®å®ããŠã©ãã«è¡ãã°ããã®ã§ããããïŒ
ãã®å ŽåãCurry-Howardååãš
De Morganã®æ³åã䜿çšããŠã亀差ãšåŠå®ã®ã¿ã€ããããŠããªã³ã¿ã€ãã®å®çŸ©ãååŸã§ããŸãã ãããã©ããªããã¯ããã«ãããŸã...
ãŸããDe Morganã®å¹³çãæãåºããŠãã ããã
(A âš B) â ¬(¬A ⧠¬B)
次ã«ãCurry-Howardååãé©çšããŸãïŒScalaã®åå€
=:=
æäœã䜿çšïŒã
(A ⚠B) =:= ¬[¬[A] with ¬[B]]
ãããScalaã«æžãèŸŒãæ¹æ³ãèŠã€ããããšãã§ããã°ãç®æšã¯éæãããããŸããŸãªçš®é¡ã®çµ±äžãå¯èœã«ãªããŸãã ã§ã¯ãScalaã§ååŠå®ã衚çŸã§ããŸããïŒ
æ®å¿µãªãããã§ããŸããã ããããã§ããããšã¯ã倿ãããã³ã³ããã¹ãã§åŠå®ãèšè¿°ã§ããããã«ãã¹ãŠã®åã倿ããããšã§ãã æ¬¡ã«ããã¹ãŠãå
ã®æªä¿®æ£ã®ã³ã³ããã¹ãã§æ©èœãããæ¹æ³ãèŠã€ããå¿
èŠããããŸãã
äžéšã®èªè
ã¯ã以åã«é£çµãšçµã¿åããã亀差ã¿ã€ããåé¢ãšçµã¿åããããŠããªã³ã¿ã€ããããã³å«æãšçµã¿åããããµãã¿ã€ãæ¯ã䜿çšããŠã«ãªãŒãã¯ãŒãååã説æãããšãã«å°ãé©ãããããããŸããã éåžžã補åã¿ã€ããã€ãŸã
(A, B)
æ¥ç¶è©ãã¢ãã«åããåã®ã¿ã€ãïŒ
Either[A, B]
ïŒã¯éžèšãã¢ãã«åãã颿°ã¿ã€ãã¯å«æãã¢ãã«åããŸãã 補åãåèšã颿°ã䜿çšããŠåã®è¡šãæžãæãããšã次ã®ããã«ãªããŸãã
ïŒAãBïŒ=> A | ïŒAâ§BïŒâA |
ïŒAãBïŒ=> B | ïŒAâ§BïŒâB |
A => [AãB]ã®ãããã | AâïŒAâšBïŒ |
B =>ã©ã¡ãã[AãB] | BâïŒAâšBïŒ |
å·ŠåŽã§ã¯ããµãã¿ã€ãã®é¢ä¿ã«é¢ããæ£ç¢ºæ§ã¯ãã¯ãæåŸ
ãããŠããŸããã代ããã«ã颿°ã®ã·ã°ããã£ã®ã¿ã«åºã¥ããŠé¢æ°åãå®è£
ã§ãããã©ããã倿ã§ããããã«ãã
ãã©ã¡ããªãã¯ã®
ååã芳å¯ããå¿
èŠããããŸãã æããã«ãå·Šã®åã®ãã¹ãŠã®é¢æ°ã·ã°ããã£ãå®è£
ã§ããŸãã æåã®2ã€ã®ã±ãŒã¹ã§ã¯ã颿°ã®åŒæ°ãšããŠãã¢
(A, B)
ãããããã
_1
ãŸãã¯
_2
ã䜿çšããŠãã®ãã¢ããã¿ã€ã
A
ãŸãã¯
B
å€ãç°¡åã«ååŸã§ããŸãã
val conj1: ((A, B)) => A = p => p._1 val conj2: ((A, B)) => B = p => p._2
2çªç®ãš3çªç®ã®ã±ãŒã¹ã§ã¯ã颿°ã®åŒæ°ã¯ããããã¿ã€ã
A
ãš
B
å€ã§ãããããã³ã³ã¹ãã©ã¯ã¿ãŒ
Left[A]
ãš
Right[B]
ã䜿çšããŠ
Either[A, B]
å
Either[A, B]
çµæãååŸã§ããŸãã
val disj1: A => Either[A, B] = a => Left(a) val disj2: B => Either[A, B] = b => Right(b)
ãã®åœ¢åŒã§ãã«ãªãŒ-ãã¯ãŒãååã¯éåžžããµãã¿ã€ãã®ãªãèšèªã§è¡šçŸãããŸãã ãã ããå
±çšäœã¿ã€ããšäº€å·®ã¿ã€ãã¯ãæ¬è³ªçã«ãµãã¿ã€ãã«åºã¥ããŠããŸãã ãããã£ãŠãèæ
®ããããããã³ã°ã¯ã決ããŠçµåãå©ããŸããã ããããããã¯åŠå®ã®å©ãã«ãªããŸããããã¯ããºã«ã®æ¬ ããŠããéšåã§ãã
ãµãã¿ã€ãã®æç¡ã«ããããããScalaã§
Nothing
ãšããŠè¡šãããæå°ã®ã¿ã€ãïŒããã ã¿ã€ãïŒã¯è«çfalseã«ããããããŸãã ããšãã°ã次ã®çåŒã¯ãã¹ãŠçã§ãã
A =>ã©ã¡ãã[AãNothing] | AâïŒAâšfalseïŒ |
B =>ã©ã¡ãã[NothingãB] | BâïŒfalseâšBïŒ |
ããã¯ãå·ŠåŽã®ãã¹ãŠã®é¢æ°ã·ã°ããã£ãå®çŸå¯èœã§ãããå³åŽã®è«çåŒãçã§ãããšããäºå®ã«åºã¥ããŠããŸãïŒJames Airyã®
æçš¿ã§ã¯ãäžèŽãã補å/æ¥ç¶ã®ã±ãŒã¹ã衚瀺ããªãçç±ã説æããŠããŸãïŒã 次ã®ã·ã°ããã£ãæã€é¢æ°ã«å¯Ÿå¿ãããã®ã«ã€ããŠèããŠã¿ãŸãããã
A => Nothing
ã«ãªãŒ-ãã¯ãŒãååæ§ã®å³åŽã®è«ççãªåŽé¢ã§ã¯ããã®ã·ã°ããã£ã¯æ°åŒ
¬A
ãŸããããã¯
¬A
ãšåç
¬A
ã ããã¯éåžžã«çŽæçã«åççãªããã§ã-ã¿ã€ã
Nothing
ã®å€ããªããããã·ã°ããã£
A => Nothing
ãå®è£
ã§ããŸããïŒäŸå€ãã¹ããŒããããšãé€ãããã®å Žåã¯èš±å¯ãããŸããïŒã
ãã®çœ²åãååŠå®ã®è¡šçŸãšããŠäœ¿çšãããšã©ããªããèŠãŠã¿ãŸãããã
type ¬[A] = A => Nothing
ãããŠãDe Morganã®æ³åã®æèã§ãããé©çšããŠãé¢é£ä»ãã®ã¿ã€ããååŸããŸãã
type âš[T, U] = ¬[¬[T] with ¬[U]]
ããã§ãScala REPLã䜿çšããŠåã確èªã§ããŸãã
scala> type ¬[A] = A => Nothing defined type alias $u00AC scala> type âš[T, U] = ¬[¬[T] with ¬[U]] defined type alias $u2228 scala> implicitly[Int <:< (Int âš String)] <console>:11: error: Cannot prove that Int <:< ((Int) => Nothing with (String) => Nothing) => Nothing. implicitly[Int <:< (Int âš String)]
REPLã¯ããœãªã¥ãŒã·ã§ã³ããŸã åä¿¡ãããŠããªãããšã瀺ããŠããŸãã
implicitly[Int <:< (Int âš String)]
ãªåŒ
implicitly[Int <:< (Int âš String)]
ã¯ã
Int
ã
Int
ã®ãµãã¿ã€ãã§ããããšã蚌æã§ãããã©ãããã³ã³ãã€ã©ãŒã«å°ããŸããããã¯ãå
±çšäœã®ã¿ã€ãã«åœãŠã¯ãŸããŸãã
äœãæªãã£ãã®ã§ããïŒ åé¡ã¯ã
A => Nothing
ãšããŠæå®ãããååŠå®ã䜿çšããããã«ã
<:<
æŒç®åã®å³åŽã®åã颿°åã«å€æããããšã§ãã ããã¯ããŠããªã³ã®ã¿ã€ãèªäœã颿°ã®ã¿ã€ãã§ããããšãæå³ããŸãã ããããããã¯æããã«ãINTããŠããªã³åã®ãµãã¿ã€ãã§ããããšãšã¯ç°ãªããREPLããã®ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããŸãã ãšã©ãŒãæé€ããã«ã¯ã
<:<
æŒç®åã®å·ŠåŽããå³åŽã®åã®ãµãã¿ã€ãã«ãªãåã«å€æããå¿
èŠããããŸãã
ããã¯ã©ã®ãããªå€é©ã§ããïŒ äºéåŠå®ã¯ã©ãã§ããïŒ
type ¬¬[A] = ¬[¬[A]]
ã³ã³ãã€ã©ãŒã®èšãããšãèŠãŠã¿ãŸãããïŒ
scala> type ¬¬[A] = ¬[¬[A]] defined type alias $u00AC$u00AC scala> implicitly[¬¬[Int] <:< (Int ⚠String)] res5: <:<[((Int) => Nothing) => Nothing, ((Int) => Nothing with (String) => Nothing) => Nothing] = <function1> scala> implicitly[¬¬[String] <:< (Int ⚠String)] res6: <:<[((String) => Nothing) => Nothing, ((Int) => Nothing with (String) => Nothing) => Nothing] = <function1>
ãã³ãŽïŒ
¬¬[Int]
ãš
¬¬[String]
ã¯äž¡æ¹ãšãã
¬¬[Int]
ãµãã¿ã€ãã§ãã
次ã«ãæ¯åè¯å®çãªçããè¿ãã ãã§ã¯ãªãããšã確èªããå¿
èŠããããŸãã
scala> implicitly[¬¬[Double] <:< (Int ⚠String)] <console>:12: error: Cannot prove that ((Double) => Nothing) => Nothing <:< ((Int) => Nothing with (String) => Nothing) => Nothing.
ããã§ãç§ãã¡ã¯ã»ãšãã©çµãããŸãããæåŸã®ä»äžããããããšã¯æ®ã£ãŠããŸãã ææãããµãã¿ã€ãã®é¢ä¿ã¯ãååŸããããµãã¿ã€ããšååã§ãïŒã¿ã€ã
¬¬[T]
ã¯
¬¬[T]
ãšååã§ããããïŒã ããããç§ãã¡ã¯ãŸã å¿
èŠãªæªä¿®æ£ã®åãšåãé¢ä¿ã衚çŸããæ¹æ³ããããŸããã
ãã®åé¡ã解決ããã«ã¯ã
¬[T]
ã
¬¬[T]
ããã³
¬¬[T]
ãã¡ã³ãã ã¿ã€ããæ€èšãããããã®ã¿ã€ãã®å€ãçŽæ¥æäœããã®ã§ã¯ãªããå¿
èŠãªãµãã¿ã€ãã®é¢ä¿ã衚ãããã ãã«äœ¿çšããŸãã ãã¹ãã±ãŒã¹ã§ãããã©ã®ããã«çºçããããæ¬¡ã«ç€ºããŸãã
def size[T](t: T)(implicit ev: (¬¬[T] <:< (Int ⚠String))) = t match { case i: Int => i case s: String => s.length }
ããã¯äžè¬åãããåå¶çŽã䜿çšããŸããããã¯ã
size
ã¡ãœããã®ååŒæ°ãšããŠæšå®ããã
T
ããã®äºéåŠå®ãIntâšStringã®ãµãã¿ã€ãã§ããããšãã³ã³ãã€ã©ã蚌æããããšãèŠæ±ããŸãã æ¬¡ã®REPLã»ãã·ã§ã³ã瀺ãããã«ããã®æ¡ä»¶ã¯ã
T
ã
Int
ãŸãã¯
String
å Žåã«ã®ã¿æºããããŸãã
scala> def size[T](t: T)(implicit ev: (¬¬[T] <:< (Int ⚠String))) = | t match { | case i: Int => i | case s: String => s.length | } size: [T](t: T)(implicit ev: <:<[((T) => Nothing) => Nothing, ((Int) => Nothing with (String) => Nothing) => Nothing])Int scala> size(23) res8: Int = 23 scala> size("foo") res9: Int = 3 scala> size(1.0) <console>:13: error: Cannot prove that ((Double) => Nothing) => Nothing <:< ((Int) => Nothing with (String) => Nothing) => Nothing.
ãããŠä»ãæåŸã®ããªãã¯ã æ§æã«é¢ããŠã¯ãæé»ã®èšŒæãã©ã¡ãŒã¿ãŒã¯theããŠéãããã«èŠããŸãããããã
T
åã®ãã©ã¡ãŒã¿ãŒã®ã³ã³ããã¹ãå¶çŽã«å€æããããšã§ä¿®æ£ã§ããŸãã
type |âš|[T, U] = { type λ[X] = ¬¬[X] <:< (T âš U) } def size[T: (Int |âš| String)#λ](t: T) = t match { case i: Int => i case s: String => s.length }
ã§ããïŒ èšèªèªäœã倿ŽããããšãªããScalaã§unionåã®unpackedãstaticly type-safe衚çŸãååŸããŸããïŒ
åœç¶ãScalaããŠããªã³åãããªããã£ããšããŠãµããŒãããæ¹ãè¯ãã§ãããã ããããå°ãªããšãç§ãã¡ãåŸã解決çã¯ãScalaã³ã³ãã€ã©ããããè¡ãããã«å¿
èŠãªãã¹ãŠã®æ
å ±ãæã£ãŠããããšã瀺ããŠããŸãã ä»ã§ã¯ããŒãã£ã³ãšã¢ããªã¢ãŒã³ãæ©ãŸããŠããã ããªã®ã§ãçµ±äžã®ã¿ã€ããçŽæ¥å©çšã§ããŸãã