追è¨
ééã£ã¦ããªããã¨ã示ãã¦ããã ãã¾ãã â
「Scalaに存在演算子を求めるのは間違っているだろうか」の解答例 - scalaとか・・・
ããã«Lensã§ããâ
「Scalaに存在演算子を求めるのは間違っているだろうか」をLens/Prismで解いてみる - 独学大学情報学部
ï¼ééã£ã¦ããªããã©ãããããæ½è±¡åãé©åã¨ã¯è¨ã£ã¦ããªãï¼
ç²¾é²ããã°ã»ã»(´・_ï½¥`)
追è¨çµããã
ããªãã¯ããã«ãã¾ãã
CoffeeScriptã«ã¯åå¨æ¼ç®å?.
ãããã¾ãã
ããã¯ãJSONã®ãããªãã¹ãããæ§é ã§ããã¤å¤ãéä¸ã§nullã«ãªã£ã¦ããããããªããã©ä¸çªå å´ã®å¤ã欲ããï¼ ã¨ãã«ä¾¿å©ãªä»çµã¿ã§ãã
ã³ã¼ãã¨ãã¦ã¯
obj = { e : { d : { c: { b: { a: { value: 1 } } } } } } # åå¨æ¼ç®åã使ã£ã¦valueã«ã¢ã¯ã»ã¹ï¼ obj?.e?.d?.c?.b?.a.value
ã®ããã«æ¸ãã¨ä»¥ä¸ã®ããã«ã³ã³ãã¤ã«ããã¾ãã
var obj, ref, ref1, ref2, ref3; obj = { e: { d: { c: { b: { a: { value: 1 } } } } } }; if (obj != null) { if ((ref = obj.e) != null) { if ((ref1 = ref.d) != null) { if ((ref2 = ref1.c) != null) { if ((ref3 = ref2.b) != null) { ref3.a.value; } } } } }
ã³ã³ãã¤ã«å¾ã®ã³ã¼ããè¦ã¦ã¿ãã¨ãedcbaã«å¯¾ãã¦ã²ãããnullãã§ãã¯ãè¡ã£ã¦ãããã¨ãåããã¾ãã
Scalaã§ã®åå¨
ã¾ãæ¬ç·¨éãã¦ã®build.sbtãè²¼ã£ã¦ããã¾ãã
name := "OptionValueAccessor" version := "1.0" scalaVersion := "2.11.6" libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
ãã¦ãScalaã§åããã¨ãããã¨ãããã©ãã§ããããï¼
ã¾ãã以ä¸ã®æ§ãªç¶æ³ãæ³å®ãã¾ãã
case class A(value: Int) case class B(value: Option[A]) case class C(value: B) case class D(value: Option[C]) case class E(value: D) val obj = Some(E(D(Some(C(B(Some(A(1))))))))
ããå¤ã¯å¿ é ã ãã©ãå¥ã®ããå¤ã¯å¿ é ã§ã¯ãªããããããå¤ããã¹ããã¦ããã±ã¼ã¹ã§ãã*1
Scalaã§ãããããªãã¸ã§ã¯ãã«ã¢ã¯ã»ã¹ãããã¨ãã¯æ®éã¯ä»¥ä¸ã®ããã«ããã®ã§ã¯ãªãã§ããããã
for { edcba <- obj dcba <- edcba.value cba <- dcba.value ba <- cba.value a <- ba.value } yield a.value
ãããªãã¨æã£ãããã®ããªãï¼ããåããªããã§ããï¼edcba = E(D(..))
ã¨ãªã£ã¦ãã®ã§flatMapã使ããªããã§ããã
æ£ããã¯ããã§ãã
for { edcba <- obj dcba = edcba.value cba <- dcba.value ba = cba.value a <- ba.value } yield a.value
ãã¼ããããã©ããéãã§ãã(ââ¸â)
ãã¨ã®case classã®valueãå ¨é¨Optionã«ããã°è¯ããã§ãããããã ã¨ãããã¯å¿ é è¦ç´ ã§ããã¯ãªãã·ã§ã³è¦ç´ ã§ã»ã»ã»ãã¨ãã£ãç¥èãåã§è¡¨ç¾ãããã¨ãåºæ¥ãªããªã£ã¦ãã¾ãã¾ãã ãã¨ï¼å人çãªæè¦ã§ããï¼ãCoffeeScriptã»ã©ã·ã³ãã«ã«ã¯æ¸ãã¦ããªãã¨æãã¾ãã
ã¨ãããã¨ã§ããã£ã¡ãã¢ã¯ã»ã¹ã§ãããã®ãä½ããã¨æãç«ã¡ã¾ããããã¿ãã¬ããã¨ãçµå±åºæ¥ã¾ããã§ããã(ââ¸â)ããããè²ã Scalaã®æ©è½ã使ããã®ã§ãããããåå¼·ã¡ã¢ã¨ãã¦è¨äºã«æ®ãã¦ããã¾ãã(´・_ï½¥`)
å¶ç´ç
ãããªãå®è£ ããã®ã¯é£ããã£ãã®ã§ãã¾ããcase classã®ãã£ã¼ã«ãåã¯å ¨é¨valueãã¨ããå¶éãã¤ãããã¼ã¸ã§ã³ãä½æãã¾ããã
ã¾ããåä½ã¤ã¡ã¼ã¸ããã§ãã
package OptionValueAccessor import OptionValueAccessor._ object OptionValueAccessorTest { case class A(value: Int) case class B(value: Option[A]) case class C(value: Option[B]) case class D(value: Option[C]) case class E(value: D) def main(args: Array[String]): Unit = { val edcba = Some(E(D(Some(C(Some(B(Some(A(1))))))))) println(edcba.?.?.?.?.?) // Some(1) val ednon = Some(E(D(None))) println(ednon.?.?.?.?.?) // None } }
?.
ã¨ããã¡ã½ããå¼ã³åºãã¯Scalaçã«ãã¤ããã ã£ãã®ã§.?
ã¨ãã¾ãããã¾ãããã§ã大æ ã¯åé¡ãªãã¯ãã§ãã
ï¼ã¡ãªã¿ã«?
ã¨ããã¡ã½ãããå®ç¾©ãããå ´åã¯ã def ?: T = ...
ã¨ããã¨ã¨ã©ã¼ã«ãªãã®ã§ã def ? : T = ...
ã®ããã«åè§ã¹ãã¼ã¹ã空ãã¾ãããï¼
ä¸è¨ã®ããã«.?
ãããã§ã¼ã³ãããã¨ã§å
å´ã®å¤ã«ã¢ã¯ã»ã¹ãããã¨ãã§ããããéä¸ã§Noneãæã¾ã£ã¦ãããéä¸ã§è©ä¾¡ãããã¦Noneãè¿ããããã«ãªã£ã¦ãã¾ãã?
ã ããã§èªã¿ã«ããã§ããã©ã»ã»ã»ã(´・_ï½¥`)
ãã®ãããªåä½ãè¡ãããã«ãä»åã¯ãã¯ãã使ã£ã¦?
ã¡ã½ãããå®ç¾©ãã¾ããã
package OptionValueAccessor import scala.language.experimental.macros import scala.reflect.macros.whitebox.Context object OptionValueAccessor { implicit class OptValue[A, B](val self: Option[A])(implicit ev: A <:< {def value: B}) { def ? : Option[B] = macro Impl.optValImpl[A, B] } implicit class OptOpt[A, B](val self: Option[Option[A]])(implicit ev: A <:< {def value: B}) { def ? : Option[B] = macro Impl.optOptImpl[A, B] } object Impl { def optValImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context): c.Expr[Option[B]] = { import c.universe._ c.Expr[Option[B]](q"${c.prefix}.self.map {_.value}") } def optOptImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context): c.Expr[Option[B]] = { import c.universe._ c.Expr[Option[B]](q"${c.prefix}.self.flatten.map {_.value}") } }
https://gist.github.com/matsu-chara/702b7046eb890c4c0fe4
ã¨ãã£ã¦ãããªãã®ãã¨ã¯ãªã?
ã¡ã½ãããå¼ã³åºããã¤ã³ã¹ã¿ã³ã¹ã®åãOption[Option[A]
ãªã®ãOption[A]
ãªã®ããè¦åãã¦ã?
ã®é¨åãmap {_.value}
ãflatten.map {_.value}
ã«ç½®ãæãã¦ããã ãã§ããï¼ã¶ã£ã¡ãããã¯ãè¦ããªããã§ãããå¾ã»ã©valueã®é¨åãå¯å¤ã«ãããã£ãã®ã§ãã¯ããå¿
è¦ããªï¼ã¨æã£ãã®ã§ç·´ç¿ã¨ãã¦ãã¡ãããã¯ãã§ä½ãã¾ãããï¼
ã¡ãªã¿ã«ãA <:< {def value: B}
ã®ãããªåæå®ã§ãããããã¯generalized type constraintsã¨ãããã®ã§ããAãvalue: B
ã¨ããã¡ã½ãããæã£ã¦ãããã¨ãã«ã ãå¼ã³åºããã¡ã½ãããå®ç¾©ã§ãããã®ã§ãã*2詳ããã¯Scalaで<:<とか=:=を使ったgeneralized type constraintsがスゴすぎて感動した話 - ( ꒪⌓꒪) ゆるよろ日記ã§è§£èª¬ããã¦ãã¾ãã
Type Dynamic
ããã»ã©ã®ä¾ã¯.value
ã§åºå®ããã¦ããä¸ã«?
ã ããã§èªã¿ã«ããã£ãã®ã§ããªãã¨ã?foo.?bar.?baz
ã®ãããªå¼ã³åºãã«ãããã¨ããã§ããããããScalaã§ã¡ã½ããå¼ã³åºããæååã§åãåã£ã¦ãå¥ã®ã¡ã½ããå¼ã³åºãã«ããæ¿ããä¸ã«åãã§ãã¯ãåºæ¥ããªãã¦ç¡çã ããªã¼ããããªãããªã¼ã¨æã£ã¦ããæã
Type Dynamic を type safe に扱う方法 - seratch's weblog in Japaneseã¨ããè¨äºã§Type Dynamicã¨ããã¾ãã«ã¡ããã©æ±ãã¦ãããã®ããããã¨ãçºè¦ãã¾ããã
ããã使ãã¨ã以ä¸ã®ããã«_ãªãã¨ã
ã¨ããã¡ã½ãããå¼ã³åºãã¨ãå®éã«ã¯ã¢ã³ãã¼ã¹ã³ã¢ãåãè½ã¨ãããªãã¨ã
ã¨ããã¡ã½ãããå¼ã°ãããããªç¶æ³ï¼ããããªãã¨ã
ãç¡ãå ´åã¯ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªãç¶æ³ï¼ãä½ãåºããã¨ãåºæ¥ã¾ãã
ããæ¹ã¯ç°¡åã§ãextends Dynamic
ãã¦ãdef selectDynamic(name: String)
ãç¨æããã ãï¼
ä¸è¨ã®ä¾ã§ã¯Exmaple
ã¯ã©ã¹ã®value
ãã£ã¼ã«ãã«e._value
ã®ããã«ã¢ã³ãã¼ã¹ã³ã¢ä»ãã§ã¢ã¯ã»ã¹ãã¦ãã¾ããï¼ã¾ããã¦ãType Dynamicã ããªããã¯ãã¯ä¸è¦ã§ããããã£ã¼ã«ããåå¨ããªãã£ãå ´åã«ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãããå ´åã¯å¿
è¦ã§ããï¼*3
package TypeDynamic import scala.language.experimental.macros import scala.reflect.macros.whitebox import scala.reflect.macros.whitebox.Context object TypeDynamic { class Example() extends Dynamic { val value: Int = 2 def selectDynamic(name: String): Int = macro selectDynamicImpl } def selectDynamicImpl(c: whitebox.Context)(name: c.Expr[String]): c.Expr[Int] = { import c.universe._ // "_"ãåãè½ã¨ã val nameStr: String = name.tree match { case pq"${n: String}" if n.startsWith("_") => n.drop(1) case _ => c.abort(c.enclosingPosition, s"#$name does not start with _") } c.Expr[Int](q"${c.prefix}.${TermName(nameStr)}") } }
å®è¡ç¨ã®ã³ã¼ãã¯ãã¡ãã
package TypeDynamic import TypeDynamic._ object TypeDynamicTest { def main(args: Array[String]): Unit = { val e = new Example() println(e._value) // e.valueãå¼ã³åºããã¦2ã表示ãããã } }
https://gist.github.com/matsu-chara/e34bc9b03674a20c9f41
?ã¡ã½ããã¨Type Dynamicã®èå
Type Dynamic�
ã¡ã½ãããçµã¿åãããã°ããæãã«è¡ããããã¼ãââ (ภËÏË )ว â¾â¾ã¨æã£ãã®ã§ãããScalaã§ã¯?hoge
ã®ãããª?ã®å¾ã«ä½ããç¶ãã¡ã½ããå¼ã³åºããèªãããã¦ãã¾ããã§ããã(´・_ï½¥`)
ãããããªãã®ã§_hoge
ã§å¼ã³åºãã¨ãªãã·ã§ã³ãçªãæãã¦ã¢ã¯ã»ã¹ã§ããããã«ãããã¨ã«ãã¾ããã
å®è£ ä¾ã¯ãã¡ãã§ãã
package OptionValueAccessor import scala.language.experimental.macros import scala.reflect.macros.whitebox object OptionValueAccessor { implicit class OptValue[A, B](val self: Option[A])(implicit ev: A <:< {def value: B}) extends Dynamic { def selectDynamic(name: String): Option[B] = macro Impl.Opt.selectDynamicImpl[B] } implicit class OptOpt[A, B](val self: Option[Option[A]])(implicit ev: A <:< {def value: B}) { def selectDynamic(name: String): Option[B] = macro Impl.OptOpt.selectDynamicImpl[B] } object Impl { object Opt { def selectDynamicImpl[B: c.WeakTypeTag](c: whitebox.Context)(name: c.Expr[String]): c.Expr[Option[B]] = { import c.universe._ val nameStr: String = name.tree match { case pq"${n: String}" if n.startsWith("_") => n.drop(1) case _ => c.abort(c.enclosingPosition, s"#$name not found.") } c.Expr[Option[B]](q"${c.prefix}.self.map {_.${TermName(nameStr)}}") } } object OptOpt { def selectDynamicImpl[B: c.WeakTypeTag](c: whitebox.Context)(name: c.Expr[String]): c.Expr[Option[B]] = { import c.universe._ val nameStr: String = name.tree match { case pq"${n: String}" if n.startsWith("_") => n.drop(1) case _ => c.abort(c.enclosingPosition, s"#$name not found.") } c.Expr[Option[B]](q"${c.prefix}.self.flatten.map {_.${TermName(nameStr)}}") } } } }
ããããããæã£ãããã«ã¯åãã¾ããã§ããã(ââ¸â)
ä¸å¿ãåä½ããã³ã¼ãä¾ã¯ãã¡ãã§ãã
package OptionValueAccessor import OptionValueAccessor._ object OptionValueAccessorTest { case class A(value: Int) case class B(value: Option[A]) case class C(value: Option[B]) case class D(value: Option[C]) case class E(value: D) def main(args: Array[String]): Unit = { val edcba: Option[E] = Some(E(D(Some(C(Some(B(Some(A(1))))))))) println( edcba .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") ) val edcbnone = Some(E(D(None))) println( edcbnone .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") .selectDynamic("_value") ) } }
https://gist.github.com/matsu-chara/de8b85b6bf21f5fa977c
ãªãããã®selectDynamicå°çã¯ï¼æå³ãªããããï¼
ã¡ããã¨èª¿ã¹ããã¦ãªãã®ã§ç¢ºè¨¼ãå
¨ãç¡ãã®ã§ããããType Dynamicã«ããã¡ã½ããå¼ã³åºãã®selectDynamic
ã¸ã®å¤æãã¨ãimplicit classã«ããæé»ã®åå¤æãã¯ä¸¡ç«ããªãã¿ããã»ã»ã»ï¼ã§ãã(調ã¹ãéãã§ããåºæ¥ãªããã¨ããè¨è¿°ã¯ãªãã£ãã®ã§ããããããã§ããããããã¾ãããï¼
ããä¸ã¤åé¡ããã£ã¦ãOptValue
ã¨OptOptValue
ã®å®ç¾©ã«{def value: B}ã¨ãã¦ããã£ã¼ã«ãåããã¼ãã³ã¼ãã£ã³ã°ãã¦ããã®ã§ãåè¿°ã®åé¡ã解æ¶ãã¦ãã¾ã äºå®éãã«ã¯åãã¾ããããããã©ãããã°åé¿ã§ããã®ããã¾ãã¡ã¢ã¤ãã¢ãããã¾ããã§ããã
課é¡
以ä¸ã®ãããªæãã§é常ã«ä¸éå端ãªã®ã§ãããç¾ç¶ã®èª²é¡ç¹ãã¾ã¨ãã¾ãã
CoffeeScriptã®åå¨æ¼ç®åã¯
?.
ã ããä»åä½ããã®ã¯.?
ã?hoge
ã®ãããªã¡ã½ããå¼ã³åºããåºæ¥ãªãã®ã§_hoge
ã§å¦¥åãType Dynamicã使ããã¨ãã¦ãimplicit conversionã¨ä¸¡ç«ããªã(?)ãããæ示çã«selectDynamicãå¼ã³åºãå¿ è¦ãããã
def hoge: X
ã®ãããªæ§é çé¨ååã使ç¨ãã¦ããã®ã§ãType Dynamicã使ã£ã¦ãçµå±æ±ç¨çãªãã£ã¼ã«ãã«ã¯ä½¿ããªãã(大éã®implicit classãå®ç¾©ããã°ãã£ã¼ã«ãåã1~5æåãªã使ããã¿ãããªãã¨ã¯ã§ããããã)
ãã¼ããããã¯ã¡ãã£ã¨èª²é¡å±±ç©ã¿ã§ããã©ããããªã£ã¦ããã¯ãªã¢ããã®ãé£ããããªã®ã§ä»åã¯ãã®è¾ºã§çµããã¨ãã¾ãã(´・_ï½¥`)
ããããããã¤ã³ã¿ã¼ãã§ã¼ã¹ã®å¤æ´(ãã¨ãã° .?hoge
ã諦ãã¦?("hoge")
ã¨ããã)ããããã¡ãã£ã¨ä½ããã¯ããã¯ã使ã£ãããåæ©çãªè¦è½ã¨ããçºè¦ããã°ãããããããã¾ããã»ã»ã»ã
åèæç®
åå¨æ¼ç®åã«ã¤ã㦠CoffeeScript入門 - プログラムdeタマゴ
assertEqualã®ãµã³ãã«ããããããã®Scalaãã¯ãã®æ¸ãæ¹ã®åèã«ãã¾ããã Scalaのマクロの基礎。評価タイミング、評価回数と、健全性 - scalaとか・・・
å ¬å¼ã®ãã¯ãããã¥ã¡ã³ã Macros - ユースケース - Scala Documentation
åå¶ç´ã«ä½¿ã£ãgeneralized type constraintsã«ã¤ãã¦ï¼åéã«æãã¦ãããã¾ãããï¼ Scalaで<:<とか=:=を使ったgeneralized type constraintsがスゴすぎて感動した話 - ( ꒪⌓꒪) ゆるよろ日記
Type Dynamicã«ã¤ã㦠Type Dynamic を type safe に扱う方法 - seratch's weblog in Japanese
*1:å ã®åé¡ã¨éããããï¼ã¨ããã¤ã£ãã¿ã«ã¤ãã¦ã¯å¾è¿°ãã¾ãã»ã»ã»ã
*2:Option#flattenãªããããã®å¶ç´ã使ã£ã¦ãã¦ãflattenèªä½ã¯Optionã®ä»ã®ã¡ã½ããï¼ä¾ãã°isEmptyãªã©ï¼ã¨ä¸ç·ã«å®ç¾©ããã¦ããã®ã§ãããflattenã¯ããã®å¶ç´ã使ããã¨ã§AãOption[B]ã®ã¨ãã®ã¿ï¼ã¤ã¾ãOption[A] = Option[Option[B]ã®ããã«ãã¹ããã¦ããã¨ãã®ã¿ï¼å¼ã³åºããã¡ã½ããå®ç¾©ã«ãªã£ã¦ãã¾ãã
*3:ä»åã¯ãã§ãã¯ãé©å½ãªã®ã§ã³ã¼ãä¸ã§ããã£ã¼ã«ãã確èªãã¦abortï¼ã¿ãããªãã¨ã¯ãã¦ãªãã®ã§ãããä¸å¿ã¨ã©ã¼ã¡ãã»ã¼ã¸ããããã«ããã ãã§ã¨ã©ã¼ã«ã¯ãªãã¾ãã