<?xml version="1.0" encoding="utf-8" ?>


<?xml-stylesheet href="http://d.hatena.ne.jp/deve68/rssxsl" type="text/xsl" media="screen"?>


<rdf:RDF
xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xml:lang="ja">
<channel rdf:about="http://d.hatena.ne.jp/deve68/rss">
<title>コードの恵み</title>
<link>http://d.hatena.ne.jp/deve68/</link>
<description>コードの恵み</description>

<dc:creator>deve68</dc:creator>
<dc:date>2012-06-15T06:38:54+09:00</dc:date>
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://d.hatena.ne.jp/deve68/20120614/1339684070"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/deve68/20120607/1339077306"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/deve68/20120603/1338696720"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/deve68/20120527/1338136850"/>
<rdf:li rdf:resource="http://d.hatena.ne.jp/deve68/20120520/1337525066"/>
</rdf:Seq>
</items>
</channel>



<item rdf:about="http://d.hatena.ne.jp/deve68/20120614/1339684070">
<title>[algorithm][.groovy] BlockSorting を Groovy で</title>
<link>http://d.hatena.ne.jp/deve68/20120614/1339684070</link>
<description> 今年も半分が終わろうとしているが1月の TODO を解決する。 404 Blog Not Found:Algorithm - Suffix Array を JavaScript で再発明してみた Suffix Array ではなく BWT の方を。 Groovy で実装してみる 参考 @nifty:@homepage:エラー BlockSorting - 西尾泰和のはてなダイア</description>

<content:encoded><![CDATA[
<div class="section">
<p>今年も半分が終わろうとしているが1月の TODO を解決する。</p>

<ul>
<li> <a href="http://blog.livedoor.jp/dankogai/archives/51765565.html" target="_blank">404 Blog Not Found:Algorithm - Suffix Array を JavaScript で再発明してみた</a></li>
</ul>
<p>Suffix Array ではなく BWT の方を。</p>
<br>

<h4> Groovy で実装してみる</h4>
<p>参考</p>

<ul>
<li> <a href="http://homepage3.nifty.com/DO/blocksorting.htm" target="_blank">@nifty:@homepage:エラー</a></li>
<li> <a href="http://d.hatena.ne.jp/nishiohirokazu/20080218/1203322931" target="_blank">BlockSorting - 西尾泰和のはてなダイアリー</a></li>
<li> <a href="http://d.hatena.ne.jp/nishiohirokazu/20080220/1203477403" target="_blank">続・BlockSorting(BWT) - 西尾泰和のはてなダイアリー</a></li>
<li> <a href="http://d.hatena.ne.jp/sumim/20080219/p1" target="_blank"> BlockSorting を Squeak Smalltalk で - Smalltalkのtは小文字です</a></li>
</ul>
<br>

<p>Ruby 版をそのまま Groovy へ</p>
<pre class="syntax-highlight">
<span class="synSpecial">def</span> encode(src) {
  <span class="synType">int</span> n = src.<span class="synIdentifier">size</span>()
  <span class="synSpecial">def</span> srcsrc = src + src
  <span class="synSpecial">def</span> vars = (<span class="synConstant">0.</span>.&#60;n).<span class="synIdentifier">collect</span>{ srcsrc[it<span class="synStatement">..</span>&#60;it+n] }
  <span class="synSpecial">def</span> code = vars.<span class="synIdentifier">sort</span>(<span class="synConstant">true</span>).<span class="synIdentifier">collect</span>{ it[-<span class="synConstant">1</span>] }
  <span class="synStatement">return</span> [code.<span class="synIdentifier">join</span>(), vars.indexOf(src)]
}

<span class="synSpecial">def</span> decode(code, <span class="synType">int</span> index) {
  <span class="synType">int</span> n = code.<span class="synIdentifier">size</span>()
  <span class="synSpecial">def</span> pairs  = [code.<span class="synIdentifier">toList</span>(), <span class="synConstant">0.</span>.&#60;n].transpose()
  <span class="synComment">// stable sort</span>
  <span class="synSpecial">def</span> sorted = pairs.<span class="synIdentifier">sort</span>{ a, b <span class="synStatement">-&#62;</span> a[<span class="synConstant">0</span>] &#60;=&#62; b[<span class="synConstant">0</span>] ?: a[<span class="synConstant">1</span>] &#60;=&#62; b[<span class="synConstant">1</span>] }
  <span class="synSpecial">def</span> result = []
  n.<span class="synIdentifier">times</span>{
    result <span class="synStatement">&#60;&#60;</span> sorted[index][<span class="synConstant">0</span>]
    index   = sorted[index][<span class="synConstant">1</span>]
  }
  <span class="synStatement">return</span> result.<span class="synIdentifier">join</span>()
}

<span class="synStatement">assert</span> encode(<span class="synConstant">&#34;abracadabra&#34;</span>) == [<span class="synConstant">&#34;rdarcaaaabb&#34;</span>, <span class="synConstant">2</span>]
<span class="synStatement">assert</span> decode(<span class="synConstant">&#34;rdarcaaaabb&#34;</span>, <span class="synConstant">2</span>) == <span class="synConstant">&#34;abracadabra&#34;</span>
</pre>

<br>

<h4> BWT とは？</h4>
<p>Burrows-Wheeler Transform の略でブロックソートとも呼ばれているみたい。</p>
<p>圧縮前に行う変換処理で BWT 自体は圧縮しないが、圧縮しやすいように並べ替えてくれる。</p>
<p>先程実装したものを使って確認してみる。</p>
<pre class="syntax-highlight">
<span class="synStatement">assert</span> encode(<span class="synConstant">&#34;abcabc&#34;</span>) == [<span class="synConstant">&#34;ccaabb&#34;</span>, <span class="synConstant">0</span>]
<span class="synStatement">assert</span> encode(<span class="synConstant">&#34;abccba&#34;</span>) == [<span class="synConstant">&#34;bacacb&#34;</span>, <span class="synConstant">1</span>] 
</pre>

<p>1つ目のようにパターンに同じようなパターンが表れると変換後連続するようになる。</p>
<p>2つ目のような場合はばらばらのまま。</p>
<p>不思議なことにこの変換後の文字列と数値から元の文字列へ戻すことができる。</p>
<br>

<h4> どうして decode できるのか？</h4>
<p>Wikipedia の説明が分かりやすいのそっちを読んだ方がいいかも</p>

<ul>
<li> <a href="http://ja.wikipedia.org/wiki/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88" target="_blank">ブロックソート - Wikipedia</a></li>
</ul>
<br>

<p>ここでは、例としてよくない気がするが "abcde" を変換する様子を見ていく。</p>
<p>巡回行列をつくる。</p>
<pre class="syntax-highlight">
<span class="synSpecial">def</span> matrix = [
  <span class="synConstant">&#34;abcde&#34;</span>,
  <span class="synConstant">&#34;eabcd&#34;</span>,  <span class="synComment">// 1行目を rotate 1</span>
  <span class="synConstant">&#34;deabc&#34;</span>,  <span class="synComment">// 2行目を rotate 1</span>
  <span class="synConstant">&#34;cdeab&#34;</span>,  <span class="synComment">// 3行目を rotate 1</span>
  <span class="synConstant">&#34;bcdea&#34;</span>   <span class="synComment">// 4行目を rotate 1</span>
]
</pre>

<br>

<p>第1列でソートする。</p>
<p>第1列でソートしたとき最終列は e,a,b,c,d である。</p>
<p>これが encode の戻り値でもう1つの戻り値の数値は元の文字列の行インデックスを返している。</p>
<pre class="syntax-highlight">
<span class="synStatement">assert</span> matrix.<span class="synIdentifier">sort</span>{ it[<span class="synConstant">0</span>] } == [
  <span class="synConstant">&#34;abcde&#34;</span>,
  <span class="synConstant">&#34;bcdea&#34;</span>,
  <span class="synConstant">&#34;cdeab&#34;</span>,
  <span class="synConstant">&#34;deabc&#34;</span>,
  <span class="synConstant">&#34;eabcd&#34;</span>
]

<span class="synStatement">assert</span> encode(<span class="synConstant">&#34;abcde&#34;</span>) == [<span class="synConstant">&#34;eabcd&#34;</span>, <span class="synConstant">0</span>]
</pre>

<br>

<p>他の列でもソートしてみる。</p>
<p>巡回しているのでソートした列の1つ前の列は e,a,b,c,d である。</p>
<pre class="syntax-highlight">
<span class="synComment">// 第2列でソートしたとき第1列は e,a,b,c,d である</span>
<span class="synStatement">assert</span> matrix.<span class="synIdentifier">sort</span>{ it[<span class="synConstant">1</span>] } == [
  <span class="synConstant">&#34;eabcd&#34;</span>,
  <span class="synConstant">&#34;abcde&#34;</span>,
  <span class="synConstant">&#34;bcdea&#34;</span>,
  <span class="synConstant">&#34;cdeab&#34;</span>,
  <span class="synConstant">&#34;deabc&#34;</span>,
]
<span class="synComment">// 第3列でソートしたとき第2列は e,a,b,c,d である</span>
<span class="synComment">// 第4列でソートしたとき第3列は e,a,b,c,d である</span>
<span class="synComment">// 第5列でソートしたとき第4列は e,a,b,c,d である</span>
</pre>

<br>

<p>この性質を使って、最終列の文字列から巡回行列をソートした状態をつくることができる。</p>
<pre class="syntax-highlight">
<span class="synComment">// 1. 第1列を e,a,b,c,d にし、第2列をソートされた文字列にする</span>
matrix = [
  <span class="synConstant">&#34;ea...&#34;</span>,
  <span class="synConstant">&#34;ab...&#34;</span>,
  <span class="synConstant">&#34;bc...&#34;</span>,
  <span class="synConstant">&#34;cd...&#34;</span>,
  <span class="synConstant">&#34;de...&#34;</span>,
]

<span class="synComment">// 2. 第1列でソートする。最終列は、e,a,b,c,d になるはず</span>
matrix = [
  <span class="synConstant">&#34;ab..e&#34;</span>,
  <span class="synConstant">&#34;bc..a&#34;</span>,
  <span class="synConstant">&#34;cd..b&#34;</span>,
  <span class="synConstant">&#34;de..c&#34;</span>,
  <span class="synConstant">&#34;ea..d&#34;</span>,
]

<span class="synComment">// 3. 全行 rotate 1 すれば 1. に戻る</span>
</pre>

<p>巡回行列をソートした状態の何番目に元の文字列があるかはわからないのでインデックスを使う。</p>
<br>

<h4> ソートを1回だけにする</h4>
<p>先程の工程をそのまま実装すると n 回のソートが必要になる</p>
<pre class="syntax-highlight">
<span class="synSpecial">def</span> process1(input) {
  <span class="synSpecial">def</span> n = input.<span class="synIdentifier">size</span>()
  <span class="synSpecial">def</span> output = [[]] * n
  n.<span class="synIdentifier">times</span> {
    output = [input, output].transpose().<span class="synIdentifier">sort</span>{ it[<span class="synConstant">0</span>] }.<span class="synIdentifier">collect</span>{ h, t <span class="synStatement">-&#62;</span> [h, *t] }
  }
  <span class="synStatement">return</span> output
}
</pre>

<br>

<p>同じ文字列をソートしているので、すべてのソートは同じ変換になる。</p>
<p>巡回しているのでそれ以降が既にソートされていることも重要である。</p>
<p>このためソートは常に安定ソートになる。</p>
<p>ソートで行う行の入れ替えを transform に覚えておけばソートは1回で済む。</p>
<pre class="syntax-highlight">
<span class="synSpecial">def</span> process2(input) {
  <span class="synSpecial">def</span> n = input.<span class="synIdentifier">size</span>()
  <span class="synSpecial">def</span> output = [[]] * n
  <span class="synSpecial">def</span> transform = [input, <span class="synConstant">0.</span>.&#60;n].transpose().<span class="synIdentifier">sort</span>{
    a, b <span class="synStatement">-&#62;</span> a[<span class="synConstant">0</span>] &#60;=&#62; b[<span class="synConstant">0</span>] ?: a[<span class="synConstant">1</span>] &#60;=&#62; b[<span class="synConstant">1</span>]
  }.transpose()[<span class="synConstant">1</span>]
  n.<span class="synIdentifier">times</span> {
    output = [input, output].transpose()
    output = (<span class="synConstant">0.</span>.&#60;n).<span class="synIdentifier">collect</span>{ output[transform[it]] }.<span class="synIdentifier">collect</span>{ h, t <span class="synStatement">-&#62;</span> [h, *t] }
  }
  <span class="synStatement">return</span> output
}
</pre>

<br>

<p>最終的な行番号が分かっていれば、その行だけ変換するようにできる。</p>
<pre class="syntax-highlight">
<span class="synComment">// trace は対象行だけの処理を行う</span>
<span class="synSpecial">def</span> process3(input) {
  <span class="synSpecial">def</span> n = input.<span class="synIdentifier">size</span>()
  <span class="synSpecial">def</span> transform = [input, <span class="synConstant">0.</span>.&#60;n].transpose().<span class="synIdentifier">sort</span>{
    a, b <span class="synStatement">-&#62;</span> a[<span class="synConstant">0</span>] &#60;=&#62; b[<span class="synConstant">0</span>] ?: a[<span class="synConstant">1</span>] &#60;=&#62; b[<span class="synConstant">1</span>]
  }.transpose()[<span class="synConstant">1</span>]
  <span class="synSpecial">def</span> trace = { i <span class="synStatement">-&#62;</span>
    <span class="synSpecial">def</span> result = []
    n.<span class="synIdentifier">times</span>{
      i = transform[i]
      result <span class="synStatement">&#60;&#60;</span> input[i]
    }
    <span class="synStatement">return</span> result
  }
  <span class="synStatement">return</span> (<span class="synConstant">0.</span>.&#60;n).<span class="synIdentifier">collect</span>{ trace(it) }
}

<span class="synStatement">assert</span> process1(<span class="synConstant">&#34;rdarcaaaabb&#34;</span> <span class="synSpecial">as</span> <span class="synType">List</span>) == process2(<span class="synConstant">&#34;rdarcaaaabb&#34;</span> <span class="synSpecial">as</span> <span class="synType">List</span>)
<span class="synStatement">assert</span> process1(<span class="synConstant">&#34;rdarcaaaabb&#34;</span> <span class="synSpecial">as</span> <span class="synType">List</span>) == process3(<span class="synConstant">&#34;rdarcaaaabb&#34;</span> <span class="synSpecial">as</span> <span class="synType">List</span>)
</pre>

<p>decode 時には行番号が分かるのでその行だけ追いかければよい。</p>
<p>これで最初に実装した処理の意味が分かった。</p>
<br>

<h4> 行番号の代わりに終端文字を使う実装</h4>
<p>文字列の最後に終端を示す文字を加えておけば、復元した行列から最後が終端文字の文字列が元の文字列であると分かる。</p>
<p>ただし、終端を示す文字は元の文字列に含まれていないこと。</p>
<br>

<p>英語版の Wikipedia に載っているものを Groovy で実装してみる。</p>
<pre class="syntax-highlight">
SEP = <span class="synConstant">'</span><span class="synError">\0</span><span class="synConstant">'</span>

<span class="synSpecial">def</span> bwt(s) {
  <span class="synStatement">assert</span> !s.contains(SEP)
  s += SEP
  <span class="synSpecial">def</span> table = (<span class="synConstant">0.</span>.&#60;s.<span class="synIdentifier">size</span>()).<span class="synIdentifier">collect</span>{ s[it<span class="synStatement">..</span>-<span class="synConstant">1</span>] + s[<span class="synConstant">0.</span>.&#60;it] }.<span class="synIdentifier">sort</span>(<span class="synConstant">true</span>)
  <span class="synStatement">return</span> table.<span class="synIdentifier">collect</span>{ it[-<span class="synConstant">1</span>] }.<span class="synIdentifier">join</span>()
}

<span class="synSpecial">def</span> ibwt(r) {
  <span class="synSpecial">def</span> table = [<span class="synConstant">&#34;&#34;</span>] * r.<span class="synIdentifier">size</span>()
  r.<span class="synIdentifier">size</span>().<span class="synIdentifier">times</span> {
    table = (<span class="synConstant">0.</span>.&#60;r.<span class="synIdentifier">size</span>()).<span class="synIdentifier">collect</span>{ r[it] + table[it] }.<span class="synIdentifier">sort</span>()
  }
  <span class="synStatement">return</span> table.<span class="synIdentifier">find</span>{ it[-<span class="synConstant">1</span>] == SEP }.replaceFirst(~/.$/, <span class="synConstant">&#34;&#34;</span>)
}

<span class="synStatement">assert</span> <span class="synConstant">&#34;cacao&#34;</span> == ibwt(bwt(<span class="synConstant">&#34;cacao&#34;</span>))
</pre>

<p>参考</p>

<ul>
<li> <a href="http://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform" target="_blank">Burrows?Wheeler transform - Wikipedia, the free encyclopedia</a></li>
</ul>
</div>
]]></content:encoded>
<dc:creator>deve68</dc:creator>
<dc:date>2012-06-14T23:27:50+09:00</dc:date>
<dc:subject>algorithm</dc:subject>
<dc:subject>.groovy</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/deve68/20120607/1339077306">
<title>[.scm][.clj][.scala][.groovy] Reverse Polish notation calculator</title>
<link>http://d.hatena.ne.jp/deve68/20120607/1339077306</link>
<description> 『すごいHaskellたのしく学ぼう!』 の 10章の逆ポーランド記法電卓を Groovy, Scala, Clojure, Scheme で書いてみる。 Reverse Polish notation calculator Groovy def solveRPN(expr) { expr.tokenize().inject([]){ acc, v -&#62; &#34;*&#34; == v ? [acc[1] * acc[0], *</description>

<content:encoded><![CDATA[
<div class="section">
<p>『すごいHaskellたのしく学ぼう!』 の 10章の逆ポーランド記法電卓を Groovy, Scala, Clojure, Scheme で書いてみる。</p>

<ul>
<li> <a href="http://learnyouahaskell.com/functionally-solving-problems#reverse-polish-notation-calculator" target="_blank">Reverse Polish notation calculator</a></li>
</ul>
<br>

<h4> Groovy</h4>
<pre class="syntax-highlight">
<span class="synSpecial">def</span> solveRPN(expr) {
  expr.<span class="synIdentifier">tokenize</span>().<span class="synIdentifier">inject</span>([]){ acc, v <span class="synStatement">-&#62;</span>
    <span class="synConstant">&#34;*&#34;</span> == v ? [acc[<span class="synConstant">1</span>] * acc[<span class="synConstant">0</span>], *acc.drop(<span class="synConstant">2</span>)] :
    <span class="synConstant">&#34;+&#34;</span> == v ? [acc[<span class="synConstant">1</span>] + acc[<span class="synConstant">0</span>], *acc.drop(<span class="synConstant">2</span>)] :
    <span class="synConstant">&#34;-&#34;</span> == v ? [acc[<span class="synConstant">1</span>] - acc[<span class="synConstant">0</span>], *acc.drop(<span class="synConstant">2</span>)] :
               [v <span class="synSpecial">as</span> <span class="synType">double</span>,     *acc]
  }[<span class="synConstant">0</span>]
}

<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;10 4 3 + 2 * -&#34;</span>) == -<span class="synConstant">4.0</span>
<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;2 3.5 +&#34;</span>) == <span class="synConstant">5.5</span>
<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;90 34 12 33 55 66 + * - +&#34;</span>) == -<span class="synConstant">3947.0</span>
<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;90 34 12 33 55 66 + * - + -&#34;</span>) == <span class="synConstant">4037.0</span>
<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;90 3.8 -&#34;</span>) == <span class="synConstant">86.2</span>
<span class="synStatement">assert</span> solveRPN(<span class="synConstant">&#34;&#34;</span>) == <span class="synConstant">null</span>
</pre>

<p>0, 1 の順なら pop でも対応できそうだが、1, 0 の順に参照しなければならないので drop と組み合わせた。</p>
<p>意味はないが空文字が渡されたら null を返すようにしてみた。</p>
<p>関連するメソッドの動作。</p>
<pre class="syntax-highlight">
<span class="synStatement">groovy</span>:<span class="synConstant">000</span>&#62; <span class="synConstant">&#34;&#34;</span>.<span class="synIdentifier">tokenize</span>()
===&#62; []
<span class="synStatement">groovy</span>:<span class="synConstant">000</span>&#62; <span class="synConstant">&#34;&#34;</span>.split()
===&#62; [Ljava.lang.<span class="synType">String</span>;@83f700d
<span class="synStatement">groovy</span>:<span class="synConstant">000</span>&#62; [].head()
ERROR java.util.<span class="synStatement">NoSuchElementException</span>:
Cannot access first() element from an empty <span class="synType">List</span>
        at groovysh_evaluate.run (groovysh_evaluate:<span class="synConstant">2</span>)
        <span class="synStatement">..</span>.
<span class="synStatement">groovy</span>:<span class="synConstant">000</span>&#62; [][<span class="synConstant">0</span>]
===&#62; <span class="synConstant">null</span>
</pre>

<br>

<h4> Scala</h4>
<pre class="syntax-highlight">
val solveRPN: String =&#62; Double =
  _.split(' ').foldLeft(List.empty[Double]){
    case (x::y::ys, &#34;*&#34;) =&#62; (y * x)::ys
    case (x::y::ys, &#34;+&#34;) =&#62; (y + x)::ys
    case (x::y::ys, &#34;-&#34;) =&#62; (y - x)::ys
    case (xs, number)    =&#62; number.toDouble::xs
  }.head

assert( solveRPN(&#34;10 4 3 + 2 * -&#34;) == -4.0 )
assert( solveRPN(&#34;2 3.5 +&#34;) == 5.5 )
assert( solveRPN(&#34;90 34 12 33 55 66 + * - +&#34;) == -3947.0 )
assert( solveRPN(&#34;90 34 12 33 55 66 + * - + -&#34;) == 4037.0 )
assert( solveRPN(&#34;90 3.8 -&#34;) == 86.2 )
</pre>

<p>Scala はパターンマッチがあるので Haskell と変わらない。</p>
<p>14章に Maybe を使った安全版があるので Scala ならそっちを実装するべきだったかもしれない。</p>
<p>空文字にも対応していない。</p>
<p>split が曲者だった。</p>
<pre class="syntax-highlight">
scala&#62; <span class="synConstant">&#34;&#34;</span>.split(' ')
res0: <span class="synConstant">Array</span>[<span class="synConstant">String</span>] = <span class="synConstant">Array</span>(<span class="synConstant">&#34;&#34;</span>)

scala&#62; <span class="synConstant">&#34;&#34;</span>.split(<span class="synConstant">&#34;\\s+&#34;</span>)
res1: <span class="synConstant">Array</span>[java.lang.<span class="synConstant">String</span>] = <span class="synConstant">Array</span>(<span class="synConstant">&#34;&#34;</span>)

scala&#62; <span class="synConstant">&#34;&#34;&#34;\s+&#34;&#34;&#34;</span>.r.split(<span class="synConstant">&#34;&#34;</span>)
res2: <span class="synConstant">Array</span>[<span class="synConstant">String</span>] = <span class="synConstant">Array</span>(<span class="synConstant">&#34;&#34;</span>)

scala&#62; <span class="synConstant">&#34;&#34;&#34;\S+&#34;&#34;&#34;</span>.r.findAllIn(<span class="synConstant">&#34;&#34;</span>)
res3: scala.util.matching.Regex.MatchIterator = empty iterator
</pre>

<br>

<h4> Clojure</h4>
<pre class="syntax-highlight">
(defn solve-rpn [expr]
  (defn f [[x y &#38; ys :as s] w]
    (cond
      (= &#34;*&#34; w) (cons (* y x) ys)
      (= &#34;+&#34; w) (cons (+ y x) ys)
      (= &#34;-&#34; w) (cons (- y x) ys)
      :else     (cons (Double/parseDouble w) s)))
  (-&#62;&#62; expr (re-seq #&#34;\S+&#34;) (reduce f []) first))

(assert (= (solve-rpn &#34;10 4 3 + 2 * -&#34;) -4.0) )
(assert (= (solve-rpn &#34;2 3.5 +&#34;) 5.5) )
(assert (= (solve-rpn &#34;90 34 12 33 55 66 + * - +&#34;) -3947.0) )
(assert (= (solve-rpn &#34;90 34 12 33 55 66 + * - + -&#34;) 4037.0) )
(assert (= (solve-rpn &#34;90 3.8 -&#34;) 86.2) )
(assert (= (solve-rpn &#34;&#34;) nil) )
</pre>

<p>パターンマッチはないが分配束縛があるのでそれを使った。</p>
<p>nil 耐性があるので引数の時点で分配している。</p>
<pre class="syntax-highlight">
user=&#62; (clojure.string/split &#34;&#34; #&#34;\s+&#34;)
[&#34;&#34;]
user=&#62; (re-seq #&#34;\S+&#34; &#34;&#34;)
nil
user=&#62; (first nil)
nil
user=&#62; (first [])
nil
</pre>

<br>

<h4> Scheme</h4>
<pre class="syntax-highlight">
<span class="synSpecial">(</span><span class="synStatement">define</span> <span class="synSpecial">(</span>solve-rpn expr<span class="synSpecial">)</span>
  <span class="synSpecial">(</span><span class="synStatement">define</span> <span class="synSpecial">(</span>f v acc<span class="synSpecial">)</span>
    <span class="synSpecial">(</span><span class="synStatement">cond</span>
      <span class="synSpecial">((</span><span class="synIdentifier">equal?</span> <span class="synConstant">&#34;*&#34;</span> v<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span><span class="synIdentifier">*</span> <span class="synSpecial">(</span><span class="synIdentifier">cadr</span> acc<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">car</span> acc<span class="synSpecial">))</span> <span class="synSpecial">(</span><span class="synIdentifier">cddr</span> acc<span class="synSpecial">)))</span>
      <span class="synSpecial">((</span><span class="synIdentifier">equal?</span> <span class="synConstant">&#34;+&#34;</span> v<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span><span class="synIdentifier">+</span> <span class="synSpecial">(</span><span class="synIdentifier">cadr</span> acc<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">car</span> acc<span class="synSpecial">))</span> <span class="synSpecial">(</span><span class="synIdentifier">cddr</span> acc<span class="synSpecial">)))</span>
      <span class="synSpecial">((</span><span class="synIdentifier">equal?</span> <span class="synConstant">&#34;-&#34;</span> v<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span><span class="synIdentifier">-</span> <span class="synSpecial">(</span><span class="synIdentifier">cadr</span> acc<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">car</span> acc<span class="synSpecial">))</span> <span class="synSpecial">(</span><span class="synIdentifier">cddr</span> acc<span class="synSpecial">)))</span>
      <span class="synSpecial">(</span><span class="synStatement">else</span>           <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span><span class="synIdentifier">string-&#62;number</span> v<span class="synSpecial">)</span> acc<span class="synSpecial">))))</span>
  <span class="synSpecial">(</span><span class="synIdentifier">car</span> <span class="synSpecial">(</span>fold f <span class="synSpecial">'()</span> <span class="synSpecial">(</span>string-split expr <span class="synConstant">#/</span>\s+/<span class="synSpecial">))))</span>

<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;10 4 3 + 2 * -&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; -4</span>
<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;2 3.5 +&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; 5.5</span>
<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 34 12 33 55 66 + * - +&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; -3947</span>
<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 34 12 33 55 66 + * - + -&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; 4037</span>
<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 3.8 -&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; 86.2</span>
<span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;&#34;</span><span class="synSpecial">)</span> <span class="synComment">;=&#62; #f</span>
</pre>

<p>まだ、どんな関数があるのかよく知らない。</p>
<p>今風な API Doc が欲しい。</p>
<pre class="syntax-highlight">
gosh&#62; <span class="synSpecial">(</span>string-split <span class="synConstant">&#34;&#34;</span> <span class="synConstant">#/</span>\s+/<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synConstant">&#34;&#34;</span><span class="synSpecial">)</span>
gosh&#62; <span class="synSpecial">(</span><span class="synIdentifier">string-&#62;number</span> <span class="synConstant">&#34;&#34;</span><span class="synSpecial">)</span>
<span class="synConstant">#f</span>
gosh&#62; <span class="synSpecial">(</span><span class="synIdentifier">car</span> <span class="synSpecial">'())</span>
<span class="synConstant">***</span> ERROR: pair <span class="synError">required,</span> but got <span class="synSpecial">()</span>
gosh&#62; <span class="synSpecial">(</span>use srfi-1<span class="synSpecial">)</span>
<span class="synError">#&#60;undef&#62;</span>
gosh&#62; <span class="synSpecial">(</span>reduce <span class="synIdentifier">+</span> <span class="synConstant">10</span> <span class="synSpecial">'(</span><span class="synConstant">1</span> <span class="synConstant">2</span> <span class="synConstant">3</span><span class="synSpecial">))</span>
<span class="synConstant">6</span>
gosh&#62; <span class="synSpecial">(</span>reduce <span class="synIdentifier">+</span> <span class="synConstant">10</span> <span class="synSpecial">'())</span>
<span class="synConstant">10</span>
</pre>

<br>

<h4> 終わりに</h4>
<p>簡単そうに思えたが書いてみるといろいろ気づくことがあった。</p>
<p>言語によって微妙に違うので注意したい。</p>
<br>

<h4> 2012-06-11 追記</h4>
<p>Clojure 版の f はローカル関数にしたつもりだったがグローバルから参照できてしまった。</p>
<p>defn ではなく letfn を使って f を定義するように修正する。</p>
<pre class="syntax-highlight">
<span class="synSpecial">(</span><span class="synPreProc">defn</span> solve-rpn <span class="synSpecial">[</span>expr<span class="synSpecial">]</span>
  <span class="synSpecial">(</span><span class="synPreProc">letfn</span> <span class="synSpecial">[(</span>f <span class="synSpecial">[[</span>x y <span class="synSpecial">&#38;</span> ys <span class="synStatement">:as</span> s<span class="synSpecial">]</span> w<span class="synSpecial">]</span>
            <span class="synSpecial">(</span><span class="synStatement">cond</span>
              <span class="synSpecial">(</span>= <span class="synConstant">&#34;*&#34;</span> w<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span>* y x<span class="synSpecial">)</span> ys<span class="synSpecial">)</span>
              <span class="synSpecial">(</span>= <span class="synConstant">&#34;+&#34;</span> w<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span>+ y x<span class="synSpecial">)</span> ys<span class="synSpecial">)</span>
              <span class="synSpecial">(</span>= <span class="synConstant">&#34;-&#34;</span> w<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span>- y x<span class="synSpecial">)</span> ys<span class="synSpecial">)</span>
              <span class="synStatement">:else</span>     <span class="synSpecial">(</span><span class="synIdentifier">cons</span> <span class="synSpecial">(</span>Double/parseDouble w<span class="synSpecial">)</span> s<span class="synSpecial">)))]</span>
    <span class="synSpecial">(</span>-&#62;&#62; expr <span class="synSpecial">(</span>re-<span class="synIdentifier">seq</span> <span class="synConstant">#&#34;\S+&#34;</span><span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synStatement">reduce</span> f <span class="synSpecial">[])</span> <span class="synIdentifier">first</span><span class="synSpecial">)))</span>

<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;10 4 3 + 2 * -&#34;</span><span class="synSpecial">)</span> -<span class="synConstant">4.0</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;2 3.5 +&#34;</span><span class="synSpecial">)</span> <span class="synConstant">5.5</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 34 12 33 55 66 + * - +&#34;</span><span class="synSpecial">)</span> -<span class="synConstant">3947.0</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 34 12 33 55 66 + * - + -&#34;</span><span class="synSpecial">)</span> <span class="synConstant">4037.0</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;90 3.8 -&#34;</span><span class="synSpecial">)</span> <span class="synConstant">86.2</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synPreProc">assert</span> <span class="synSpecial">(</span>= <span class="synSpecial">(</span>solve-rpn <span class="synConstant">&#34;&#34;</span><span class="synSpecial">)</span> <span class="synConstant">nil</span><span class="synSpecial">)</span> <span class="synSpecial">)</span>
</pre>

</div>
]]></content:encoded>
<dc:creator>deve68</dc:creator>
<dc:date>2012-06-07T22:55:06+09:00</dc:date>
<dc:subject>.scm</dc:subject>
<dc:subject>.clj</dc:subject>
<dc:subject>.scala</dc:subject>
<dc:subject>.groovy</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/deve68/20120603/1338696720">
<title>[method] 学習</title>
<link>http://d.hatena.ne.jp/deve68/20120603/1338696720</link>
<description> 頭の中の灰色の細胞が CPU や HDD だったとする。 知っていることが増えるのは HDD に書き込んだからということにしよう。 しかし、プログラミング能力が向上することを説明するのは難しい。 なぜなら CPU は変わっていないのだから。 考えられるのは HDD の中から似ている</description>

<content:encoded><![CDATA[
<div class="section">
<p>頭の中の灰色の細胞が CPU や HDD だったとする。</p>
<p>知っていることが増えるのは HDD に書き込んだからということにしよう。</p>
<p>しかし、プログラミング能力が向上することを説明するのは難しい。</p>
<p>なぜなら CPU は変わっていないのだから。</p>
<br>

<p>考えられるのは HDD の中から似ているコードを検索することだ。</p>
<p>HDD に貯め込んだコードの量が増えるほどプログラミングできる範囲は広がる。</p>
<p>しかし、コードの量が増えるほどプログラミング速度が遅くなってしまいそうだ。</p>
<p>これは観測結果と一致しない。</p>
<p>むしろ広範囲の知識を持っている人の方がプログラミングも速い気がする。</p>
<p>CPU も HDD も優秀な人がいることはわかるが、自分自身でも知識が広がった方が速くなってるのでハード的な問題ではなさそうだ。</p>
<br>

<h4> 認知心理学の知恵を借りる</h4>
<p>岡本浩一氏の 『上達の法則』 を読んだところ、知識は 「宣言型知識」 と 「手続き型知識」 の2種類に分けられるらしい。</p>

<ul>
<li> 宣言型知識は、円周率は 3.14 のような一般的に 「知識」 と呼ばれるもの</li>
<li> 手続き型知識は、言葉では言い表せない 「手続き」 を含んだもの</li>
</ul>
<p>技能の習得にはこの両方が必要で、これらを効率よく記憶、検索、利用できるようになることが上達を意味する。</p>
<br>

<p>では初心者と上級者の違いは何なのか？</p>
<p>まず脳には制約があって、脳に存在するワーキングメモリは7個ぐらいの塊で出し入れしなければならない。</p>
<p>上級者は知識を塊に変換する方法の種類が豊富で、かつ塊を小さくできたり大きくできたりするので初心者より出し入れしやすい。</p>
<p>初心者はワーキングメモリのフィルタではじかれるものがあるから同じ技能経験で得られるものも変わってくる。</p>
<br>

<p>ここまでが書籍の2章に書かれていた内容</p>
<br>

<h4> どれくらい違うのだろうか？</h4>
<p>塊の認識の違いは、カスパロフ氏の 『決定力を鍛える』 に書かれていた。</p>
<p>人間が計算力でコンピュータに対抗できるのは、意味のある単位にまとめて組合せの数を減らせるからだそうだ。</p>
<p>うまく塊を扱えれば線形的な違いではなくオーダーの違いを得られる。</p>
<br>

<p>しかしチェスは何手読めるかで勝敗が決まるわけではないそうだ。</p>
<p>同じ局面を見て黒が有利という人と白が有利という人に分かれる。</p>
<p>計算力と判断力は別の軸らしい。</p><p>「計算力の優劣で判断する人を決める」ことは「定規を持っているから長さで決める」ことと似ている。<span class="footnote"><a href="/deve68/#f1" name="fn1" title="当然計算力で解決する問題は違う">*1</a></span></p>
<br>

<p>プログラミング自体は大抵答えのある問題を扱っている(実装したい機能や計算したい値がある)はず。</p>
<p>そうするとやはり塊を扱う能力が重要となってくる。</p>
<p>ウサイン・ボルト選手は平均より2倍速いわけではないが1番速い。プログラミング速さは実際どれぐらいなのだろうか？</p>
<p>これは難しい問題らしい。</p>

<ul>
<li> <a href="http://d.hatena.ne.jp/yaneurao/20100927" target="_blank">われわれは100倍、速く書けない - やねうらお−俺のブログがこんなによっちゃんイカなわけがない</a></li>
</ul>
<p>しかし、アルゴリズムのオーダーと同じように考えるとやはりうまく塊を扱えることがポイントになりそうだ。</p>
<p>塊を扱う単位を変えたところでオーダーが変えられるわけではないが、扱う単位を変えられなければばオーダーは変わらない。</p>
<br>

<h4> 知識の塊の扱い方</h4>
<p>これを知りたい。</p>
<p>上級者から教わることがある。</p>
<p>「そこはこの2つセットで考える」 とか 「こっちから見る方法もある」 みたいに。</p>
<p>そうでない場合は、上級者の切り口をみて自分で考えるしかない。</p>
<p>「塊を小さく切り分けているな」 ということは分かっても、どうしてその単位なのかは分からなかったりする。</p>
<p>オーダーの違いや手続き型知識の場合もあるので必ずしも聞いて分かるとは限らない。</p>
<br>

<p>世の中には斬鉄剣の使い手のように知識の塊を 「また、つまらぬ物を斬ってしまった」 と簡単に扱える人がいる。</p>
<p>そのような人は大抵のことが遅延学習法で間に合う。一方、斬鉄剣を持っていない人はどういう順序で学ぶべきか？</p>
<p>持っている人より、どうすればオーダーが変わるのか、今のオーダーで十分なものは何かということを意識して選択した方がいいのだろう。</p>
<p>見積もれるわけではないので意識するより具体的な方法を思いつかない。</p>
<br>

<p>「なぜ関数プログラミングを学ぶのか？」 という質問に対する個人的な答えは、「知らない切り口があるから」 だ。</p>
<p>もちろん関数プログラミング以外ににも新しい切り口は存在するのでそっちを優先するという選択も考えられる。</p>
<p>必ずしも使うから学ぶわけではないし、今後流行しそうだからでもない。</p>
<p>「現在知っている言語で実装できているのになぜ？」 と考える人は、現在のオーダーで今後も間に合うのか考える必要があるはずだ。</p>
<br>

<p>今は、『すごい Haskell たのしく学ぼう!』 を読んでいる。</p>
<p>本になっているのだから宣言型知識として書かれている。</p>
<p>しかし、技術として両輪となる手続き型知識を私はまだ得られていない。</p>
<p>得られていない言い訳を考えてたらこんなことになってしまった。</p>
<p>『初めての人のための LISP』 を読んだときも再帰で考えることに苦労した。</p>
<p>そのときはここを参考にしながら読んでいって何とか14章まで読んだ。</p>

<ul>
<li> <a href="http://d.hatena.ne.jp/Rion778/20100901/1283276920" target="_blank"> 初めての人のためのLISP (第1講-第5講) - もうカツ丼でいいよな</a></li>
</ul>
<p>その経験があるので、今回も最終的に理解できるだろうぐらいの感覚で読んでいる。</p>
<p>とりあえず、手続き型知識を得られるように訓練しなければならない。</p>
<br>

<h4> 追記</h4>
<p>『数学ガール ガロア理論』を読み始めた。</p>
<blockquote>
<p>「なるほど！確かに対称式が係数で表せています」テトラちゃんは式を確認して言った。「対称式はいつでもこのように係数で表せるんですね……ところで、こういう変形って、なるほど！って思うんですが、自分では思いつきそうにありません。どうしたらできるようになるんでしょう」</p>
<p>「練習」とミルカさんが即答する。</p>
<p>「そうですか……」とテトラちゃんが言った。</p>
</blockquote>
<p>テトラさんはどういう風に練習をすればいいかを聞いているような気がするのだが…</p>
<p>しかし、テトラさんといえば総当りなのだから表を作っておけばよいと思った。</p>
<p>ミルカさんが使ったことがあるテクニックを一覧表にしておいて毎回検索。</p>
<br>

<p>知識の塊も多次元テーブルでモデリングしておけばよいだけなのか？</p>
<p>未知の列が追加される場合は仕方がないが、追加されたときに他の軸との交点がどうなるのかを埋める。</p>
<p>そういえば『なぜ関数プログラミングは重要か』でも“新しいデータ型を定義したときにその型を処理する高階関数を書くべきである”と書かれていた。</p>
<br>

<h4> 2012-06-04 追記</h4>
<p>発想法とか</p>

<ul>
<li> <a href="http://bizmakoto.jp/bizid/articles/0804/22/news064.html" target="_blank">アイデア創発の素振り：TRIZ――10分以内に「それ、どうやって実現するか」を思いつく方法 (1/3) - ITmedia Biz.ID</a></li>
<li> <a href="http://d.hatena.ne.jp/antipop/20090523/1243098153" target="_blank">体系的な知識・技術を身につけるための学習法について - delirious thoughts</a></li>
</ul>
<p>コーディングに置き換えたらどうなるのだろう？</p>
<br>

<p>プログラム版 20Q が欲しい。</p>
<p>データはたくさんですか？データにランダムアクセスできますか？とか答えているとプログラムが返ってくる。</p>
<p>そう考えるとタグが重要で、勉強の質と量の質はそのためのタグが足りているかどうかだと思った。</p>
<p>子曰く 「勉強したら検索のこと考えてタグ付けなきゃだめだよ。タグを付けていても量がなきゃだめだよ。」</p>
<p>でも違和感ない。</p>
<br>

<p>手続き型知識を得られないのは、宣言型知識に十分なタグを付けてないので、他の知識との連動できない状態なんだと思う。</p>
<p>ファンクターを、どうタグ付けしたらいいのかよく分からないから、どう使うのか分からない。</p>
<p>タグ付けできれば今まで同じタグを使っている箇所をファンクターで置き換えることができる。</p>
<p>ただ、分からない理由が分かっても分かったことにはならない。</p>
</div>
<div class="footnote">
<p class="footnote"><a href="/deve68/#fn1" name="f1">*1</a>：当然計算力で解決する問題は違う</p>
</div>
]]></content:encoded>
<dc:creator>deve68</dc:creator>
<dc:date>2012-06-03T13:12:00+09:00</dc:date>
<dc:subject>method</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/deve68/20120527/1338136850">
<title>[.clj][.groovy] Learn you a Clojure for Great Groovy!</title>
<link>http://d.hatena.ne.jp/deve68/20120527/1338136850</link>
<description> 最近話題のタイトルは、たのしく読んでいる途中（9章に入った)。 その話ではなく、このエントリは Clojure で Ninety-Nine Prolog Problems をやっているときに思いついたもの。 1. Prolog Lists - Prolog Site Ninety-Nine Prolog Problems も Lists のところだけ、現在 Gr</description>

<content:encoded><![CDATA[
<div class="section">
<p>最近話題のタイトルは、たのしく読んでいる途中（9章に入った)。</p>
<p>その話ではなく、このエントリは Clojure で Ninety-Nine Prolog Problems をやっているときに思いついたもの。</p>

<ul>
<li> <a href="https://sites.google.com/site/prologsite/prolog-problems/1" target="_blank">1. Prolog Lists - Prolog Site</a></li>
</ul>
<br>
<p>Ninety-Nine Prolog Problems も Lists のところだけ、現在 Groovy, Haskell, Scala, Prolog, Clojure で解いた。<span class="footnote"><a href="/deve68/#f1" name="fn1" title="Prolog では 28 がまだだが">*1</a></span></p>
<p>Lists の前半のクライマックスは encode-direct 辺りだが Groovy に較べて Clojure は簡潔に書けてしまう。</p>
<pre class="syntax-highlight">
;; 1.13
(defn encode-direct [s]
  (for [[n c] (map (juxt count first) (partition-by identity s))] (if (= 1 n) c [n c]) ))
(assert (= [[4 \a] \b [2 \c] [2 \a] \d [4 \e]] (encode-direct &#34;aaaabccaadeeee&#34;) ))
</pre>

<br>

<p>これは Haskell の group 関数にあたるものが Clojure に存在するためだ。</p>
<pre class="syntax-highlight">
Prelude<span class="synStatement">&#62;</span> <span class="synStatement">:</span>m <span class="synStatement">+</span> Data.List
Prelude Data.List<span class="synStatement">&#62;</span> group <span class="synConstant">&#34;aaaabccaadeeee&#34;</span>
[<span class="synConstant">&#34;aaaa&#34;</span>,<span class="synConstant">&#34;b&#34;</span>,<span class="synConstant">&#34;cc&#34;</span>,<span class="synConstant">&#34;aa&#34;</span>,<span class="synConstant">&#34;d&#34;</span>,<span class="synConstant">&#34;eeee&#34;</span>]
</pre>

<br>

<p>つまり 1.09 の pack が Clojure では</p>

<ul>
<li> 参考：<a href="http://clojuredocs.org/clojure_core/clojure.core/partition-by" target="_blank">ClojureDocs - clojure.core/partition-by</a></li>
</ul>
<pre class="syntax-highlight">
;; 1.09
(defn pack [s] (partition-by identity s))
(assert (= [[\a \a \a \a] [\b] [\c \c] [\a \a] [\d] [\e \e \e \e]] (pack &#34;aaaabccaadeeee&#34;) ))
</pre>

<br>
<p>で、Groovy では <span class="footnote"><a href="/deve68/#f2" name="fn2" title="Scala も探したけど見当たらない。Scala では foldRight + パターンマッチで切り抜けた">*2</a></span></p>
<pre class="syntax-highlight">
<span class="synComment">// 1.09</span>
<span class="synSpecial">def</span> pack(list) {
  <span class="synStatement">if</span> (!list) <span class="synStatement">return</span> []
  list = list.<span class="synIdentifier">reverse</span>()
  list.tail().<span class="synIdentifier">inject</span>([[list.head()]]){ acc, v <span class="synStatement">-&#62;</span> acc.head()[<span class="synConstant">0</span>] == v ? [[v,*acc.head()],*acc.tail()] : [[v],*acc] }
}

<span class="synStatement">assert</span> [<span class="synConstant">&#34;aaaa&#34;</span>,<span class="synConstant">&#34;b&#34;</span>,<span class="synConstant">&#34;cc&#34;</span>,<span class="synConstant">&#34;aa&#34;</span>,<span class="synConstant">&#34;d&#34;</span>,<span class="synConstant">&#34;eeee&#34;</span>] == pack(<span class="synConstant">&#34;aaaabccaadeeee&#34;</span>.<span class="synIdentifier">toList</span>())*.<span class="synIdentifier">join</span>()
</pre>

<br>

<p>Groovy にも Collection#split という同じインターフェイスのメソッドが存在するが振る舞いが違う。</p>
<p>Groovy の split は、引数のクロージャで true と false に分類しているのに対し</p>
<p>Clojure の partition-by は、引数のクロージャで変換した結果が1つ前のグループと同じかどうかで分類している。</p>
<br>
<p>これは便利だ。いつもなら partition-by を実装するところだが Clojure はオープンなので貸してもらうことにする。<span class="footnote"><a href="/deve68/#f3" name="fn3" title="Groovy もオープンだ">*3</a></span></p>
<pre class="syntax-highlight">
@Grab(group=<span class="synConstant">'org.clojure'</span>, module=<span class="synConstant">'clojure'</span>, version=<span class="synConstant">'1.4.0'</span>)
@Grab(group=<span class="synConstant">'org.apache.commons'</span>, module=<span class="synConstant">'commons-lang3'</span>, version=<span class="synConstant">'3.1'</span>)
<span class="synPreProc">import</span> clojure.lang.Compiler
<span class="synPreProc">import</span> clojure.lang.Symbol
<span class="synPreProc">import</span> clojure.lang.RT
<span class="synPreProc">import static</span> org.apache.commons.lang3.StringUtils.removeEnd
<span class="synPreProc">import static</span> org.apache.commons.lang3.StringUtils.splitByCharacterTypeCamelCase


<span class="synSpecial">def</span> methodMissing(<span class="synType">String</span> name, args) {
  <span class="synSpecial">def</span> names = splitByCharacterTypeCamelCase(name)*.toLowerCase()
  <span class="synStatement">if</span> (names[<span class="synConstant">0</span>] == <span class="synConstant">&#34;is&#34;</span>) {
    names = names.tail()
    names[-<span class="synConstant">1</span>] = names[-<span class="synConstant">1</span>] + <span class="synConstant">&#34;?&#34;</span>
  }
  <span class="synStatement">return</span> Compiler.eval(Symbol.create(names.<span class="synIdentifier">join</span>(<span class="synConstant">&#34;-&#34;</span>))).invoke(*args)
}

<span class="synSpecial">def</span> propertyMissing(<span class="synType">String</span> name) {
  <span class="synComment">// Why?</span>
  <span class="synComment">// Caused by: java.lang.RuntimeException: Unable to resolve symbol: out in this context</span>
  <span class="synStatement">if</span> (name == <span class="synConstant">&#34;out&#34;</span>) <span class="synStatement">return</span> System.out
  <span class="synStatement">return</span> Compiler.eval(Symbol.create(name))
}

<span class="synSpecial">def</span> pack(s) {
  partitionBy(identity, s)
}

<span class="synSpecial">def</span> encode1(s) {
  map(juxt(<span class="synIdentifier">count</span>, first), pack(s))
}

<span class="synSpecial">def</span> encode2(list) {
  pack(list).<span class="synIdentifier">collect</span>{ [it.<span class="synIdentifier">size</span>(),it.head()] }
}

<span class="synStatement">assert</span> [<span class="synConstant">&#34;aaaa&#34;</span>, <span class="synConstant">&#34;b&#34;</span>, <span class="synConstant">&#34;cc&#34;</span>, <span class="synConstant">&#34;aa&#34;</span>, <span class="synConstant">&#34;d&#34;</span>, <span class="synConstant">&#34;eeee&#34;</span>] == pack(<span class="synConstant">&#34;aaaabccaadeeee&#34;</span>)*.<span class="synIdentifier">join</span>()
<span class="synStatement">assert</span> [[<span class="synConstant">4</span>,<span class="synConstant">'a'</span>], [<span class="synConstant">1</span>,<span class="synConstant">'b'</span>], [<span class="synConstant">2</span>,<span class="synConstant">'c'</span>], [<span class="synConstant">2</span>,<span class="synConstant">'a'</span>], [<span class="synConstant">1</span>,<span class="synConstant">'d'</span>], [<span class="synConstant">4</span>,<span class="synConstant">'e'</span>]] == encode1(<span class="synConstant">&#34;aaaabccaadeeee&#34;</span>)
<span class="synStatement">assert</span> [[<span class="synConstant">4</span>,<span class="synConstant">'a'</span>], [<span class="synConstant">1</span>,<span class="synConstant">'b'</span>], [<span class="synConstant">2</span>,<span class="synConstant">'c'</span>], [<span class="synConstant">2</span>,<span class="synConstant">'a'</span>], [<span class="synConstant">1</span>,<span class="synConstant">'d'</span>], [<span class="synConstant">4</span>,<span class="synConstant">'e'</span>]] == encode2(<span class="synConstant">&#34;aaaabccaadeeee&#34;</span>)
<span class="synStatement">assert</span> isZero(<span class="synConstant">0</span>)
<span class="synComment">// Why?</span>
<span class="synComment">// groovy.lang.MissingPropertyException: No such property: lang for class: clojure</span>
<span class="synComment">// assert 'a' == clojure.lang.RT.first(&#34;abc&#34;)</span>
<span class="synStatement">assert</span> <span class="synConstant">'a'</span> == RT.first(<span class="synConstant">&#34;abc&#34;</span>)
</pre>

<p>encode1 は Groovy でも encode2 のように書けるのでメリットがあるわけではないが他の関数も借りられますよということで書いてみた。</p>
<p>propertyMissing の振る舞いがよく分かっていないので Why? が2箇所発生している。</p>
<p>clojure.lang.RT のメソッドなら直接呼び出すことも可能なようだ。</p>
<p>Symbol を毎回生成して eval しているがこれはキャッシュに保持してもいいかもしれない。</p>
<p>改善点はあると思うが Clojure の関数は Groovy から簡単に呼び出せたよ、ということが言いたかった。</p>
</div>
<div class="footnote">
<p class="footnote"><a href="/deve68/#fn1" name="f1">*1</a>：Prolog では 28 がまだだが</p>
<p class="footnote"><a href="/deve68/#fn2" name="f2">*2</a>：Scala も探したけど見当たらない。Scala では foldRight + パターンマッチで切り抜けた</p>
<p class="footnote"><a href="/deve68/#fn3" name="f3">*3</a>：Groovy もオープンだ</p>
</div>
]]></content:encoded>
<dc:creator>deve68</dc:creator>
<dc:date>2012-05-28T01:40:50+09:00</dc:date>
<dc:subject>.clj</dc:subject>
<dc:subject>.groovy</dc:subject>
</item>
<item rdf:about="http://d.hatena.ne.jp/deve68/20120520/1337525066">
<title>[.scala] 関数型パーサー</title>
<link>http://d.hatena.ne.jp/deve68/20120520/1337525066</link>
<description> もうすぐ Haskell の本が出版されるので復習する。 『プログラミング Haskell』 の第8章を今回は Scala(version 2.9.2) で書く。 Scala 的に使った方がいいらしいので Option や Either も勉強する。 Scala の API と以下を参考にしながら書いてみた。 Java で Either モナ</description>

<content:encoded><![CDATA[
<div class="section">
<p>もうすぐ Haskell の本が出版されるので復習する。</p>
<p>『プログラミング Haskell』 の第8章を今回は Scala(version 2.9.2) で書く。</p>
<p>Scala 的に使った方がいいらしいので Option や Either も勉強する。</p>
<p>Scala の API と以下を参考にしながら書いてみた。</p>

<ul>
<li> <a href="http://d.hatena.ne.jp/xuwei/20120518/1337292876" target="_blank">Java で Either モナド - scalaとか・・・</a></li>
<li> <a href="http://modegramming.blogspot.jp/2012/02/scala-tips-option-index.html" target="_blank">Modegramming Style: Scala Tips / Option - Index</a></li>
<li> <a href="http://modegramming.blogspot.jp/2012/04/scala-tips-either-index.html" target="_blank">Modegramming Style: Scala Tips / Either - Index</a></li>
</ul>
<br>

<h4> まずはパターンマッチで</h4>
<p>ほとんど変わらないはずだが、書籍よりも Code の Parsing.lhs と parser.lhs の方を参考にした。</p>

<ul>
<li> <a href="http://www.cs.nott.ac.uk/~gmh/book.html" target="_blank"> Programming in Haskell </a> </li>
</ul>
<pre class="syntax-highlight">
object Parsers {
  type P[A] = Seq[Char] =&#62; Option[(A,Seq[Char])]

  implicit def parserWrapper[A](p: P[A]) = new {
    def &#62;&#62;=[B](f: A =&#62; P[B]): P[B] = inp =&#62; parse(p, inp) match {
      case None          =&#62; None
      case Some((v,out)) =&#62; parse(f(v), out)
    }
    def +++(q: P[A]): P[A] = inp =&#62; parse(p, inp) match {
      case None =&#62; parse(q, inp)
      case x    =&#62; x
    }
  }

  def parse[A](p: P[A], inp: Seq[Char]): Option[(A,Seq[Char])] = p(inp)

  def unit   [A](v: A): P[A]    = inp =&#62; Some((v,inp))
  def failure[A]      : P[A]    = inp =&#62; None
  def item            : P[Char] = inp =&#62; inp match {
    case Seq()         =&#62; None
    case Seq(v,out@_*) =&#62; Some((v,out))
  }

  def many [A](p: P[A]): P[Seq[A]] = many1(p) +++ unit(Seq.empty)
  def many1[A](p: P[A]): P[Seq[A]] = p &#62;&#62;= (v =&#62; many(p) &#62;&#62;= (vs =&#62; unit(v+:vs)))
  def token[A](p: P[A]): P[A]      = space &#62;&#62;= (_ =&#62; p &#62;&#62;= (v =&#62; space &#62;&#62;= (_ =&#62; unit(v))))

  val sat: (Char =&#62; Boolean) =&#62; P[Char] =
    p =&#62; item &#62;&#62;= (x =&#62; if (p(x)) unit(x) else failure)
  val digit      = sat(_.isDigit)
  val lower      = sat(_.isLower)
  val upper      = sat(_.isUpper)
  val alpha      = sat(_.isLetter)
  val alphanum   = sat(_.isLetterOrDigit)
  val char: Char =&#62; P[Char] = x =&#62; sat(_ == x)
  val string: String =&#62; P[String] = {
    case &#34;&#34; =&#62; unit(&#34;&#34;)
    case x  =&#62; char(x.head) &#62;&#62;= (_ =&#62; string(x.tail) &#62;&#62;= (_ =&#62; unit(x)))
  }
  val ident      = lower &#62;&#62;= (x =&#62; many(alphanum) &#62;&#62;= (xs =&#62; unit(x+:xs)))
  val nat        = many1(digit) &#62;&#62;= (xs =&#62; unit(xs.mkString.toInt))
  val int        = (char('-') &#62;&#62;= (_ =&#62; nat &#62;&#62;= (n =&#62; unit(-n)))) +++ nat
  val space      = many(sat(_.isWhitespace)) &#62;&#62;= (_ =&#62; unit())
  val identifier = token(ident)
  val natural    = token(nat)
  val integer    = token(int)
  val symbol: (String =&#62; P[String]) = xs =&#62; token(string(xs))
}

import Parsers._
lazy val expr: P[Int] = term &#62;&#62;= (t =&#62;
                         (symbol(&#34;+&#34;) &#62;&#62;= (_ =&#62;
                          expr        &#62;&#62;= (e =&#62;
                          unit(t+e)))
                         ) +++ unit(t))
lazy val term: P[Int] = fact &#62;&#62;= (f =&#62;
                         (symbol(&#34;*&#34;) &#62;&#62;= (_ =&#62;
                          term        &#62;&#62;= (t =&#62;
                          unit(f*t)))
                         ) +++ unit(f))
lazy val fact: P[Int] = (symbol(&#34;(&#34;) &#62;&#62;= (_ =&#62;
                         expr        &#62;&#62;= (e =&#62;
                         symbol(&#34;)&#34;) &#62;&#62;= (_ =&#62;
                         unit(e))))
                        ) +++ natural
val eval = (xs: String) =&#62; parse(expr, xs.toSeq) match {
  case Some((n, Seq())) =&#62; n
  case Some((_, out))   =&#62; sys.error(&#34;unused input &#34; + out.mkString)
  case None             =&#62; sys.error(&#34;invalid input&#34;)
}

assert( eval(&#34;2*3+4&#34;)       == 10 )
assert( eval(&#34;2*(3+4)&#34;)     == 14 )
assert( eval(&#34;2 * (3 + 4)&#34;) == 14 )
</pre>

<br>

<h4> Option のメソッドを使う</h4>
<p>パターンマッチは一覧性にすぐれるのだけれども Option でパターンマッチする場合に決まった形が現れる。</p>
<p>この部分の None =&#62; None は何度も書いていると飽きてくる...多分</p>
<pre class="syntax-highlight">
<span class="synIdentifier">    def</span> &#62;&#62;=[B](f: A =&#62; P[B]): P[B] = inp =&#62; parse(p, inp) match {
      <span class="synType">case</span> None          =&#62; None
      <span class="synType">case</span> Some((v,out)) =&#62; parse(f(v), out)
    }
</pre>

<br>

<p>というわけで省略してしまう。</p>
<pre class="syntax-highlight">
<span class="synIdentifier">    def</span> &#62;&#62;=[B](f: A =&#62; P[B]): P[B] =
      inp =&#62; parse(p, inp).flatMap{ <span class="synType">case</span> (v,out) =&#62; parse(f(v), out) }
</pre>

<p>Some を書かない代わりに flatMap でつなげるだけ。</p>
<br>

<p>もう一つの方も x =&#62; x は Some(y) =&#62; Some(y) なので何かメソッドがありそう。</p>
<pre class="syntax-highlight">
    def +++(q: P[A]): P[A] = inp =&#62; parse(p, inp) match {
      case None =&#62; parse(q, inp)
      case x    =&#62; x
    }
</pre>

<br>

<p>しかし、Option の API を探してみたがこれと思えるものがなかった。</p>
<pre class="syntax-highlight">
<span class="synIdentifier">    def</span> +++(q: P[A])        : P[A] =
      inp =&#62; parse(p, inp).toLeft(parse[A](q, inp)).fold(Option(_), identity)
</pre>

<p>toLeft で一旦 Either に変換して再度 fold で Option に戻している。</p>
<p>おそらく None =&#62; None の場合は flatMap で済むのでメソッドにすればよいが、</p>
<p>それ以外の場合は最初から Either を使うのだろう。</p>
<br>

<h4> Either のメソッドを使う</h4>
<p>パーサーの戻り値を Either 型に変更する。</p>
<p>まずはパターンマッチで</p>
<pre class="syntax-highlight">
  type P[A] = Seq[Char] =&#62; Either[Unit,(A,Seq[Char])]

  implicit def parserWrapper[A](p: P[A]) = new {
    def &#62;&#62;=[B](f: A =&#62; P[B]): P[B] = inp =&#62; parse(p, inp) match {
      case Left(_)        =&#62; Left()
      case Right((v,out)) =&#62; parse(f(v), out)
    }
    def +++(q: P[A]): P[A] = inp =&#62; parse(p, inp) match {
      case Left(_) =&#62; parse(q, inp)
      case x       =&#62; x
    }
</pre>

<p>None が Left に、Some が Right に変わっただけ</p>
<br>

<p>これを Either のメソッドを使うように変更してみる。</p>
<pre class="syntax-highlight">
  implicit<span class="synIdentifier"> def</span> parserWrapper[A](p: P[A]) = <span class="synStatement">new</span> {
<span class="synIdentifier">    def</span> &#62;&#62;=[B](f: A =&#62; P[B]): P[B] = inp =&#62;
      parse(p, inp).right flatMap{ <span class="synType">case</span> (v,out) =&#62; parse(f(v), out) }
<span class="synIdentifier">    def</span> +++   (q: P[A])     : P[A] = inp =&#62;
      parse(p, inp).left  flatMap{ <span class="synType">case</span> _       =&#62; parse(q, inp) }
  }
</pre>

<p>両方とも flatMap になるので読みやすい。</p>
<p>.right や .left は 「Right だったら」や「Left だったら」と読める。</p>
<br>

<p>パーサーを生成している部分も変更しなくてはならない。</p>
<p>これも素直に None を Left に Some を Right に書き換えただけ。</p>
<pre class="syntax-highlight">
  def unit   [A](v: A): P[A]    = inp =&#62; Right((v,inp))
  def failure[A]      : P[A]    = inp =&#62; Left()
  def item            : P[Char] = inp =&#62; inp match {
    case Seq()         =&#62; Left()
    case Seq(v,out@_*) =&#62; Right((v,out))
  }
</pre>

<br>

<p>item は Seq でパターンマッチしているがこれもパターンマッチでなくすことができる。</p>
<pre class="syntax-highlight">
<span class="synIdentifier">  def</span> item            : P[Char] = inp =&#62; <span class="synStatement">if</span> (inp.isEmpty) Left() <span class="synStatement">else</span> Right((inp.head,inp.tail))
</pre>

<br>

<p>さらに Either のメソッドを使って</p>
<pre class="syntax-highlight">
  def item            : P[Char] = inp =&#62; Either.cond(!inp.isEmpty, (inp.head,inp.tail), ())
</pre>

<p>左が Right で右が Left なので少しややこしい。</p>
<br>

<h4> for 式を使う</h4>
<p>調べていたら、第8章を Scala で実装されている方がいた。</p>

<ul>
<li> <a href="http://www.ayutaya.com/dev/scala/haskell-parser-generator" target="_blank">Page not found - Ayutaya.com</a></li>
<li> <a href="http://svc.ayutaya.com/wordpress/2011/04/22/scala-haskell-parser-generato/" target="_blank">404 Not Found</a></li>
</ul>
<br>

<p>パーサーに map と flatMap が実装されていれば for 式が使えるらしい。</p>
<pre class="syntax-highlight">
<span class="synType">object</span> Parsers {
  <span class="synType">type</span> P[A] = Seq[Char] =&#62; Either[Unit,(A,Seq[Char])]

  implicit<span class="synIdentifier"> def</span> parserWrapper[A](p: P[A]) = <span class="synStatement">new</span> {
<span class="synIdentifier">    def</span> flatMap[B](f: A =&#62; P[B]): P[B] = inp =&#62;
      parse(p, inp).right flatMap{ <span class="synType">case</span> (v,out) =&#62; parse(f(v), out) }
<span class="synIdentifier">    def</span> map    [B](f: A =&#62; B)   : P[B] = inp =&#62;
      parse(p, inp).right flatMap{ <span class="synType">case</span> (v,out) =&#62; Right((f(v),out)) }
<span class="synIdentifier">    def</span> +++   (q: P[A])     : P[A] = inp =&#62;
      parse(p, inp).left  flatMap{ <span class="synType">case</span> _       =&#62; parse(q, inp) }
  }

<span class="synIdentifier">  def</span> parse[A](p: P[A], inp: Seq[Char]) = p(inp)

<span class="synIdentifier">  def</span> <span class="synType">unit</span>   [A](v: A): P[A]    = inp =&#62; Right((v,inp))
<span class="synIdentifier">  def</span> failure[A]      : P[A]    = inp =&#62; Left()
<span class="synIdentifier">  def</span> item            : P[Char] = inp =&#62; Either.cond(!inp.isEmpty, (inp.head,inp.tail), ())

<span class="synIdentifier">  def</span> many [A](p: P[A]): P[Seq[A]] = many1(p) +++ <span class="synType">unit</span>(Seq.empty)
<span class="synIdentifier">  def</span> many1[A](p: P[A]): P[Seq[A]] = <span class="synStatement">for</span> (v &#60;- p; vs &#60;- many(p)) <span class="synType">yield</span> v+:vs
<span class="synIdentifier">  def</span> token[A](p: P[A]): P[A]      = <span class="synStatement">for</span> (_ &#60;- space; v &#60;- p;_ &#60;- space) <span class="synType">yield</span> v

  <span class="synType">val</span> sat: (Char =&#62; Boolean) =&#62; P[Char] =
    p =&#62; <span class="synStatement">for</span> (x &#60;- item; y &#60;- <span class="synStatement">if</span> (p(x)) <span class="synType">unit</span>(x) <span class="synStatement">else</span> failure) <span class="synType">yield</span>(y)
  <span class="synType">val</span> digit      = sat(_.isDigit)
  <span class="synType">val</span> lower      = sat(_.isLower)
  <span class="synType">val</span> upper      = sat(_.isUpper)
  <span class="synType">val</span> alpha      = sat(_.isLetter)
  <span class="synType">val</span> alphanum   = sat(_.isLetterOrDigit)
  <span class="synType">val</span> <span class="synType">char</span>: Char =&#62; P[Char] = x =&#62; sat(_ == x)
  <span class="synType">val</span> string: <span class="synConstant">String</span> =&#62; P[<span class="synConstant">String</span>] = {
    <span class="synType">case</span> <span class="synConstant">&#34;&#34;</span> =&#62; <span class="synType">unit</span>(<span class="synConstant">&#34;&#34;</span>)
    <span class="synType">case</span> x  =&#62; <span class="synStatement">for</span> (_ &#60;- <span class="synType">char</span>(x.head);_ &#60;- string(x.tail)) <span class="synType">yield</span> x
  }
  <span class="synType">val</span> ident      = <span class="synStatement">for</span> (x &#60;- lower; xs &#60;- many(alphanum)) <span class="synType">yield</span> x+:xs
  <span class="synType">val</span> nat        = <span class="synStatement">for</span> (xs &#60;- many1(digit)) <span class="synType">yield</span> xs.mkString.toInt
  <span class="synType">val</span> <span class="synType">int</span>        = (<span class="synStatement">for</span> (_ &#60;- <span class="synType">char</span>('-'); n &#60;- nat) <span class="synType">yield</span> -n) +++ nat
  <span class="synType">val</span> space      = <span class="synStatement">for</span> (_ &#60;- many(sat(_.isWhitespace))) <span class="synType">yield</span> ()
  <span class="synType">val</span> identifier = token(ident)
  <span class="synType">val</span> natural    = token(nat)
  <span class="synType">val</span> integer    = token(<span class="synType">int</span>)
  <span class="synType">val</span> symbol: (<span class="synConstant">String</span> =&#62; P[<span class="synConstant">String</span>]) = xs =&#62; token(string(xs))
}

<span class="synPreProc">import</span> Parsers._
lazy <span class="synType">val</span> expr: P[Int] = <span class="synStatement">for</span> {
                          t &#60;- term
                          r &#60;- (<span class="synStatement">for</span> {
                            _ &#60;- symbol(<span class="synConstant">&#34;+&#34;</span>);
                            e &#60;- expr
                          } <span class="synType">yield</span> t+e) +++ <span class="synType">unit</span>(t)
                        } <span class="synType">yield</span> r
lazy <span class="synType">val</span> term: P[Int] = <span class="synStatement">for</span> {
                          f &#60;- fact
                          r &#60;- (<span class="synStatement">for</span> {
                            _ &#60;- symbol(<span class="synConstant">&#34;*&#34;</span>);
                            t &#60;- term
                          } <span class="synType">yield</span> f*t) +++ <span class="synType">unit</span>(f)
                        } <span class="synType">yield</span> r
lazy <span class="synType">val</span> fact: P[Int] = (<span class="synStatement">for</span> {
                           _ &#60;- symbol(<span class="synConstant">&#34;(&#34;</span>)
                           e &#60;- expr
                           _ &#60;- symbol(<span class="synConstant">&#34;)&#34;</span>)
                         } <span class="synType">yield</span> e) +++ natural
<span class="synType">val</span> eval = (xs: <span class="synConstant">String</span>) =&#62; parse(expr, xs.toSeq) match {
  <span class="synType">case</span> Right((n, Seq())) =&#62; n
  <span class="synType">case</span> Right((_, out))   =&#62; sys.error(<span class="synConstant">&#34;unused input &#34;</span> + out.mkString)
  <span class="synType">case</span> Left(_)           =&#62; sys.error(<span class="synConstant">&#34;invalid input&#34;</span>)
}

assert( eval (<span class="synConstant">&#34;2*3+4&#34;</span>)       == <span class="synConstant">10</span> )
assert( eval (<span class="synConstant">&#34;2*(3+4)&#34;</span>)     == <span class="synConstant">14</span> )
assert( eval (<span class="synConstant">&#34;2 * (3 + 4)&#34;</span>) == <span class="synConstant">14</span> )
</pre>

<p>flatMap だけでよさそうに思うが map がないとエラーになる。</p>
<p>eval でメソッド使ってないことに気づいたが、ここはパターンマッチの方が見やすいのでこのままにしておく。</p>
</div>
]]></content:encoded>
<dc:creator>deve68</dc:creator>
<dc:date>2012-05-20T23:44:26+09:00</dc:date>
<dc:subject>.scala</dc:subject>
</item>
</rdf:RDF>
