<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://www3.atwiki.jp/nanakoso/">
    <title>Haskellの駄目な使い方</title>
    <link>http://www3.atwiki.jp/nanakoso/</link>
    <description>Haskellの駄目な使い方</description>

    <dc:language>ja</dc:language>
    <dc:date>2007-07-08T06:23:10+09:00</dc:date>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/10.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/20.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/9.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/23.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/2.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/21.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/22.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/18.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/19.html" />
                <rdf:li rdf:resource="http://www3.atwiki.jp/nanakoso/pages/16.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/10.html">
    <title>駄目日記/2006年04月19日/世界一やさしいモナド解説を読んで</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/10.html</link>
    <description>
      #blognavi

すごい放置してたのに
いきなり更新。


http://d.hatena.ne.jp/m-hiyama/20060419/1145432492
↑ここのおかげで
もやもやしたままなんとなくMonad使ってきたけど、
かなり頭が整理できました。

モナド三点セット(M, ext, unit)はHaskellでは
M :各モナド型 (IO とか Maybeとか)
unit : は return
ext : は liftM (←まちがい。[[訂正記事&gt;http://www3.atwiki.jp/nanakoso/pages/13.html]]）

一番多用する(m &gt;&gt;= f)は  (liftM f) $ m　

ext,liftM　になんで関数適用($)をくっ付けて使うのかは
プログラミング言語としての使い勝手の問題かな？

追記：上記の　liftM は間違い。[[訂正記事&gt;http://www3.atwiki.jp/nanakoso/pages/13.html]]

#right{
カテゴリ: &amp;#x5b;[[プログラミング&gt;駄目日記/カテゴリ/プログラミング]]&amp;#x5d; - &amp;trackback() - 2006年04月19日 18:50:33
}


- LOiklxvZnTAFz  -- adult comics  (2007-07-08 06:23:10)
#comment(nostyle,nsize8,size30)
#blognavi    </description>
    <dc:date>2007-07-08T06:23:10+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/20.html">
    <title>駄目日記/2006年05月29日/今回はHaskellともKISSとも関係ないmixiについて。</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/20.html</link>
    <description>
      #blognavi

http://d.hatena.ne.jp/another/20060528/1148822562
を読んでチョット思うところあったので。

mixi（さらにいえばSNS全般について）

＜強調＞複数アカウントを禁止するのであれば＜／強調＞

マイミクとコミュニティのクラスタリングをサポートしてほしい。
（ひょっとして他のSNSに似たようなのがあったりして）

たとえば、実際おいらのmixiは
エロ同人つながりのマイミクがたくさんいるけど
そのおかげで数学、プログラミング関係の込みユニティに入るのは
躊躇しちゃうんだよね。
自分も恥ずかしいし実際に嫌がるひともいそうだし。
（エロマンガ家のマイミクの人で実際はじかれたりしている人もいるし。コミュじゃなくて個人にだけど）

そんなわけで、
クラスタは個人ごとに自由に作成、設定、できるようにして、
エロ同人クラスタつながりで見に来た人にはエロクラスタつながりしか見えないし
プログラミングクラスタつながりで来た人にはそのクラスタしか見せない。
両方にマイミク（コミュ）をもっている人だけその人の全貌が見える。
みたいなのがほしい。

リアルライフを振り返ってみても、
『知り合った以上はすべての人間関係を晒さなければならない』
というのはちょっと要求が高すぎる。

仕事関係と趣味の関係で２つ以上の顔を使い分けている人はきっと沢山いるわけで
複数アカウントを認めない限りは需要はあると思う。

つらつらとここまで書いてみて思ったけど、

特定アカウントの個人を弾く機能が実際ある以上、
この手の機能をサポートしないのは
倫理的な片手落ちじゃないかとすら思えてきたぞ。

（mixiの機能一覧をよくしらべないでここまで書いたけど
有料オプションとかにすでにあったらどうしよう？）

ていうか全部mixiで遣る必要もないんじゃね？っていわれると
そのとおりですとしかいえないけど。

追記、
よく考えたら自分の書く日記やプロフィールも全部クラスタ指定できないと
意味がないと気がついた。
ていうか、メンドクサス。複数アカウント使いわけるのと変わらんわ！

追記２
http://ised.glocom.jp/ised/07030514#p2
あるところにはすでにあるようです。
 また先進的なブログサービスとしては、「DI:DO」があります*9。
 （中略）
 さらに閲覧者をグループ分けすることもできる。
 たとえば会社の同僚と高校時代の同級生といった具合ですね。

#right{
カテゴリ: &amp;#x5b;[[雑記&gt;駄目日記/カテゴリ/雑記]]&amp;#x5d; - &amp;trackback() - 2006年05月29日 11:15:27
}

#comment(nostyle,nsize8,size30)
#blognavi    </description>
    <dc:date>2007-06-28T13:21:20+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/9.html">
    <title>駄目日記/2005年06月05日/いつのまに</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/9.html</link>
    <description>
      #blognavi

うお、こんな時間かかてしまった。
でもなんとなくわかってきたぞ。

#right{
カテゴリ: &amp;#x5b;[[その他&gt;駄目日記/カテゴリ/その他]]&amp;#x5d; - &amp;trackback() - 2005年06月05日 04:37:27
}


- コメントもテスト  -- 自作自演  (2005-06-05 04:58:31)


#blognavi    </description>
    <dc:date>2007-03-02T13:55:55+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/23.html">
    <title>文字列処言語間理比較表</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/23.html</link>
    <description>
      ここ→&lt;a href=
&quot;http://0xcc.net/blog/archives/000137.html&quot;&gt;配列操作の比較表&lt;/a&gt;に触発されて、Rubyの文字列メソッドの対応物をJavaとHaskellで探してみました。&lt;br&gt;

&lt;br&gt;
Javaの文字列処理がそれほど高機能じゃないのはある程度想定内だったけど、Haskellもなかなか１対１の対応物がない。&lt;br&gt;

lines,unlinesとか逆にあまったけど。&lt;br&gt;
&lt;br&gt;
そもそもHaskellのソレって文字列処理用っていうよりほとんど汎用リスト操作関数なわけで。&lt;br&gt;

&lt;br&gt;
Haskellって&lt;br&gt;
「汎用性の高い関数を用意したから自由に組み合わせて使ってね」&lt;br&gt;

って思想だと思うわけで。&lt;br&gt;
カリー化された関数の強力な応用力とあいまってこれはこれで一つの便利さの方向性だとはおもう。&lt;br&gt;

&lt;br&gt;
ただこれの欠点は&lt;br&gt;
「もっとエレガントで短い書き方があるんじゃないか？」&lt;br&gt;

って不安がいつまでも付きまとう事。&lt;br&gt;
（しかもタチの悪い事にパズルみたいで楽しすぎる！）&lt;br&gt;
自分の修行が足りなくてイディオムを知らないせいもあるけどね。&lt;br&gt;

（これ調べてるうちに、&lt;a href=
&quot;http://www3.atwiki.jp/nanakoso/pages/4.html&quot;&gt;HaskellでLha&lt;/a&gt;にもいろいろ直したいところが！）&lt;br&gt;

&lt;br&gt;
&lt;br&gt;
Javaのパッケージ名やHaskellのモジュール名を明示するため、必要なものは完全名で書きました。&lt;br&gt;

（実際ほとんどの場合ソースの頭でimport文を使って短くかけるようにします。）&lt;br&gt;

&lt;br&gt;
&lt;br&gt;
&lt;table style=&quot;width: 485px; height: 3076px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Ruby (String)&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;th&gt;Haskell&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s = &quot;abc&quot;&lt;/td&gt;
&lt;td&gt;String s = &quot;abc&quot;&lt;/td&gt;
&lt;td&gt;s = &quot;abc&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s = x + y&lt;/td&gt;
&lt;td&gt;s = x + y&lt;/td&gt;
&lt;td&gt;s = x ++ y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s == x&lt;/td&gt;
&lt;td&gt;s.equals(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s == x&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s % [x, y]&lt;br&gt;
sprintf(s, x, y)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;String.format(s, x, y)//J2SE5.0より&lt;br&gt;&lt;/td&gt;
&lt;td&gt;Text.Printf.printf　s　x y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[x, y, z].join(s)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;foldr1 (￥a b-&amp;gt;a ++ s ++ b) [x,y,z]&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.capitalize&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.capitalize!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;vertical-align: top;&quot;&gt;&lt;code&gt;s.casecmp(x)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;vertical-align: top;&quot;&gt;// s.equalsIgnoreCase(x)&lt;br&gt;
// ってのがあるけど同値判定だけだし、、&lt;br&gt;&lt;/td&gt;
&lt;td style=&quot;vertical-align: top;&quot;&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.center(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.chomp&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.chomp!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;
&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.chop&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;init s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.chop!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.clear&lt;/td&gt;
&lt;td&gt;// sbはStringBuffer型&lt;br&gt;
sb.setLength(0);&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.concat(x)&lt;/td&gt;
&lt;td&gt;// sbはStringBuffer型&lt;br&gt;
sb.append(x);&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.count(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;
length filter (flip elem x) s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.crypt(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.delete(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;
filter (flip notElem x) s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.delete!(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.downcase&lt;/td&gt;
&lt;td&gt;s.toLowerCase()&lt;br&gt;&lt;/td&gt;
&lt;td&gt;map Data.Char.toLower s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.downcase!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&quot;2&quot;&gt;s.each_byte {|x|&lt;br&gt;
... }&lt;/td&gt;
&lt;td&gt;for(int i=0; i &amp;lt; s.length(); i++){&lt;br&gt;
char x = s.charAt(i);&lt;br&gt;
...&lt;br&gt;
}&lt;br&gt;&lt;/td&gt;
&lt;td rowspan=&quot;2&quot;&gt;mapM_ (￥x-&amp;gt;...) s&lt;br&gt;
--&lt;br&gt;
副作用を含む処理を順次起動するって意味では&lt;br&gt;
mapM_で正解だけど、...のところはモナドじゃないといけない。&lt;br&gt;

実際そこまでは要らなくて集計値とか計算結果のリストが欲しいだけで&lt;br&gt;

foldシリーズやただのmapで十分ってことも多いと思われる。&lt;br&gt;

&lt;a name=&quot;a1&quot; title=&quot;a1&quot; id=&quot;a1&quot;&gt;&lt;/a&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;//J2SE5.0より&lt;br&gt;
for(char x:s.toCharArray()){&lt;br&gt;
...&lt;br&gt;
}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&quot;2&quot;&gt;s.each_line {|x|&lt;br&gt;
... }&lt;/td&gt;
&lt;td&gt;String[] xs = s.split(&quot;￥n&quot;,-1);&lt;br&gt;
for(int i=0 ; i &amp;lt; xs.length; i++){&lt;br&gt;
String x = xs[i];&lt;br&gt;
...&lt;br&gt;
}&lt;br&gt;&lt;/td&gt;
&lt;td rowspan=&quot;2&quot;&gt;mapM_ (￥x-&amp;gt;...) $ lines s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;//J2SE5.0より&lt;br&gt;
for(String x:s.split(&quot;￥n&quot;,-1)){&lt;br&gt;
...&lt;br&gt;
}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.empty?&lt;/td&gt;
&lt;td&gt;s.length() == 0&lt;br&gt;&lt;/td&gt;
&lt;td&gt;null s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.end_with?(x)&lt;/td&gt;
&lt;td&gt;s.endsWith(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;Data.List.isSuffixOf x s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.gsub(x, y)&lt;/td&gt;
&lt;td&gt;s.replaceAll(x, y)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.gsub!(x, y)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.hex&lt;br&gt;
s.to_i(16)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;
Integer.parseInt(s,16)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.include?(x)&lt;/td&gt;
&lt;td&gt;s.indexOf(x) &amp;gt;= 0&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.index(x)&lt;/td&gt;
&lt;td&gt;s.indexOf(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.insert(i, x)&lt;/td&gt;
&lt;td&gt;// sbはStringBuffer型&lt;br&gt;
sb.insert(i,x);&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.length&lt;br&gt;
s.size&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.length()&lt;br&gt;&lt;/td&gt;
&lt;td&gt;length s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.ljust(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.lstrip&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;dropWhile Data.Char.isSpace s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.lstrip!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.match(x)&lt;/td&gt;
&lt;td&gt;s.matches(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x.match(s)&lt;/td&gt;
&lt;td&gt;java.util.regex.Pattern.matches(x, s)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.next&lt;br&gt;
s.succ&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.next!&lt;br&gt;
s.succ!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.oct&lt;br&gt;
s.to_i(8)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;Integer.parseInt(s,8)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.partition(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;Data.List.partition x s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.replace(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.reverse&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;reverse s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.reverse!&lt;/td&gt;
&lt;td&gt;// sbはStringBuffer型&lt;br&gt;
sb.reverse();&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.rindex(x)&lt;/td&gt;
&lt;td&gt;s.lastIndexOf(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.rjust(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.rpartition(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.rstrip&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.rstrip!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.scan(x) { ... }&lt;/td&gt;
&lt;td&gt;TODO&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s[i]&lt;br&gt;
s.slice(i)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.charAt(i)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s !! i&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s[i..-1]&lt;br&gt;
s.slice(i..-1)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.substring(i)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;drop i s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s[i, l]&lt;br&gt;
s.slice(i, l)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.substring(i,i+l)&lt;/td&gt;
&lt;td&gt;take l $ drop i s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s[i..j]&lt;br&gt;
s.slice(i..j)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.substring(i,j+1)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;take (l-i+1) $ drop i s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s[i...j]&lt;br&gt;
s.slice(i...j)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;s.substring(i,j)&lt;/td&gt;
&lt;td&gt;take (l-i) $ drop i s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.split(x)&lt;/td&gt;
&lt;td&gt;s.split(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.start_with?(x)*4&lt;/td&gt;
&lt;td&gt;s.startsWith(x)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;Data.List.isPrefixOf x s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.strip&lt;/td&gt;
&lt;td&gt;s.trim()&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.strip!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.sub(x, y)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.sub!(x, y)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.swapcase&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.to_f&lt;/td&gt;
&lt;td&gt;Float.parseFloat(s)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;read s&lt;br&gt;
--この式が使用される場所の型によって適宜、変換関数の実装が（コンパイル時に）選択される（多相型）&lt;br&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.to_i&lt;/td&gt;
&lt;td&gt;Integer.parseInt(s)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;read s&lt;br&gt;
--同上&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.tr!(x, y)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.tr_s!(x, y)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.unpack(x)&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.upcase&lt;/td&gt;
&lt;td&gt;s.toUpperCase()&lt;br&gt;&lt;/td&gt;
&lt;td&gt;map Data.Char.toUpper s&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.upcase!&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regexp.escape(s)&lt;br&gt;
Regexp.quote(s)&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;span id=&quot;a1&quot;&gt;&lt;/span&gt;&lt;br&gt;    </description>
    <dc:date>2006-10-29T01:37:35+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/2.html">
    <title>メニュー</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/2.html</link>
    <description>
      メニュー
-[[トップページ]]
-[[メニュー]]
-[[HaskellでLha]]
-[[文字列処言語間理比較表]]
-[[駄目日記]]

**更新履歴
#recent(10)    </description>
    <dc:date>2006-10-29T00:42:14+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/21.html">
    <title>駄目日記/カテゴリ/雑記</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/21.html</link>
    <description>
      -(2006年05月29日)&amp;nbsp;&amp;nbsp;[[今回はHaskellともKISSとも関係ないmixiについて。&gt;駄目日記/2006年05月29日/今回はHaskellともKISSとも関係ないmixiについて。]]    </description>
    <dc:date>2006-05-29T11:15:57+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/22.html">
    <title>駄目日記/2006年05月29日</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/22.html</link>
    <description>
      -[[駄目日記/2006年05月29日/今回はHaskellともKISSとも関係ないmixiについて。]]
#blognavi    </description>
    <dc:date>2006-05-29T11:15:57+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/18.html">
    <title>駄目日記/2006年04月26日/Parsecを使ってみる。</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/18.html</link>
    <description>
      #blognavi

このサイトでは最終的にHaskellで[[KISSローダー&gt;http://www.kiss-wkp.com/]]を作るという野望があるわけで。

今回は、コンフィグファイルの読み込みで使うであろう、Parsecに手を付けてみました。

[[Parsecのサイト&gt;http://www.cs.uu.nl/~daan/parsec.html]]

Parsecを使えば簡単にLL(n)文法のテキストファイルを簡単に読み込めるようになるらしいです。（理論的なことはよくわかってない）

自分は、上記のサイトのparsec-2.0.zip をダウンロードしてきたあと、Hugsの作業フォルダにTextフォルダ以下を展開しました。こうすればとりあえずは使えるようになります。
（詳しくはHugsやGHCのマニュアルを読んでください）

-Parsecの特徴
Yacc+LexやJavaCCが「文法ファイルからプログラムソースを自動生成するツール」なのに対し、Parsecは「ただのHaskellのライブラリ」です。
本体の言語のほかに「文法ファイルの文法」を覚える必要がありません。

-とりあえず試してみる
 module Main where
 import Text.ParserCombinators.Parsec
 
 paren :: Parser Char
 paren = (char &#039;{&#039;) &gt;&gt; (char &#039;}&#039;)
こんだけ。
見れば分かるとおりモナドです。
まず文字列の頭から&#039;{&#039;かどうかチェックして次に&#039;}&#039;かどうかチェックしてます。
 Main&gt; parseTest paren &quot;{}&quot; ← parseTestはParsecの関数
 &#039;}&#039;                        ← 成功したのか？

Main&gt; parseTest paren &quot;{x}&quot;  ← わざと間違ってみる。
parse error at (line 1, column 2): ← それっぽいエラーが。
unexpected &quot;x&quot;
expecting &quot;}&quot;

どうやらうまくいってる様子。
パース成功したときに&#039;}&#039;とでているのは後述。

もちろんモナドだからdo構文だって使えます。
 paren2 = do
    char &#039;{&#039;
    char &#039;}&#039;
繰り返しはこう
 starplus = do
    many (char &#039;*&#039;)
    many1 (char &#039;+&#039;)
これで、「&#039;*&#039;の０回以上の繰り返しのあとに&#039;+&#039;の１回以上の繰り返し。」になります。

正規表現の(a|b)『aまたはb』は&lt;|&gt;という新しい演算子を使います。
 starplus2 =
    many1 (char &#039;*&#039; &lt;|&gt; char &#039;+&#039;)
これで「&#039;*&#039;か&#039;+&#039;の１回以上の繰り返し」になります。

正規表現の[ab]のようなもの。
引数の文字列のいずれか１文字とマッチします。
 starplus3 = many1 (oneOf &quot;*+&quot;)
ちょっと試してみる。

Main&gt; parseTest starplus2 &quot;+*+&quot; 
&quot;+*+&quot;

Main&gt; parseTest starplus2 &quot;+*+@&quot; ←ためしに駄目っぽい入力を
&quot;+*+&quot;                            ←成功してしまった

Main&gt; parseTest starplus2 &quot;@   &quot; ←やっと失敗した
parse error at (line 1, column 1): 
unexpected &quot;@&quot;
expecting &quot;*&quot; or &quot;+&quot;

途中までパースに成功していればエラーにならないようです。

最後まできっちりチェックしたければこうするっぽい。
 starplus4 = do
    many1 (char &#039;*&#039; &lt;|&gt; char &#039;+&#039;)
    eof --正規表現の$に相当する関数。最後にのみマッチ
１文字づつチェックは面倒ですから文字列でまとめてチェックする(string)という組み込みパーサーも使ってみます。
 dame = string &quot;abc&quot; &lt;|&gt; char &#039;+&#039;

Main&gt; :l sample.hs 
ERROR &quot;sample.hs&quot;:23 - Type error in application
*** Expression     : string &quot;abc&quot; &lt;|&gt; char &#039;+&#039;
*** Term           : string &quot;abc&quot;
*** Type           : GenParser Char b String
*** Does not match : GenParser Char a Char

型不整合になってしまいました。

実は、Parsecのパーサーもただの(Parserモナドの)関数ですから、返り値をもっていて(&lt;|&gt;)を使うときは左右それぞれ型が合っていなければならないようです。
つまり(string &quot;abc&quot;)は成功したときは(Parser String)という型の値を返しますが、char &#039;+&#039;の返り値は(Parser Char)だから駄目ということ。
（エラーメッセージと少しちがいますがだいたいそんな感じ。）

とりあえずこうしてみた。
(（&gt;&gt;)より(&lt;|&gt;)のほうが結合の優先順位がたかいので注意。）
 abcplus :: Parser String
 abcplus = 
    string &quot;abc&quot; &lt;|&gt; (char &#039;+&#039; &gt;&gt; return &quot;+&quot;)
 
 abcplus2 :: Parser String
 abcplus2 = --これでもOK
    string &quot;abc&quot; &lt;|&gt; 
    ( do
        char &#039;+&#039; 
        return &quot;+&quot;
    )
 
 abcplus3 :: Parser ()
 abcplus3 = --どっちも返り値なしで合わせてみたパターン
    (string &quot;abc&quot; &gt;&gt; return ()) &lt;|&gt; (char &#039;+&#039; &gt;&gt; return () )
見れば分かるとおり、Parserモナドのreturn関数はチェックをまったくせずに任意のParser型の返り値を作れます。

（&gt;&gt;）や（&gt;&gt;=）で結合した場合はもちろん最後の値が有効になりますから
『(char &#039;{&#039;) &gt;&gt; (char &#039;}&#039;)』の結果が成功したときには&#039;}&#039;が表示されていたわけです。

ちなみにmanyやmany1は繰り返しの結果をリストにして返します。
いままで(char x)をmanyに適用させていたのでうまいぐあいに(Parser [Char])つまりは(Parser String)が帰ってきていたわけでした。

あと、気をつけなければならないのは(&lt;|&gt;)は最初の（左側の）関数を試したあとで『そのままでは後戻りしない』らしいこと↓。
(以下[[邦訳ドキュメント&gt;http://www.lab2.kuis.kyoto-u.ac.jp/~hanatani/tmp/Parsec.html]]の受け売り。)
 testOr  =   string &quot;(a)&quot;
         &lt;|&gt; string &quot;(b)&quot;
これを parserTest testOr &quot;(b)&quot; でためしてみると
パースに失敗してしまいます。

Main&gt; parserTest testOr &quot;(b)&quot;
ERROR - Undefined variable &quot;parserTest&quot;
Main&gt; parseTest testOr &quot;(b)&quot;
parse error at (line 1, column 1):
unexpected &quot;b&quot;
expecting &quot;(a)&quot;

これは&lt;|&gt;の最初の関数でひとたび２文字以上先に進んでしまうと二度と後戻りしないからのようです。

これには２通り解決方法があります。
最初は(try)という関数を使う方法。
 testOr2  = try( string &quot;(a)&quot; ) &lt;|&gt; string &quot;(b)&quot;
基本的にtryの中にはいくらでも複雑なパーサーが入れられるようですがそれだけ後戻り用メモリや処理時間のペナルティも大きくなります。

二番目の方法は、実現したい文法によっては難しいこともあるかも。
 testOr3  = do
        char &#039;(&#039;
        (string &quot;a&quot; &lt;|&gt; string &quot;b&quot;)
        char &#039;)&#039;
ここがParsecと正規表現の違う点だと思いました。

なるべくtryを使わないように、また使うとすればなるべく範囲を狭くするようにするのが高速化のコツでしょうか。

最後に返り値を使った例を。
 pair :: Parser (String,String)
 pair = do
    char &#039;{&#039;
    a &lt;- many1 (noneOf &quot;,}&quot;) -- noneOf x はx以外のものとマッチ
    char &#039;,&#039;
    b &lt;- many1 (noneOf &quot;,}&quot;)
    char &#039;}&#039;
    return (a,b)

 pairs :: Parser [(String,String)]
 pairs = many1 pair

{a,b}を入力すると
(&quot;a&quot;,&quot;b&quot;)というタプルを返します。

Main&gt; parseTest pair &quot;{,}&quot;        ←わざとエラーに
parse error at (line 1, column 2):
unexpected &quot;,&quot;
 
Main&gt; parseTest pair &quot;{a,b}&quot;      ←成功！
(&quot;a&quot;,&quot;b&quot;)

Main&gt; parseTest pairs &quot;{a,b}{c,d}{xxx,yyy}&quot;  ←こっちも試す
[(&quot;a&quot;,&quot;b&quot;),(&quot;c&quot;,&quot;d&quot;),(&quot;xxx&quot;,&quot;yyy&quot;)]


複雑なdata型なども作れそうです。

以上でParsecの基本は一通りみたでしょうか。

正規表現でできるようなことはだいたいできるようになりました。
しかし、これだけで実用的なパーサーを１から作るのは結構大変です。
正規表現よりタイプ量がものすごく多くなりますし。
コンパイルと型チェックできるだけでもそれなりに自分にはありがたいのですけどね。
（他の言語で正規表現は単なる文字列値として扱われて実行時まで記述ミスがわからないことも多い）

実際にParsecを使ってパーサーを書くときには、char や string といった低レベルな関数ばかりでなく、空白やコメントを読み飛ばしながらリテラルや予約語をとりだせるような、もうすこし高機能な関数を使用することになります。
(↓下記ドキュメントにも解説が載っています）
だたし、こういった高機能な関数はコメントの定義(/* */,--など)や、識別子や演算子に使える文字の種類など設定項目が結構あります。

この辺の使い方も気が向いたら書こうかと思います。

今回のエントリに関しては下記のParsecの和訳ドキュメントに
大いにお世話になりました。
http://www.lab2.kuis.kyoto-u.ac.jp/~hanatani/tmp/Parsec.html

あと、ここもリンク集と使用レポートおせわになりました。
http://221.112.61.214/~kzk/column/haskell_parsec.html


#right{
カテゴリ: &amp;#x5b;[[プログラミング&gt;駄目日記/カテゴリ/プログラミング]]&amp;#x5d; - &amp;trackback() - 2006年04月26日 17:53:13
}
#comment(nostyle,nsize8,size30)
#blognavi    </description>
    <dc:date>2006-04-26T17:53:50+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/19.html">
    <title>駄目日記/2006年04月26日</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/19.html</link>
    <description>
      -[[駄目日記/2006年04月26日/Parsecを使ってみる。]]
#blognavi    </description>
    <dc:date>2006-04-26T17:53:50+09:00</dc:date>
  </item>
    <item rdf:about="http://www3.atwiki.jp/nanakoso/pages/16.html">
    <title>駄目日記/2006年04月21日/Haskellの(&gt;&gt;=)の正体</title>
    <link>http://www3.atwiki.jp/nanakoso/pages/16.html</link>
    <description>
      #blognavi

ここ数日のモナドのどたばたで得た
結論めいたものをちょっとまとめておきます。

-Haskellの演算子(&gt;&gt;=)は、実質的には圏論のモナド(M, ext, unit)の ext(拡張)そのものである。
-ただし、２項演算子として使いやすいようにextの第一引数と第二引数を入れ替えてある。
つまり
 ext = (flip (&gt;&gt;=)) = (=&lt;&lt;)
 --flip f a b = f b a
なわけでした。

当初 
 m &gt;&gt;= f = (ext f) $ m
と捉えていたせいで「ext になぜ関数適用($)がくっついているんだろう。」と疑問でしたが,
 (&gt;&gt;=) m f = ext f m
と書けば、単に引数が逆なだけだったのでした。

以下ちょっと蛇足？

 f3( f2( f1 ) )
という式があってこれをモナドで拡張すると、
 (ext f3&#039;) ( (ext f2&#039;) ( f1&#039; ) ) --ただしf1&#039;はf1のモナド版
参照：[[世界で一番やさしい「モナド入門」&gt;http://d.hatena.ne.jp/m-hiyama/20060419/1145432492]]

これをHaskellの中置演算子記法で変形すると
 f3&#039; `ext` f2&#039; `ext` f1&#039;
と右→左の順番になります。
もとのf3( f2( f1 ) )をあらわす関数結合が f3.f2.f1ですから当然なのかも知れませんが。

ただ、Haskellを作った人はたぶん「これはちょっと不便だ」と考えて、
原義の ext の引数の順序を入れ替えて(&gt;&gt;=)を作ったのでしょう。
 f1&#039; &gt;&gt;= f2&#039; &gt;&gt;= f3&#039;
そのお陰でいま私たちはIO処理を
普段文章を読むのと同じ順序・方向で書けるわけなのでした。

(すでに檜山さんのところのコメント欄や酒井さんやブクマなどで散々指摘されてきた内容が
私の脳にしみこむのにここまでかかってしまいました。)

#right{
カテゴリ: &amp;#x5b;[[プログラミング&gt;駄目日記/カテゴリ/プログラミング]]&amp;#x5d; - &amp;trackback() - 2006年04月21日 15:00:13
}
#comment(nostyle,nsize8,size30)
#blognavi    </description>
    <dc:date>2006-04-21T15:24:06+09:00</dc:date>
  </item>
  </rdf:RDF>

