Custom AST Transformation 㧠ã¡ã¢åã試ãã¦ã¿ã¾ãã
Groovy ASTå¤æã«ããã³ã³ãã¤ã«æã¡ã¿ããã°ã©ãã³ã°ã«ã¤ãã¦ã調æ»ãç¶ç¶ãã¦ãã¾ãã
ä»æ¥ã¯ãç°¡åãªã³ã¼ããæ¸ãã¦ã¿ã¾ãããã³ã³ãã¤ã«ä¸ã« AST å¤æãè¡ããä»»æã®ã¡ã½ãããã¡ã¢åã§ãã¾ãã
ã¨ãããã使ç¨ä¾ãã
@Memoized def fib(n) { if (n <= 1) return n else return fib(n - 1) + fib(n - 2) }
ä¸è¨ã®ããã«ã@Memoized ã¨ã¢ãã¼ãã¼ã·ã§ã³ãã¤ããã¨ããã®ã¡ã½ãããã¡ã¢åããããã㪠Custom AST å¤æãä½ã£ã¦ã¿ã¾ããã
ASTå¤æåä½ã®æ¦è¦ã¯ãä¸è¨ã®ãããªæãã§ãã
- ã¢ãã¼ãã¼ã·ã§ã³ãä»ããããã¡ã½ãããå¥åã«å¤æ´ãã
- å ã®ååã§ã¡ã¢åå¦çç¨ã®ãã£ãã·ã¥åç §é¢æ°ãçæãã
ç¾ç¶ã§ã¯ã1å¼æ°ã®ã¡ã½ããã«ã ã対å¿ãã¦ãã¾ããã¾ã ã¾ã Groovy ã§ã®éçºç°å¢æ´åãåºæ¥ã¦ããªãç¶æ³ã§ãããã«ãã¹ã/ãããã°ãã§ããªãæãæ§ã§ããå®éãã½ã¼ã¹ãã覧ããã ããã°åããã¨ãããã¡ãã»ã¼ã¸ããã¯ã¹ã§ãããã°ã¡ãã»ã¼ã¸ãåºãã¦ããã¨ããç¶æ ãã¨ããããã§ãã¾ãã¯ç°å¢æ´åãé²ãã¦ãããã¨æãã¾ãã
次åã¯ãCustom AST ã³ã¼ãéçºã«ããããã¹ãç°å¢ãªã©ã«ã¤ãã¦èãã¦ããããã¨æãã¾ããç¾ç¶ã¯ãASTå¤æã楽ããã®ã§å£æªãªãã¹ãç°å¢ã§ãæ°ã«ãªããªãã®ã§ããããã®ãã¡ã«å«æ°ãå·®ãã¦ããã§ãããããããã
Groovy å§ãã¾ããã
Groovy ã§ã¯ãAST ãã«ã¸ã¥ã¢ã«ã«å¤æã§ããã¨èãã¾ããããµã¤ã³ã¼ãããªãã§ãããã¨ãããã¨ã§ããããªã AST å¨ãã調ã¹ã¦ãã¾ãã
ã§ãä¸ã¤çåããint + int ã®è¨ç®ã§ããããã¤ã左辺å¤ã®ã³ã³ããã¹ãã int ãè¦æ±ãã¦ããã®ã«ããªãã§ä¸å Object ã«å¤æããããã ããï¼
ã¾ã ã¾ã Groovy ã®ãã¨ã¯ãªãã«ãåãã£ã¦ãã¾ããããããããã³ã³ãã¤ã«æã¡ã¿ããã°ã©ãã³ã°ã«ç²¾é²ãã¦ããããã§ãã
æ¯è¼ã¯ã¢ãã¤ã
æ¯è¼ã¢ããã«ã¤ãã¦èå¯ããã¦ããä¸é£ã®ã¨ã³ããªã«æéãåãã¦ãç§ãæ¯è¼ã«ã¤ãã¦èãã¦ã¿ã¾ããã
ã¾ããèå¯å¯¾è±¡ã¨ãã¦ãæ¯è¼çµæãã¨ãæ¯è¼æä½ãã«åãã¦èãã¾ããæ¯è¼çµæã¨ããã®ã¯ãæ¯è¼å¾ã«è¿ã£ã¦ããå¤(ä¾ï¼Java ã® Comparator ã® compare ã«ããã è² ã»é¶ã»æ£)ãè¨ãã¾ããæ¯è¼æä½ã¨ããã®ã¯ãæ¯è¼ããé¢æ°(ãããã¯é¢æ°ãªãã¸ã§ã¯ã)èªä½(ä¾ï¼Java ã® Compartor
æ¯è¼çµæã¢ãã¤ã
æ¯è¼çµæã¨ããã®ã¯ã2ã¤ã®æ¯è¼å¯¾è±¡ã«å¯¾ãã¦ããã®çæ¹ãä»æ¹ããããå°ããã®ãããçããã®ããã大ããã®ããã示ãå¤ã§ããä¾ãã°ãPerl ã® æ¯è¼æ¼ç®å <=> ã Java ã® Comparator ã«ããã¦ã左辺ãå°ãããã¨ãè² ã®æ´æ°ã§ã左辺ã¨å³è¾ºãçãããã¨ã 0 ã§ã左辺ã®ã»ãã大ãããã¨ãæ£ã®æ´æ°ã§ç¤ºãã¨ãã®ãè² ã®æ´æ°ãã0ããæ£ã®æ´æ°ãã®ãã¨ãæãã¾ãã
æ¯è¼çµæãã¢ãã¤ãã¨ãã¦æ±ã£ã¦ããè¨èªã§ã¯ãæ´åãªã©ã®æä½ãé©ãã»ã©ã¹ãã¼ãã«è¨è¿°ã§ãã¾ãã
ä¾é¡ã¨ãã¦ãããã°ã®ã¨ã³ããªãæ´åããåé¡ãèãã¦ã¿ã¾ããããæ¥ä»ã®éé ã§ä¸¦ã¹ãããæ¥ä»ãåãå ´åã¯ã¨ã³ããªæ¯ã®IDã®æé ã§ä¸¦ã¹ãã¨ããåé¡ã§ãããªããããã°ã®ã¨ã³ããªã示ãã¯ã©ã¹ã®ãã£ã¼ã«ãã«ã¯ããã®ã¨ã³ããªãæ¸ãããæ¥ä»(pubDate)ã¨ãä¸æã®æ´æ°åèå¥å(id)ããããã®ã¨ãã¾ãã
ããã Java ã§æ¸ãã¨ããããªæãã§ãã¤ãã¤ã¨ãã¦ãã¾ãã¾ããã
List<Entry> entries = ...// Entry ãè¤æ°è©°ã¾ã£ã¦ãã Collections.sort(entries, new Comparator<Entry>() { public int compare(Entry e1, Entry e2) { if (!e1.pubDate.equals(e2.pubDate)) { return e2.pubDate.compareTo(e1.pubDate); } else { return new Integer(e1.id).compareTo(e2.id); } } });
ä¸è¨ã«ç¤ºãããã« groovy ã Rubyã ã¨äºæ
ã¯å°ãæ¹åããã¾ãããç¸å¤ãããæ¡ä»¶åå²ããã£ã¦ãããããã£ããããããã¯ãããæå·§çã§ãã£ããã¨ããæããããªãããªãã§ãã
ï¼ã¾ããæå·§çã¨ãã¦ç¤ºããå´ã®ã³ã¼ãã¯æ¯è¼æ¼ç®åã{-1, 0, +1}ãè¿ãã¦ããããåã«{è² , é¶, æ£}ãè¿ããããªããããªãè¡åã®æªãæ¯è¼å¯¾è±¡ã«ã¯ä½¿ãã¾ãããã¨ããããRuby ã®å ´åã¯ã-1, 0, +1 ãè¿ããã¨ãæ¨å¥¨ããã¦ããã ãã§ã-1, 0, +1 ã§ããä¿è¨¼ã¯ãªãã§ããã¤ã¾ãã-1 ã +1 ã§ã¯ãªãã¦ãåãªãè² ã®æ°ãåãªãæ£ã®æ°ãè¿ã£ã¦ãã¦ããè¿ãå´ã¯ãæ£å¸¸åä½ããªã®ã§ãæå·§çãªã»ãã®ã³ã¼ããåãä¿è¨¼ã¯ãªãã§ããï¼
#-- æ®éã«æ¸ãã¦ã¿ãã³ã¼ã entries.sort { |e1, e2| if e1.pubDate != e2.pubDate e2.pubDate <=> e1.pubDate else e1.id <=> e2.id end } #-- ããæå·§çãªã³ã¼ããï¼<=>ãè¿ãå¤ã®ç¯å²ã¯{è² , é¶, æ£} ã§ã¯ãªã å¿ ã{-1, 0, +1}ãè¿ãã¦ããããã¨ãæå¾ ï¼ entries.sort { |e1, e2| 2 * (e2.pubDate <=> e1.pubDate) + (e1.id <=> e2.id) }
éã«æ´å²çã«å¤ã perl ã®ã»ããããããæ¬è³ªãè¦äºã«è¡¨ç¾ã§ãã¾ããpubDate ã§æ¯è¼ãã¦ããã§ã決ã¾ããªããã° id ã§æ¯è¼ããã¨ããæ¬è³ªãã
sort { my ($e1, $e2) = @_; ($e2->{pubDate} <=> $e1->{pubDate}) || ($e1->{id} <=> $e2->{id}) } @entries;
è¿½è¨ 2011-06-20
å½åãä¸è¨ã® Rubyã³ã¼ã ã¯Groovyã³ã¼ãã§ãããã¾ãããGroovyãRubyã§ã¯ãã¨è¨ãã¦ãã¾ãããããã®é¨åãä¿®æ£ãã¾ãããã³ã¡ã³ãæ¬ã§ id:deve68 ããããææã®éãã?: æ¼ç®åã使ãã°ã¹ãã¼ãã«è§£æ±ºã§ãã¾ãã
entries.sort { e1, e2 -> (e2.pubDate <=> e1.pubDate) ?: (e1.id <=> e2.id) }
(追è¨ããã¾ã§ãä»ã®è¿½è¨ã»åé¤ç®æã¯>ins<ã«ããä¸ç·ã>del<ã«ããææ¶ç·ã§ç¤ºãã¾ãã)
ã§ãPerl ãGroovyã ã¨ä¸æãæ¸ããçç±ãçªãè©°ããã¨ãæ¯è¼æ¼ç®å <=> ã®çµæãã¢ãã¤ãã ããã ã¨æãã¾ãããæ´æ°ãæ¯è¼çµæã¨ã¿ãªããã¨ãã|| ãå群ã®äºé æ¼ç®ã«ãªã£ã¦ãã¦ã0ãåä½å ãªã®ã§ããã£ï¼
ããå°ã説æã試ã¿ãã¨ãã¢ãã¤ãã¨ããã®ã¯ãåä½å ãæã¤å群ã®ãã¨ã§ãã
å群ã¨ããã®ã¯ã2ã¤ã®è¦ç´ (ã¤ã¾ããããã§ã¯æ¯è¼çµæ)ã2é æ¼ç®ã§ãã£ã¤ã1ã¤ã®è¦ç´ ã«ã§ãã2é æ¼ç®(ããã§ã¯ ||)ãå®ç¾©ããã¦ããéå(ããã§ã¯æ¯è¼çµæã§ãããè² ã®æ´æ°ãã0ããæ£ã®æ´æ°ã)ã§ããã¾ãããã®å群ã«ãããåä½å ã¨ã¯ãç¸æã®è¦ç´ ã¨2é æ¼ç®ã§ãã£ã¤ãã¦ããç¸æã®è¦ç´ ãå¤åããªãè¦ç´ ã®ãã¨ã§ããããã§ã¯ã0ã®ãã¨ã§ãã
Perl ã® || ã¨ããæ¼ç®åã®æåã£ã¦ãç¾ä»£ç観ç¹ããã¿ã¦ãé©ãã»ã©ãã¡ãã¨èãããã¦ãã¦ãåã«OR(è«çå) ã¨ããã ãã§ãªããããããåãã®åä½ãä¸è¬åãããã®ã«ãªã£ã¦ãã¾ããä¾ãã°ãscala ã«ããã Option ã¢ããã® orElse åä½ã«ç¸å½ããåä½ããPerl ã® || ã«ã¯å«ã¾ãã¦ãã¾ãã (null || value)ã¨æ¸ãã°ãã¡ãã㨠value ãè¿ã£ã¦ãã¾ãããã¡ãªã¿ã«ããã® orElse ã£ã¦ã仮㫠Maybe/Optionã¢ãã ã® MonadPlusçãªããã®ãããã¨ããã°ã確å®ã« plus === orElse ã¨å®ç¾©ããã®ãçã«ããªã£ã¦ããããã Plus ãªãã§ããã
ã§ãscala ã®è©±ã«ãªãã¾ãããscalaæ¨æºã£ã¦ãé©ãã»ã©ã¤ã±ãã¤ããªããscala.math.Ordering#compare ã«ãã£ã¦è¿ãããæ¯è¼çµæã®ä½ãã¤ã±ã¦ããªããã¨è¨ãã°ãããããããé©ãã»ã© Java ãªãã§ããããããè¿ãå®ä½ã¯ Java ã Perl ã Groovy ããã¯ãã¾ããC ã® strcmp ã§ãããåãã§ãæ´æ°ã®è² ã»é¶ã»æ£ãªãã§ããããã®è¿ã£ã¦ããå¤ãã©ãè¦åãã®ãããã¡ãã¡ã§ãã¦ãscala æ¨æºã¯ãPerlã«å ¨ç¶åã°ãªããå°ãªãã¨ãç§ã® scala å®åã«ããã¦ã¯ãscala ã§ã®ã¹ãã¼ããªã³ã¼ãã¯æãæµ®ãã°ãªãã§ããsorted ã® implicit ãªå¼æ°ã« Ordering ãæ示çã«æ¸¡ãã®ãã¹ãã¼ãã§ã¯ãªããsortWith 㯠less ãå¦ãã Boolean ã§è¿ãã ããªã®ã§(minimalism ã®ç¹ã§ã¯ãç§ã¯å¥½ãã ããã©)ãOrdering ã Comparator ã®ç¸æ§ãå¾®å¦ã§ãããããªããããã scala ã®æ´åã®æ¥é¨ã¨ããæããããªãããªãã®ã§ããªãããããããã³ã¼ããè¼ããæ°ããã¾ããã(æ®æ®µã¯ãããããã³ã¼ããæ¸ãã¦ãã¾ãããã©ãã)
ããã§ã試ãã«ãããã¦ãæ®æ®µã¯çµ¶å¯¾ã«æ¸ããªããããªæ¸ãæ¹ããã¦ã¿ã¾ãã
// æ£å¸¸åä½ããããã©ãæ¸ãæã®æå³ãåããã«ããã¦ã³ã³ã¼ã entries.sortBy { e => e.pubDate -> (-1-e.id) }.reverse
ãã¡ããããã®ã³ã¼ãããã¡ãä½ããã¡ãã¨ããã¨ãä¸è¦ããã ãã§ã¯ä½ãããããä¸æã ããæ¡å¼µæ§ã«ä¹ããããã§ãããã¾ããè¬ãããã®ã³ã¼ãçãè¦ã¦æå³ãä¸ç®çç¶ã§æ¡å¼µã®ä»æ¹ãæ³å®ã§ãã人ã°ããã®ä¸çã§ãã£ãã¨ãã¦ããæ¯è¼æ¯ã« Tuple2 ãçæãããreverseãããã§ããã©ã¼ãã³ã¹ãæªãã§ãã
ããã§ãæºãæãã¦ç»å ´ããã®ã ScalaZã©ã¤ãã©ãªã§ãã
ScalaZ ã®ä½ãããããã£ã¦ããã¨ããæ¯è¼çµæã¯ã¢ãã¤ãã ãã£ã¦æ示çã«è¨æãã¡ãã£ã¦ãã®ã§ãããæ£ç¢ºã«ã¯ãã¾ããæ¯è¼å¯è½ãªãã®ã«å¯¾ãã¦ã¯ Order ã¨ããåã¯ã©ã¹ãå®ç¾©ããç´æã«ãªã£ã¦ãããã§ãããã§ãOrder ã®ã¤ã³ã¹ã¿ã³ã¹ã¡ã½ãã order ã«ããæ¯è¼çµæã«å°ç¨ã®ä»£æ°çãã¼ã¿å(scalaz.Ordering = LT | EQ | GT)ãä½ã£ã¦ãããã§ããããã¼ãåå®å ¨ã§ãããããã«ãããã¤ã«å¯¾ããåã¯ã©ã¹ Semigroup 㨠Zero ãåãã£ã¦ããï¼ããªãã¡ãscalaz.Ordering ãåä½çå群â¡ã¢ãã¤ãã§ããï¼ã®ã§ããã
ã¤ã¾ãããããªãã¨ããã§ãããã§ãã
entries.sorted(OrderOrdering(order{ (e1: Entry, e2: Entry) => (e2.pubDate ?|? e1.pubDate) |+| (e1.id ?|? e2.id) }))
è¦ç¹ã¯ããã§ãï¼
(e2.pubDate ?|? e1.pubDate) |+| (e1.id ?|? e2.id)
?|? ã¯ãæ¯è¼æ¼ç®åãOrderåã¯ã©ã¹ãåãã£ã¦ããä»»æã®åã®ã¤ã³ã¹ã¿ã³ã¹å士ãæ¯è¼ããæ¼ç®åã¡ã½ãããæ¯è¼çµæã¯ãscalaz.Ordering (scala.math.Orderig[T] ã¨ã¯å¥ç©)ãã§ããã® scalaz.Ordering ã¯ã¢ãã¤ãã§ããããã£ã¤ããæ¼ç®ã |+| ãªãã§ããEQãåä½å ãªã®ã§ãããã¨ã念é ã«ããã°ããçæ¹ã EQ ã§ããã°ãä»æ¹ã®çµæãè¿ãï¼ã©ã¡ããEQã§ãªããªãã°ãå·¦å´ï¼ããªãã¡åªå å´ï¼ãè¿ããã¨ãããã¨ã¯ãã»ã¨ãã©èªæãã¤èªç¶ã
ããããPerl ã¨éã£ã¦ãscala/scalazã¯åå®å ¨ãªãã§ãï¼ï¼ï¼ï¼
æ¯è¼æä½ã¢ãã¤ã
ã§ãããã¾ã§ã¯ãæ¯è¼çµæ(= LT, EQ, GT ã¨ã -1, 0, +1 ã¨ã)ãã¢ãã¤ãã¨è¦åãã¨ã¦ã¬ã·ã¤ï¼ããå®é scalaz ã§ã¯ ã¢ãã¤ãï¼ã¨ãããã¨ã«ã¤ãã¦ã§ããã
次ã«ãæ¯è¼æä½(= Comparator ã¨ã <=> ã¨ã)ã¯ãä½ãªã®ï¼ã©ã®ããã«è¦åãã°ä¸çãã·ã³ãã«ã«è¦ããã®ããã¾ãåãã®ï¼ã£ã¦ãã話ã§ãã
ã¾ãã¯ããããå°ã¨ãã¦ãã¨ããããã¢ãã¤ãã«ãã¦ã¿ã¾ããã
æ¯è¼æä½ã®å群ã®ããã®2é æ¼ç®ã¯ãå°æ¥çã« apply ãããã¨ã(= æ¯è¼æä½ãè¡ãããã¨ãã«)ã左辺ã EQ ãè¿ããªãã°å³è¾ºã«å¤æãå§è²ãã左辺ãGT/LTãè¿ããªãã°ãã®çµæãè¿ãããããªæ¯è¼æä½ãè¿ããããã§ãåä½å 㯠EQãã¨ãããããªæãã§ãã
// Order(scalaz ã®æ¯è¼å¨)ãã¢ãã¤ãã«ããããã®åã¯ã©ã¹ trait OrderAsMonoid { // å群ãä¸ãã implicit def OrderSemigroup[T]: Semigroup[Order[T]] = semigroup { (o1, o2) => order{ (x, y) => o1.order(x, y) |+| o2.order(x, y) } } // åä½å ãä¸ãã implicit def OrderZero[T]: Zero[Order[T]] = zero(order{(x, y) => EQ}) }
ä¸è¨ã®ããã« Order ã«å¯¾ããã¢ãã¤ãåã¯ã©ã¹ãå®ç¾©ããã¨ãä¸è¨ã®ãããªæãã®ãã¨ãã§ãã¾ãã
import scalaz._ import scalaz.Scalaz._ import java.util.Date object OrderMonoidTest extends App with OrderAsMonoid with OrderLow { // Entry ã pubDate ã®éé ã§ä¸¦ã¹ã Order val orderEntryByPubDateDesc: Order[Entry] = order {(e1, e2) => e2.pubDate ?|? e1.pubDate} // Entry ã id ã®æé ã§ä¸¦ã¹ã Order val orderEntryByIdAsc: Order[Entry] = orderBy {_.id} // OrderAsMonoid ã«ãããä»ã Order èªä½ãã¢ãã¤ããªã®ã§ãOrder èªä½ã |+| ã«ããçµåå¯è½ val orderEntryByPubDateDescOrElseByIdDesc = orderEntryByPubDateDesc |+| orderEntryByIdAsc // scala ã® sorted ãå¼ã³åºãããã«ãscalaz.Order ã scala.math.Ordering ã«å¤æ val theOrderAsScalaOrdering = Order.OrderOrdering(orderEntryByPubDateDescOrElseByIdDesc) val sortedEntries = EntryManager.entries.sorted(theOrderAsScalaOrdering) }
æ¯è¼çµæãã¢ãã¤ãã¨ã¿ãæãã¨ããã®ã¯ãèªåã®ä¸ã§ã¯ããªãããæããããªããã¨æã£ã¦ãã¾ããï¼ç¡è«ãã¢ãã¤ãã¨ããè¦æ¹ãããè¦æ¹ã¨ããã ãã§ãã£ã¦ãä»ã®è¦æ¹ãæªãããã§ã¯ãªãã§ãããã£ã¨ããè¦æ¹ãããããããã¾ãããããã or ãããªããã¨ããã®ã¯æã¨å ´åã«ä¾ãé¨åãããã¨æãã¾ããï¼
ã§ãæ¯è¼æä½ãã¢ãã¤ãã¨ã¿ãæãã¨ããã®ã¯ãã¾ã èªåã®ä¸ã§ããç´å¾ã§ãã¦ããªãé¨åãããã¾ããã¨ããã®ã¯ãç´ ç´ã«èãã¦ãComparator
ã¡ãã£ã¨ãæå¾ã®ã»ããã°ãã°ãã«ãªã£ã¦ãã¾ãã¾ãã^^ï¼
å®ç¨çãªåæ並è¡ã½ã¼ããå®è£ ãã話
scala ã® parallel collection ã¯ãæ®éã® collection ã使ãããã«ä½¿ã£ã¦ããã ãã§ã並åè¨ç®ã®æ©æµãåããããå ´åãå¤ãã®ã§ãããããã§ã¯ãªãå ´åãå¤ãã§ãã
ãã®å ¸åä¾ããã½ã¼ãã§ããå®ã¯ã並åã®ã½ã¼ãã¯ãã¾ã å®è£ ããã¦ãã¾ããã
ããããèªåã§å®è£ ããã°ããã®ããã¨ããã¨ãããã¯ååæ£ããã¦ååééãã§ãã
ã©ãããäºãã¨ããã¨ãã·ã³ã°ã«ã¹ã¬ããã® java.util.Arrays.sort ãã¨ã¦ãé«éãªã®ã§ãããããéãã½ã¼ããèªåã§å®è£ ããã®ã¯é£ããã®ã§ããArrays.sort ãéãã®ã¯ãåã«ã¢ã«ã´ãªãºã ã ãã®åé¡ã§ã¯ããã¾ãããèªå㧠Array ã®æ´åå¦çãæ¸ãã¨ããã¨ãå½ç¶ãé åã®è¦ç´ ã«æ·»åã§ã¢ã¯ã»ã¹ãã¾ããããããã¨ãJVMã¯é åã®ç¯å²å ãã©ããããã§ãã¯ãã¾ãããããã®ãªã¼ãããããããããã«ãjava.util.Arrays.sort ã«åã¤å¦çãèªåã§æ¸ãã®ã¯å°é£ãªã®ã§ãã
ããã§ãjava.util.Arrays.sort ãå©ç¨ãã¤ã¤ã並åã§ã½ã¼ããããå¦çãèãã¦ã¿ã¾ããã
ã¢ã¤ãã£ã¢ã¯ç°¡åã§ãã
- é åãååã¨å¾åã®ï¼ã¤ã«åãã¾ã
- ãããããåæ並è¡ãã¦æ´å(Arrays.sort)ãã¾ã
- æå¾ã«ãã¼ã¸ãã¾ãã
ãããã³ã¼ãã«ç´ãã¾ãããã
import java.util.Arrays abstract class Sorter { def sorted(a: Array[Int]): Array[Int] } // æ®éã®ã½ã¼ã object SimpleSorter extends Sorter { def sorted(a: Array[Int]) = { Arrays.sort(a) a } } // 並è¡ã½ã¼ã object DivideAndMergeParallelSorter extends Sorter { def sorted(a: Array[Int]) = { require(a.length >= 2) import scala.annotation.tailrec import scala.concurrent.ops._ val len = a.length val half = len / 2 // 注ç®é¨åï¼ par(Arrays.sort(a, 0, half), Arrays.sort(a, half, len)) val ret = new Array[Int](a.length) @tailrec def merge(i: Int, j: Int, k: Int) { if (a(j) <= a(k)) { ret(i) = a(j) if (j < half - 1) merge(i + 1, j + 1, k) else System.arraycopy(a, k, ret, i + 1, len - k) } else { ret(i) = a(k) if (k < len - 1) merge(i + 1, j, k + 1) else System.arraycopy(a, j, ret, i + 1, half - j) } } merge(0, 0, half) ret } }
ä¸è¨ã®ããã«å·¥å¤«ããã ãã§ãå¦çæéã4å²ã»ã©åæ¸ã§ãã¾ãã(å½æ¹ã®ç°å¢ã§ 1000000è¦ç´ ã® Array[Int] ãæ´åããã®ã«è¦ããæéã 138[ms] ãã 83[ms] ã«ç縮ã§ãã¾ããï¼
ãã¦ãä¸è¨ã®ã³ã¼ãã¯ãããªãã«å®ç¨çãªãã§ãããã¡ãã£ã¨æ°ã«ãªãç¹ãããã¾ããã
CPUã®ã³ã¢æ°ãããããã£ã¦ã2ã³ã¢ãã使ã£ã¦ããªãã¨ããç¹ã§ãããªãã¨ãªããã£ãããªãã§ããã8ã³ã¢ç°å¢ãªã8ã³ã¢ã使ãããã«æ¸ããªããã¦ã¿ã¾ãããã
object DivideAndMergeParallelSorter2 extends Sorter { def sorted(a: Array[Int]) = { require(a.length >= scala.collection.parallel.availableProcessors) import scala.annotation.tailrec import scala.concurrent.ops._ val nDiv = collection.parallel.availableProcessors // æ´åç¯å²ãã³ã¢æ°ã«å¯¾å¿ããããã«åå² val len = a.length val pslices = (0 until nDiv).par map {i => Arrays.copyOfRange(a, i * len / nDiv, (i + 1) * len / nDiv)} pslices foreach (Arrays.sort _) def merge(a: Array[Int], b: Array[Int]): Array[Int] = { val alen = a.length val blen = b.length val ret = new Array[Int](alen + blen); @tailrec def rec(i: Int, j: Int, k: Int) { if (a(j) <= b(k)) { ret(i) = a(j) if (j < alen - 1) rec(i + 1, j + 1, k) else System.arraycopy(b, k, ret, i + 1, blen - k) } else { ret(i) = b(k) if (k < blen - 1) rec(i + 1, j, k + 1) else System.arraycopy(a, j, ret, i + 1, alen - j) } } rec(0, 0, 0) ret } pslices reduce merge } }
4ã³ã¢ä»¥ä¸((Hyper Threading ã®ã³ã¢ãããªãã¦ãå®ã³ã¢ãããªãã¨ãã¡ããããã¾ããã)))ç°å¢ãªããããã«é«éã«æ´åã§ããããã«ãªãã¾ãããHT8ã³ã¢(å®4ã³ã¢)ã®ç°å¢ã§ã®å®æ¸¬ã§ãã·ã³ã°ã«ã¹ã¬ããã®4å²ã®å®è¡æéã«ã¾ã§ç縮ã§ãã¾ããã
æåå³åã§ãããä¸è¨ã®ææ³ã¯ããããªãã«å®ç¨çã¨è¨ãããã§ã¯ãªãã§ãããããï¼ãã ããä¸è¨ã³ã¼ãèªä½ã¯ãIntéå®ã ã£ããæ´åãããé åã®è¦ç´ æ°ãã³ã¢æ°ä»¥ä¸ã ã¨æ±ºãæã¡ãã¦ããããã¦ãã¾ããããå®éã«ä½¿ãã«ã¯è¥å¹²ã®ä¿®æ£ãå¿ è¦ã§ããï¼
ãã³ããã¼ã¯ä»ãã®ã½ã¼ã¹ã³ã¼ããgithubに上げましたã
scala ãå·¦å¾åããã話
Scala exercises for beginners ã foldLeft ã§è§£ãã¦ã¿ãã
// Exercise 2 def sum(x: List[Int]): Int = x.foldLeft(0){_ + _} // Exercise 3 def length[A](x: List[A]): Int = x.foldLeft(0){(sum, _) => sum + 1} // Exercise 4 def map[A, B](x: List[A], f: A => B): List[B] = x.foldLeft(identity: List[B] => List[B]){(kacc, h) => racc => kacc(f(h) :: racc)}(Nil) // Exercise 5 def filter[A](x: List[A], p: A => Boolean): List[A] = x.foldLeft(identity: List[A] => List[A]){(kxs, x) => (if (p(x)) xs => kxs(x :: xs) else kxs)}(Nil) // Exercise 6 def append[A](x: List[A], y: List[A]): List[A] = x.foldLeft(identity: List[A] => List[A]){(kxs, x) => xs => kxs(x :: xs)}(y) // Exercise 7 def concat[A](x: List[List[A]]): List[A] = x.foldLeft(identity: List[A] => List[A]){(kxs, x) => xs => kxs(append(x, xs))}(Nil) // Exercise 8 def concatMap[A, B](x: List[A], f: A => List[B]): List[B] = x.foldLeft(identity: List[B] => List[B]){(kxs, x) => xs => kxs(append(f(x), xs))}(Nil) // Exercise 9 /** raise error if the list is empty */ def maximum(x: List[Int]): Int = x.reduceLeft{_ max _} //x.foldLeft(Int.MinValue){_ max _} // Exercise 10 def reverse[A](x: List[A]): List[A] = x.foldLeft(List[A]()){(acc, e) => e :: acc} def foldRight[A, B](x: List[A], acc: B, f: (A, B) => B): B = x.foldLeft(identity: B => B){(kacc, h) => racc => kacc(f(h, racc))}(acc)
åèæç®
è足ã§ãããä¸è¨æç®ã® fold == é 延è©ä¾¡çã®foldRight ã«ç¸å½ãã¾ããã5.1 The foldlãã foldLeft ã®è©±ã§ãã
akka ã®ä¾é¡ã parallel collection ã§å®è£
akka の例題ã§ã¯ãarctan(1) ããã¼ã©ã¼ç´æ°å±éãã¦åå¨çãæ±ããã¨ããä¾é¡ãåãä¸ãã¦ãããå ·ä½çã«ã¯ãä¸è¨ã®æ°å¼ã10000é ã㤠Actor ã«å²ãæ¯ã£ã¦ã並åè¨ç®ãã¦ããã
ãã®ãããªç´æ°ã scala ã§ä¸¦åè¨ç®ããæ¹æ³ã¨ãã¦ã¯ãakka ã使ã以å¤ã«ããscala 2.9.0 ããå ãã£ã parallel collection ã使ãã¨ããæ¹æ³ãããã
object PiParallel extends App { import scala.collection.GenSeq // Ï = 4*atan(1) ã®ãã¼ã©ã¼å±é def calculatePi(rng: GenSeq[Int]): Double = rng.map{i => 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)}.sum; val seqRng = Range(0, 10000 * 10000).view // é次è¨ç®ãã Range val parRng = Range(0, 10000 * 10000).par.view // 並åè¨ç®ãã ParRange // CPU ã³ã¢æ°ã®è¡¨ç¤º println("collection.parallel.availableProcessors == "+collection.parallel.availableProcessors) timeKeep(calculatePi(seqRng), "Sequential:") // é次ç´åè¨ç® timeKeep(calculatePi(parRng), "Parallel:") // å¹³è¡åæè¨ç® def timeKeep[A <: AnyRef](calcPi: => Double, msg: String) { println(msg) val t1 = System.nanoTime val pi = calcPi val t2 = System.nanoTime println( "\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis" .format(pi, (t2 - t1) / 1000000)) } }
å®è¡çµæ @ Athlon II 250 (CPUã³ã¢æ° == 2)
collection.parallel.availableProcessors == 2 Sequential: Pi estimate: 3.141592643589326 Calculation time: 8329 millis Parallel: Pi estimate: 3.1415926435898958 Calculation time: 4619 millis
Ïã®è¨ç®çµæãéãã®ã¯ãè¨ç®é åºã®éãã«ãã丸ã誤差ã®éãã«ãããã®ã
ã¡ãªã¿ã«ããã®å®è¡æéã¯ãããªãé ããã®ã§è¦æ³¨æããã®åå ã¨ãã¦ã¯ãscala collection èªä½ãé ãããã
ä¸è¨ã®ããã«æåã§ã¤ã³ã©ã¤ã³å±éãã¦ã¿ãã¨ãå®è¡æé㯠2.4ç§ã¨ãªããç´å Range çã«æ¯ã¹ã¦å®è¡æéã7å²ãåæ¸ã§ããã
def calculatePiInline: Double = { var sum = 0.0 var i = 0; while (i < 10000 * 10000) { sum += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1) i += 1 } sum }
é«éåã®ããã«ä¸¦åè¨ç®ããã®ã«ããã¨ãã¨ã® collection èªä½ã®ããã©ã¼ãã³ã¹ãæªãã¨ããã®ã¯ããªãã¨ãç®èãªè©±ã§ããã
â»ソース一式ãgistã«ä¸ãã¾ããã
Scala ã®å é¢ã Haskell åãã話
Scala ã使ã£ã¦ Haskell 風ã®è¨è¿°ããã¦ããä¾ãæã è¦ãããããã©ãå¾¹é 徹尾 Haskell ã«ãªã£ã¦ããä¾ã¯ãã¾ãè¦æããªããã¢ããªã±ã¼ã·ã§ã³ãã¸ãã¯ã ãè¦ãã°åããªãã ããã©ãå®éã®å é¨åä½ã¯å ¨ç¶éã£ã¦ããããããããã¦ãããã©ã¼ãã³ã¹ãè´å½çã«å£ã£ã¦ãããããã¨ãæ²ããã¦ãããããªãæ°æã¡ã«ãªããScala ã¯ãæ¬å½ã¯åºæ¥ãåãªãã§ãã¨ã
ããã§ãHaskell ã£ã½ãè¨è¿°ã«èããã Scala Library ãæ´åãã¦ãããã¨æãã
循ç°ç¡éãªã¹ãã®æ´å
Haskell ã®ç¡éãªã¹ãã®ã¤ãã㧠Scala ã® Stream ã使ãã¨ããããªè½ã¨ãç©´ãå¾ ã¡åãã¦ããã
ä¾ãã°ãç¡éãªã¹ãã®ç¬¬1000000*1000çªç®ã欲ããã¨ããHaskellãªãã°ãã¡ã¢ãªä¸è¶³ã«ã¯ãªããªããã ããã©ã
Prelude> repeat 42 !! (1000000*1000) 42
Scala ã® Stream ãæ®éã«ä½¿ãã¨ãã¡ã¢ãªä¸è¶³ã«é¥ãã
scala> Stream.continually(42)(1000000*100) java.lang.OutOfMemoryError: Java heap space
ããã§ãã¡ã¢ãªãé£ããªã continually ãå®è£ ãã¦ã¿ãã
def betterContinually[A](elem: => A): Stream[A] = { lazy val result: Stream[A] = Stream.cons(elem, result) result }
scala> betterContinually(42) res1: Stream[Int] = Stream(42, ?) scala> res1(1000000*100) res2: Int = 42
ãµãããã¾ããã£ãããã¨ã¯Pimp my libraryãã¿ã¼ã³ã§ãStream object ã®ã¡ã½ããã¨ãã¦è¿½å ãã¦ãããã
implicit def equipRepeatWithStream(dummy: Stream.type) = new { def repeat[A](elem: => A): Stream[A] = { lazy val result: Stream[A] = Stream.cons(elem, result) result } } // ç¨ä¾ï¼ // Stream.repeat(42)
2011-06-24 追è¨
ä¸è¨ã® repeat ã³ã¼ãã¯ãå½åã¯ä¸è¨ã®ããã«æ¸ãã¦ããã¾ãããããlazy val ãç¨ããã»ããã¹ãã¼ããªã®ã§ãæ¬æ¥ä¿®æ£ãã¾ãããご指摘くださいました okomok ããã«æè¬ãã¾ãã
def repeat[A](elem: => A): Stream[A] = { object CircularReferenceMaker { val result: Stream[A] = Stream.cons(elem, result) } CircularReferenceMaker.result }
é 延è©ä¾¡ fold ã¨ãã¦ã® foldRight ã®æ´å
Haskell ã® foldr ã®ã¤ããã§ãScala collection ã® foldRight ã使ãã¨ããããªãè½ã¨ãç©´ãå¾ ã¡åãã¦ããã
åºæ¬çã«ãHaskell ã® foldr ã¯ç¡éãªã¹ãã«é©å¿å¯è½ã§ããããªã¹ãã«é©ç¨ãããé¢æ°ãä½å帰ãªãã°ä½ã®åé¡ãèµ·ãããªãã
ããããscala ã® foldRight ã¯ããã§ã¯ãªããã©ããªå ´åã§ãç¡éãªã¹ãã«ã¯é©ç¨ä¸å¯è½ã§ãããå¿ ãè½ã¡ã¦ãã¾ããæ£æ ¼è©ä¾¡ããã以ä¸ãfoldRight ã®æåã®åä½ã¨ãã¦ã¯æçµè¦ç´ ã¸ã®ç§»å以å¤ã«ã¯ããããªãããã ãï¼ãã¡ããããã®ç§»åã®å®è£ ã¨ãã¦ã¯ãæ¬å½ã« tail ããã©ã£ã¦ç§»åãã collection ãããã°ãå ¨è¦ç´ ãå転ãã Array ãä½ãã¨ããå®è£ ã® collection ãããï¼
ã¾ããHaskell ã® foldr ãç¡éãªã¹ãã«é©ç¨å¯è½ãªä¾ã示ããfoldr ã使ã£ã¦ map ãå®ç¾©ããã¨ããä¾ã
myMap :: (a -> b) -> ([a] -> [b]) myMap f = foldr ((:) . f) []
å½ããåã ããã©ãæéè¦ç´ ã®ãªã¹ãã§æ£å¸¸åä½ãããã
Prelude> map (2*) [1..10] [2,4,6,8,10,12,14,16,18,20]
ç¡éè¦ç´ ã®ãªã¹ãã渡ãã¦ãæ£å¸¸åä½ããã
Prelude> take 10 (map (2*) [1..]) [2,4,6,8,10,12,14,16,18,20]
ããããã®ã¾ã¾ scala ã«æ¸ãç´ãã¦ãã
// ãã¡ãªä¾ def myMap[A, B](s: Stream[A], f: A => B): Stream[B] = s.foldRight[Stream[B]](Stream.Empty)((car, cdr) => Stream.cons(f(car), cdr))
æéè¦ç´ ã® Stream ã«ã¯æå¾ éãã®åä½ããããã
scala> myMap(Stream.range(1, 10), 2* : Int => Int) print 2, 4, 6, 8, 10, 12, 14, 16, 18, empty
ç¡éè¦ç´ ã«ãªãã¨ãåä½ããªãã
scala> myMap(Stream.from(1), 2* : Int => Int) take 10 print Exception in thread "main" java.lang.StackOverflowError
ããã§ãé 延è©ä¾¡ãããæ¬ç©ã® fold ã¨ã㦠foldr ãä¸è¨ã®ããã«å®ç¾©ãã¦ãããã
def foldr[A, B](lseq: LinearSeq[A], f: (A, => B) => B, v: B): B = if (lseq.isEmpty) v else f(lseq.head, foldr(lseq.tail, f, v))
ããã¨ãæéè¦ç´ ã¯ãã¨ããç¡éè¦ç´ ã® Stream ã«å¯¾ãã¦ããæ£å¸¸åä½ããããã«ãªãã
def myMap2[A, B](s: Stream[A], f: A => B): Stream[B] =
foldr[A, Stream[B]](s, (car, cdr) => Stream.cons(f(car), cdr), Stream.Empty)
scala> myMap2(Stream.range(1, 10), 2* : Int => Int) print 2, 4, 6, 8, 10, 12, 14, 16, 18, empty scala> myMap2(Stream.from(1), 2* : Int => Int) take 10 print 2, 4, 6, 8, 10, 12, 14, 16, 18, empty