Stringãè¦ç´ ã«æã¤ä»»æã®ã³ã¬ã¯ã·ã§ã³ã«grepãé©ç¨ã§ããããã«ãã - ãããã¯Scalaã®æé»é¢ã«ã¤ãã¦
2011/07/03:æ«å°¾ã«è£è¶³ã追è¨ãã¾ããã
id:xuwei ããã®エントリããå¼ç¨ãã¾ãã
æè¿ã¡ãã£ã¨Rubyãã£ã¦ãããã¾ããã§ãRubyã®Enumerableã«grepã£ã¦ããã¡ã½ãããããããããã©ãScalaã«ã¯ç´æ¥å¯¾å¿ãããã®ããªãã®ã§ãããªãéã«ã¤ãã£ã¦ã¿ã
誰å¾ï¼(ã»Ïã»ï½)ã£ã¦ããããã¸ã§ããªãã¯ã«ãããã¨ãããæå¤ã¨é£ããã¦ã§ããªãã£ã*1ãã ãã©ã©ãããã®ã»ã»ã»Scala1å¹´å以ä¸ãã£ã¦ã¦ãããªãã¨ãã§ããªãã¦æ»ã«ãã orz
ã¾ãã id:xuwei ããããæ¬æ¥æºããããä»æ§ãå®ç¾ããã®ã¯ãã»ã©ç°¡åãªãã¨ã§ããªãã®ã§*1ãç¹ã«æ°ãããå¿
è¦ã¯ç¡ããã¨æãã¾ãã
説æãé·ããªãã®ã§ãå
ã«çµè«ããè¨ãã¨æ¬¡ã®ã³ã¼ã㧠id:xuwei ããã®è¦æ±ãæºãããã¨ãã§ãã¾ãã
ãã®ã³ã¼ãã¯æ¬¡ã®ããã«ãã¦ä½¿ããã¨ãã§ãã¾ãã
REPLã®ä¾ãè¦ã¦ããã ããã°ãããããã«ãStringãè¦ç´ ã«æã¤ãList, Set, Vectorã«å¯¾ãã¦grepãé©ç¨ãããã¨ãã§ãã¦ãåã³ã¬ã¯ã·ã§ã³ã«å¯¾ããgrepã¯åãéçãªã³ã¬ã¯ã·ã§ã³åãè¿ãã¦ãããã¨ããããã¾ãã
id:xuwei ãããã©ã®ãããªã¢ããã¼ãã試ã¿ãããã®ãã¯ããããªãã®ã§ããããããã次ã®ãããªæãã ã£ãã®ã§ã¯ãªãã§ããããã
import scala.collection.Traversable import scala.collection.generic.CanBuildFrom object PimpGrepToCollection { class GrepCallable[C[X] <: Traversable[X]](tr: C[String]){ def grep[A](regex:String)(func:String => A = identity _)(implicit bf: CanBuildFrom[C[String], A, C[A]]):C[A] = tr.collect[A, C[A]]{ case s if regex.r.findFirstIn(s).isDefined => func(s) }(bf) } implicit def toGrepCallable[C[X] <: Traversable[X]](tr: C[String]): GrepCallable[C] = new GrepCallable[C](tr) }
ãããããã®ã³ã¼ããã³ã³ãã¤ã«ãã¦ã¿ããã¨ããã¨ã次ã®ãããªã³ã³ãã¤ã«ã¨ã©ã¼ãåºã¦ãã¾ãã¾ãã
error: type mismatch; found : scala.collection.generic.CanBuildFrom[C[String],A,C[A]] required: scala.collection.generic.CanBuildFrom[Traversable[String],A,C[A]] }(bf)
ãã®åã¨ã©ã¼ã¯ã
CanBuildFrom[C[String],A,C[A]]
ã
CanBuildFrom[Traversable[String],A,C[A]]
ã®ãµãã¿ã¤ãã§ãªãã®ã§ãã³ã³ãã¤ã«ã§ããªããã¼ãã¨ããäºãè¨ã£ã¦ãã¾ãã
ããã§åé¡ãªã®ã¯ãä½æ
ãã³ã³ãã¤ã«ã§ããªãããã¨ãããã¨ã§ãããããç解ããããã«ã¯ã
Traversable#collect
ã®å®£è¨(ã·ã°ããã£)- Scala/Java5以éã«ãããåãã§ãã¯ã®ææ³
ãç¥ãå¿ è¦ãããã¾ãã
ã¾ãæåã®ç¹ã«ã¤ãã¦ãScala 2.9.0.1ã®APIãªãã¡ã¬ã³ã¹ããå¼ç¨ããã¨ãcollectã®ã·ã°ããã£ã¯
def collect [B, That] (pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That
ã®ããã«ãªã£ã¦ãããã¨ããããã¾ãã
ããã§ã®ãã¤ã³ãã¯ãTraversableåã®å®ç¾©æç¹ã§ãæ¢ã«CanBuildFrom
ã®æåã®åãã©ã¡ã¼ã¿ãTraversable[A]
ã«ãªã£ã¦ãã¾ã£ã¦ãããã¨ã§ãã
次ã«2ç¹ç®ã«ã¤ãã¦ãScala/Java 5以éã®ã¸ã§ããªã¯ã¹ã§ã¯ãã¤ã¬ã¤ã¸ã£ã¨ããææ³ã«ãã£ã¦ãã³ã³ãã¤ã«æã«åãã©ã¡ã¼ã¿æ
å ±ãæ¶å»ãã¾ãããã®ãããåãã©ã¡ã¼ã¿ã«å¯¾ãã¦ä½ãå¶ç´ãæå®ããªãå ´åãAnyã«å®ç¾©ããã¦ããã¡ã½ããããå¼ã³åºããã¨ãã§ãã¾ãããåãã©ã¡ã¼ã¿Aãåã«æã¤å¼xã«å¯¾ãã¦å¿
è¦ãªã¡ã½ãããé©ç¨ã§ããããã«ããã«ã¯ãAã«å¯¾ãã¦é©åãªä¸éå¢ç/ä¸éå¢çãæå®ããå¿
è¦ãããã¾ãã
ä¸è¨ã®èª¤ã£ãã³ã¼ãä¾ã§ã¯ã
class GrepCallable[C[X] <: Traversable[X]](tr: C[String]){ def grep[A](regex:String)(func:String => A = identity _)(implicit bf: CanBuildFrom[C[String], A, C[A]]):C[A] = tr.collect[A, C[A]]{ case s if regex.r.findFirstIn(s).isDefined => func(s) }(bf) }
ã®C[X] <: Traversable[X]
ã®é¨åã該å½ãã¾ã*2ã
ããã§ããã®å®£è¨ã¯ãããã¸ã§ããªãã¯ãªåã³ã³ã¹ãã©ã¯ã¿C
ã¯Traversable
ãç¶æ¿ãã¦ããªããã°ãããªããã¨ãããã¨ã表ç¾ãã¦ãã¾ãã
åé¡ã¯ãtr.collect()
ã®å¼ã³åºãã®åãä¸ä½ä½ã«ãªããã¨ãããã¨ã§ããC
ã®ä¸éå¢çã®æå®ã§ã¯ãTraversable
ãç¶æ¿ãã¦ããã¨ãããã¨ããè¨ã£ã¦ãã¾ãããããtr.collect()
ãå¼ã³åºããã¨ãã¯ãTraversable[String]#collect
ãå¼ã³åºããã¨ãã¨åãããã«åãã§ãã¯ããã¾ãã
åã³Traversable[A]#collect
ã®å®£è¨ãè¦ã¦ã¿ã¾ãããã
def collect [B, That] (pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That
collectã®å¼ã³åºãæã«æ示çã«åãã©ã¡ã¼ã¿B, Thatãæå®ãã¦ããã®ã§ãå®éã«ã¯ã
def collect(pf: PartialFunction[String, A])(implicit bf: CanBuildFrom[Traversable[String], A, C[A]]): C[A]
ã¨ããã·ã°ããã£ãæã£ãcollectã®å¼ã³åºãã«å¯¾ãã¦åãã§ãã¯ãè¡ããã¾ããããã§åé¡ã«ãªãã®ããCanBuildFromå士ã®åã®äºææ§ã§ãã
端çã«è¨ãã¨ã
CanBuildFrom[C[String], A, C[A]] // (å¼ã³åºãå´)
ã¨
CanBuildFrom[Traversable[String], A, C[A]] //(å¼ã³åºããå´)
ã®äºã¤ã®åã®éã«ã¯äºææ§ãç¡ããããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªã£ã¦ãã¾ãã¾ãããªãäºææ§ãç¡ããã¨ããã¨ã
C[String] <: Travrersable[String] // A <: B 㯠A 㯠B ã®ãµãã¿ã¤ãã§ãããã¨ãããã¨ãæå³ãã
ãªã®ã«å¯¾ãã¦ãCanBuildFrom
ã®å®ç¾©ã¯
trait CanBuildFrom [-From, -Elem, +To] extends AnyRef
ã§ããã第ä¸åãã©ã¡ã¼ã¿From
ãåå¤ã¨ãã¦å®ç¾©ããã¦ããããã§ã*3ã
ãã¦ãããã¾ã§ã¯ãä½æ
ãæåã®èª¤ã£ãã³ã¼ããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªããã説æãã¾ããããããã¯åå ã®æ ¹æ¬ã§ã¯ããã¾ããã
æ ¹æ¬çãªåé¡ã¯ãgrepã®å®ç¾©ãå«ãã³ã¼ããã³ã³ãã¤ã«ããæç¹ã§ã¯ãScalaã³ã³ãã¤ã©ã¯C[String]
ã®ãå®éã®åããç¥ãæ段ãç¡ããããC[String]
ãTraversable[String]
ã®ããã«ã¿ãªãã¦åãã§ãã¯ãè¡ãã¨ããç¹ã§ãã
ã³ã¼ããæ¸ãã人éã¨ãã¦ã¯ãC[String]#collect
ã®å¼ã³åºãã«ããã¦ãC[String]
ã®ãå®éã®åã(List[String]
, Set[String]
, ...)ã«åºã¥ãã¦åãã§ãã¯ããã¦æ¬²ããã®ã§ãããScalaã®åã·ã¹ãã ã®å¶éä¸ãããã¯ä¸å¯è½ã§ãã
Scala 2.8ã®ã³ã¬ã¯ã·ã§ã³ã©ã¤ãã©ãªã§ã¯ãããããªããã¼ãªæå·§ãç¨ãã¦ãã®åé¡ç¹ãåé¿ãã¦ãã¾ããã¾ããTraversable[A]#collect
ãå®éã«å®ç¾©ãã¦ãããã¬ã¤ãã§ããTraversableLike
ã®å®£è¨ãè¦ã¦ã¿ã¾ãã
trait TraversableLike [+A, +Repr] extends /* æ¬é¡ã«é¢ä¿ãªãã®ã§çã ... */ { //... def collect [B, That] (pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That //... }
Traversable
ã¨æ¯è¼ããã¨ã
- ãã¬ã¤ãã®å®£è¨ã§ãè¬ã®åãã©ã¡ã¼ã¿
Repr
ã追å ããã¦ãã
- collectã®å®£è¨ã§ã¯ã
CanBuildFrom
ã«æ¸¡ã第ä¸åãã©ã¡ã¼ã¿ãRepr
ã«ãªã£ã¦ãã
ãã®Repr
ãéè¦ãªã¨ããã§ãåãã©ã¡ã¼ã¿Repr
ã«ã¯ãã³ã¬ã¯ã·ã§ã³ã®å®è£
ã¯ã©ã¹ã»ãã¬ã¤ã(Traversable
, List
...)ãå®ç¾©ããæã«ããã®ã³ã¬ã¯ã·ã§ã³ã®ãå®éã®åãã渡ããã¨ã«ãªã£ã¦ãã¾ãããã®ãããªãã¯ããã¯ã«ãã£ã¦ãã³ã¬ã¯ã·ã§ã³ã®ãå®éã®åãããã¾ãå復ããããã¨ããããã§ãã
ãããè¸ã¾ããä¸ã§ããæ£ãããå®ç¾©ãè¦ã¦ã¿ã¾ãããã
class GrepCallable[C[X] <: TraversableLike[X, C[X]]](tr: C[String]){
C[X]
ã®ä¸éå¢çã«ã¯ãTraversable[X]
ã®ä»£ããã«TraversableLike[X, C[X]]
ãæå®ããã¦ãããã¨ããããã¾ãããã®ããã«ããã¨ãtr.collect
ã®å¼ã³åºãæã«ã¯ãcollectã®åã
def collect(pf: PartialFunction[String, A])(implicit bf: CanBuildFrom[C[String], A, C[A]]): C[A]
ã¨ãªãã¾ãããã®
CanBuildFrom[C[String], A, C[A]]
ã¨ããåã¯ãcollectã®å¼ã³åºãå´ã«ããbfã®å
CanBuildFrom[C[String], A, C[A]]
ã¨ä¸è´ãããããç¡äºã«ã³ã³ãã¤ã«ãéãããã«ãªãã¾ãã
é·ã
ã¨èª¬æãã¦ãããã¨ãããããããã«ããã®åé¡ã¯ãªããªããã£ãããªãã®ã§ãScalaåå¿è
ã ãã§ã¯ãªããããç¨åº¦Scalaã®çµé¨ããã人ã«ã¨ã£ã¦ãé£ãããã¨æãã¾ãã
ä¸è¬è«ã¨ãã¦ã¯ãã³ã¬ã¯ã·ã§ã³ã«é¢ãããæ±ç¨æ§ãé常ã«é«ãã¡ã½ãããPimp my library*4ã«ãã£ã¦è¿½å ãããã¨ããã¨ãScalaã®åã·ã¹ãã ã«å¯¾ããããç¨åº¦é«åº¦ãªç解ãå¿
è¦ã«ãªãã¾ããã¤ã¾ããScalaã®æé»é¢*5ã«ããç¨åº¦è§¦ããªããã°ãªãã¾ããã
Scalaã®æé»é¢ãå¦ã¶ããã«ã©ã®ç¨åº¦ã®æéãå¿
è¦ãã«ããã®ã§ãããä»åã®ãããªã±ã¼ã¹ã§ List éå®ã§ grep ã¡ã½ããã追å ããããã«ããã®ã¯ããããªãã«å¦¥å½ãã¨æãã¾ãã
ã¡ãªã¿ã«ãC++ã®ãã³ãã¬ã¼ãã§ã¯ãã¡ã½ããå®ç¾©æç¹ã§ã¯åãã©ã¡ã¼ã¿ã«é¢ããæä½ã®æ£å½æ§ããã§ãã¯ããªããã*6ããã®ãããªåé¡ã¯çºçãã¾ããããä¸æ¹ã§ãåå²ã³ã³ãã¤ã«ã®å®è£
ã¯å®¹æã§ã¯ããã¾ãããScalaã®ãããªã·ã¹ãã ã§ã¯ãä¸è¨ã®ãããªåé¡ãèµ·ãã代ããã«ãåå²ã³ã³ãã¤ã«ã容æã«å®è£
ãããã¨ãã§ãã¾ãã
è£è¶³(éè¦)ï¼ãã®ã¨ã³ããªã§ã®è¶£æ¨ã¯ãStringãè¦ç´ ã«æã¤ä»»æã®ã³ã¬ã¯ã·ã§ã³ã«grepãé©ç¨ã§ããããã«ãã¤ã¤ããã¤ãScalaã³ã¬ã¯ã·ã§ã³ã©ã¤ãã©ãªã®åºæ¬ææ³ã§ãããæ»ãå¤ååãã®ååãéµå®ãããã¨ããã¨è¤éã«ãªãã¨ãããã®ã§ãã
強調ããé¨åãæ示ãã¦ããªãã£ãã®ã§ãã³ã¬ã¯ã·ã§ã³ã«ã¡ã½ããã追å ããã ãã§ããã ãè¤éãªäºãç¥ããªããã°ãããªããã¨èª¤è§£ãããããããã¾ãããå®éã«ã¯ããæ»ãå¤ååãã®ååãå®ããªãã¦ããã®ãªãã
import scala.collection.Traversable import scala.collection.generic.CanBuildFrom object PimpGrepToCollection { class GrepCallable[X](tr: Traversable[String]){ def grep[A](regex:String)(func:String => A = identity _):Traversable[A] = tr.collect{ case s if regex.r.findFirstIn(s).isDefined => func(s) } } implicit def toGrepCallable[A](tr: Traversable[String]): GrepCallable[A] = new GrepCallable[A](tr) }
ã¨ããã³ã¼ããæ¸ãã ãã§OKã§ããããã§ãã»ã¨ãã©å ¨ã¦ã®ã³ã¬ã¯ã·ã§ã³ã«grepã¡ã½ããã追å ã§ãã¾ãããã ããgrepã®æ»ãå¤ã¯å¿ ãTraversableã«ãªã£ã¦ãã¾ãã¾ãã
*1:ã³ã¼ãèªä½ã¯ãã»ã©é·ãããã¾ããã
*2:ãã®Xã¯é常ã®åãã©ã¡ã¼ã¿ã§ã¯ãªããé«éåãã©ã¡ã¼ã¿ã¨å¼ã¶ã¹ããã®ã§ããããã®èª¬æãããã¨é·ããªãã®ã§çãã¾ã
*3:å ±å¤ã§ããã°ã³ã³ãã¤ã«ãéãã¾ã
*4:implicit conversionã«ãã£ã¦ã¡ã½ããããå¾ä»ãã§ã追å ãããã¿ã¼ã³ã®ãã¨
*5:ååã¯åè«ã§ãã
*6:ãã®ç解ãééã£ã¦ãããããã³ããé¡ããã¾ã