« ext4にしてみた。 | トップページ | ぼちぼちβ版ですな。 »

イマサラながらuimを使ってみる。

たまたま、某掲示板で、uimで困っていた、余計な子音を切り捨てないようにする設定を開示されていた方がいたので、それを利用してみることに。
ちなみに、設定その物は以下。

(require "japanese.scm")
(define ja-rk-rule-hoge
(map
(lambda (c)
(list (cons (list c) ()) (list c c c)))
'("b" "c" "d" "f" "g" "h" "j" "k" "l" "m"
"p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
"A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
"N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z")))
(if (symbol-bound? 'ja-rk-rule-hoge)
(set! ja-rk-rule (append ja-rk-rule-hoge ja-rk-rule)))

これをhomeに、.uimとして保存すれば、変換前の状態で余計な子音がある単語も入力可能となり、F10とかで半角英数に変換する事も可能に。
その他、文節区切りを指定文字で表示するなんて機能もあるので、結構、Chromiumと組み合わせた時に威力を発揮するかもしれないな、なんて。
#何故かChromiumでiBus使うと文節の色が付かなかったりするので、文節の切り直しがとても大変。

軽いと評判のuimなので、このまま様子を見ようと思ってたりしますが、ibusの方が使い勝手が良かったりすると、というか、ibusの方に問題がないのなら、あちらが標準なので、あちらを使う方がいいのかも知れません。
ま、この辺、綺麗に動いてくれるなら、何使っても同じかも知れませんけどね。

で、shiftキーを押しても大文字で入力されてくれない。orz
この辺、もしかして、やっぱりなんか設定しないとならないのかな。ちと調べてみます。

|

« ext4にしてみた。 | トップページ | ぼちぼちβ版ですな。 »

Ubuntu」カテゴリの記事

パソコン・インターネット」カテゴリの記事

コメント

うん?何じゃこりゃ?
Schemeコード?

投稿: cametan | 2009年9月27日 (日) 23時29分

schemeかも知れません。
uim本体も、似たようなコードで書かれてました。
手を入れようと思って、文法が解らないので断念しました。(笑)

投稿: かおりん | 2009年9月28日 (月) 11時24分

かおりんさんが珍しくLispみたいな事やってんな、と(笑)。

uimって調べてみたんですが、この辺書いてないんですよね。Guile使ってんのかな?

(注:GuileはGNUの標準スクリプト実装で、言語はSchemeを使用してます。いわば「GNUのVBA」はSchemeなんです。)

Lisp系のコードってインデント無いとマジで読めないんですよ(笑)。

;; こんな感じの意味。

(require "japanese.scm")  ; ここはCで言う#includeみたいなヤツ

(define ja-rk-rule-hoge   ; 変数 ja-rk-rule-hoge を定義する。
 (map
  (lambda (c)
   (list (cons (list c) ()) (list c c c)))
  '("b" "c" "d" "f" "g" "h" "j" "k" "l" "m"
   "p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
   "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
   "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z")))

;; 以降は逐次実行
(if (symbol-bound? 'ja-rk-rule-hoge)             ; ja-rk-rule-hogeと言うシンボルが束縛されてたら?
(set! ja-rk-rule (append ja-rk-rule-hoge ja-rk-rule))) ;ja-rk-ruleを書き直せ

;; ここまで。

だから、関数とかそう言うメンド臭い事は一切定義してませんね。この式だと。大まかに言うと上のような感じです。
mapってのはリストを作る手続きで次のように使います。

> (map + '(1 2 3) '(4 5 6))
(5 7 9)
>

つまり、リストの「各要素」に対して関数を「適用する」って事ですね。
この機能はCとかには無いんですが、一方、PythonやRuby、JavaScriptじゃあお馴染みだと思います。
ですから、上の例は+(加算関数)を以降のリストに適用しているわけですが、元々のコードだと、

(lambda (c)
  (list (cons (list c) ()) (list c c c)))

って部分で、「無名の関数」を定義して、以降あるリストの各要素("b"とか"c"とか)に「適用しろ」って言ってるんですね。
ここで、無名関数で作り出したい「形式」は次のようなものです。

(((hoge)) (hoge hoge hoge))

(list (cons (list c) ()) (list c c c))の計算結果は上のようになるんで、結局、

((("b")) ("b" "b" "b"))
((("c")) ("c" "c" "c"))
......

って要素を持つリストを返せ、っつってんですね。

if式はCで言うif文とまあ、同じです。

(set! ja-rk-rule (append ja-rk-rule-hoge ja-rk-rule))

ってのはCで言う

ja-rk-rule = ja-rk-rule-hoge + ja-rk-rule

と同じだ、って考えてまあ良いと思います。まあ、実際は変数がリスト同士なんですが。
関数appendは

> (append '(a b c) '(d e f))
(a b c d e f)
>

みたいな作用があるんで、元々あるja-rk-ruleと言うリストと今新しく定義したja-rk-rule-hogeと言うリストを「連結」しちゃって、set!でja-rk-ruleを「定義しなおせ」って言ってるだけ、ですね。
どっかでja-rk-ruleってリストがあるんでしょう(恐らく冒頭のrequireでこのリストを読み込んでるんじゃないか、って思います)。

投稿: cametan | 2009年9月28日 (月) 12時44分

うーんなるほど、ですね。
uimってCとC++を中心にして、SigSchemeと言う処理系も絡んで作られているみたいですね。3つの言語混在、と言うか(笑)。QtやGTKはともかくとして、C/C++はかおりんさんの領分ですね(笑)。そっちはちっとも分からん(笑)。

SigSchemeってのは、Gimpのマクロ言語として採用されている、TinySchemeの改造版みたいです。「SCM」ってディレクトリに含まれているのがSchemeのスクリプトソースのようですね。

投稿: cametan | 2009年9月28日 (月) 19時41分

詳細な解説ありがとうございます。
map近辺がピンと来てませんけど。(^^;

無名関数定義は、確かにJavaScriptでよく使うので、そこは解るんですが、関数の中身の処理が、ピンと来てないです。
#慣れがないから、表記から計算結果がイメージできない。

とはいえ、おかげで、どんな処理なのかはイメージできました。
たぶん、そうして返された変数が、入力された文字列とマップされて、その結果を返すようになってるんでしょうね。
(c c c)の部分が、切り捨てられないように、値を設定しているところと見ました。(笑)

まあ、想像を確認するためには、uimの中身を確認しないとなりませんが。

先日、ざっくりとそちらの中身を見ましたが、さほど性能の必要ない、IMとしての主な処理は、schemeで書かれてるっぽいですね。

そういう点では、iBusと考え方は同じっぽいかな。
#iBusも変換エンジンとの通信部分はCらしいし。

とはいえ。
これに慣れるのはしんどそうだ。(^^;

投稿: かおりん | 2009年9月28日 (月) 22時40分

>無名関数定義は、確かにJavaScriptでよく使うので、そこは解る

多分そうだと思います。
JavaScriptは構文のスタイルはCに近いんですが、一方、内部的にはむしろSchemeに近い、って話なんで。
lambdaってのは数理論理学者のアロンゾ・チャーチが(確か)言い出した「ラムダ算法」由来ですが、JavaScriptの

function (x) { ... }

ってのとやってる事は全く同じです。Lispの方が論理学由来の「古い形式」引きずってるんですよね。

>関数の中身の処理が、ピンと来てないです。

うん、ちょっとリスト生成の書き方がワヤクチャですよね(笑)。あんま綺麗じゃないかも。
Schemeの標準で考えると、恐らくそこの部分は

(lambda (c)
   `(((,c)) (,c ,c ,c)))

って書いても同じじゃないのかな、って思うんですけど。
Lispだと逆引用符(`)は「計算を避けろ」って意味で、同時にコンマ(,)はそこに無名関数(ラムダ式)の引数を「埋め込め」って意味になるんで、多分こっち使った方が見た目分かりやすいんじゃないか、って思います。
例えば、敢えて無名関数じゃなくって、名前与えますが、原コードだと、例えばhogeと言う関数を次のように定義して、

(define (hoge c)
  (list (cons (list c) '()) (list c c c)))

これを、ちょっと短いリスト("b" "c" "d")にmapを使って適用すると、

> (map hoge '("b" "c" "d"))
(((("b")) ("b" "b" "b")) ((("c")) ("c" "c" "c")) ((("d")) ("d" "d" "d")))
>

となります。この「長いリスト適用バージョン」が、オリジナルのja-rk-rule-hogeで欲しい、「リスト」定義なんですよ。
一方、関数fugaを次のように定義してみます。

(define (fuga c)
  `(((,c)) (,c ,c ,c)))

これを上と同様にmap使って("b" "c" "d")に適用すると、

> (map fuga '("b" "c" "d"))
(((("b")) ("b" "b" "b")) ((("c")) ("c" "c" "c")) ((("d")) ("d" "d" "d")))
>

になるんで、結果同じですね。
多分、コード的に言うと、他言語ユーザーだと後者の方が見た目分かりやすいんじゃないでしょうか?

>まあ、想像を確認するためには、uimの中身を確認しないとなりませんが。

うん。あとは、Scheme実際走らせて見てください。端末で。
Ubuntu等のGNU/Linuxは、最近Pythonもビルトインで入ってますが、同時にGuileって処理系もビルトインで入ってる筈なんですよ。
端末でguileって入力したら、そのままGuileが走り出すと思います。インストールは必要無かった、と思います(記憶違いじゃなかったら)。

>先日、ざっくりとそちらの中身を見ましたが、さほど性能の必要ない、IMとしての主な処理は、schemeで書かれてるっぽいですね。

あと、ソースフォルダ見てみたんですけど、そのSigSchemeってのが丸ごと入ってるような感じですね。
uimビルドすると、付属のSigSchemeもまとめてビルドされるような。

投稿: cametan | 2009年9月28日 (月) 23時22分

ようやく解りました。
そういうイメージですか。ありがとうござます。

確かに後者の方が、ワタクシなんぞには解り易いですが、schemeっぽくないんでしょうね。

恥ずかしい話ですが(笑)、最初ワタクシ、この定義は単なる定義ファイルなんだと思ってました。
まさか、実装だとは。(^^;

投稿: かおりん | 2009年9月28日 (月) 23時30分

>確かに後者の方が、ワタクシなんぞには解り易いですが、schemeっぽくないんでしょうね。

う~ん、どうでしょうねえ・・・・・・。
確かにあんまSchemeでは逆引用符とかコンマは「公式には」使わない可能性が高いんですけど・・・・・・。

いや、元々Lisp系言語では、逆引用符とかコンマって使うんですよ。「ユーザー定義構文」とか、あるいは「ユーザー定義プログラミング言語」ってのをLispの上に構築する際に。これを「マクロ」って言います。
(Cで言うマクロとはニュアンスが全然違うんですが)
全くLispらしくない言語や構文を「Lispの上で」作るには重宝するんですが・・・・・・。
一方、SchemeはCommon Lispと違って、その「マクロ」ってのが仕様書決める際に長年ゴチャゴチャあーでもねえ、こーでもねえ、って議論して揉めてたんですよね(笑)。だから、逆引用符とかコンマの「機能」はあるんですが、その「使い道」であるマクロ記述方法が「これだ!!!」って形で決められなかった経緯があるわけです。「危険極まりない」とか言う議論があって。
そんなわけで、こんな形でしか「使い道が無い」ってのも事実ですね。

>最初ワタクシ、この定義は単なる定義ファイルなんだと思ってました。
>まさか、実装だとは。(^^;

いや、僕だってCとかC++の部分は分かんないですし(笑)。
まあ、お互いある意味「得意範囲がある」って事だけでしょうね(笑)。

投稿: cametan | 2009年9月28日 (月) 23時44分

ん〜、言語を書ける言語としての、schemeやらlispとすれば、マクロの用途も見える気がしますけど。
どっちかってぇと、そういうのが得意そうな言語ですね。
#見た目の雰囲気だけで物言ってますけど。(笑)

いやぁ、CとかC++ってのは、もう少し、構文っぽいじゃないですか。(笑)
ホントに、単純に定義が並んでるだと思いましたよ。
こんな、凝った定義で、文字解析するんだなぁ、なんて思いましたから。
まあ、実際には実装なんで、あながち間違いでもなかったのかも知れませんけど。(^^;

投稿: かおりん | 2009年9月29日 (火) 01時09分

>#見た目の雰囲気だけで物言ってますけど。(笑)

いや、当たってますよ(笑)。

「Lisp最強」って言う人がいるのはそれが原因ですよね。それがマクロの存在で、これは他の言語では「存在しない」機能ですから。かつ使うのが凄く難しいです(僕も殆ど分かってません)。

Lispの特徴って、実はあのスタイルって「構文木そのもの」なんだそうです。
僕はプログラミング言語の仕組みって全貌全然知らないんですけど(コンパイラの設計法とか知りませんからね)、概要言うと、例えばC言語なんかの「表層的な構文」の下のレイヤーが剥き出しになってるそうです。
元々、Lispって設計された段階で、あの「括弧だらけの奇怪なスタイル」の上に、Algol型(C言語なんかのルーツ)の構文を重ねる予定だったそうなんですが、直接構文木を弄る事を好む人が多くて、今のスタイルに落ち着いたそうです。

んで、マクロって平たく言うと「一つの式を別の式に変換する」機能なんですね。
例えば良く出る例だと、Schemeなんかでは繰り返しは

> (do ((i 0 (+ i 1)))
   ((= i 10) (newline))
  (display i)
  (display #\Space))
0 1 2 3 4 5 6 7 8 9
>

と記述して、Lisp慣れしてないと(あるいはしてても)凄く見づらいんですよね。これが困る、と。
んで、これを嫌って「もっと普通のfor文っぽいのが欲しい」とか思ったら自分でfor式を作れるわけですよ。
これがかなり突飛だ、ってのは例えばCの「繰り返し文が嫌い」だからと言って、繰り返し構文を新たに設計してC言語に組み入れる事が出来ない、ってのを考えれば分かると思います。
(全く別の言語を「C言語でプログラミングする」って事は出来ますが)
これをやるのが「マクロ」なんです。
例えば、forを定義するにはSchemeでは次のように行います。

(define-syntax for
 (syntax-rules ()
  ((_ (i from to) b1 ...)   ; for~と言う形式を
   (do ((i from (+ i 1)))  ; do~と言う形式に変換
     ((= i to))
    b1 ...))))

そうすると、もうちょっと「見た目が普通の」繰り返し構文が定義出来るわけです。

> (for (i 0 10)
   (display i)
   (display #\Space))
0 1 2 3 4 5 6 7 8 9

Common Lispはちょっと形式が違って、コードの「テンプレート」を設計してマクロを定義するんですが、「式から式に変換する」って基本的なアイディアは同じです。
つまり、こう言う考え方を拡張していくと、例えばコード書いてて、「良くある形式の」関数を複数定義をせねばならない羽目に陥った時、関数定義そのものもマクロで定義出来ちゃうんですよ。
あんま良い抽象化を思いつかないんで書きませんが、例えば「あるプログラム内で良くある頻出のパターン」ってのを抽出してマクロで「関数生成」を指定する、なんて事が出来ます。
そうすると、普通のプログラミングでは、IDEとかで「似通ったパターンをコピペして」プログラムを組み上げる、って形になるでしょうが、Lispの場合は、Lispで「関数を自動で生成する」テンプレートを作る事により、コードの圧縮が可能となるんです。100行「同じような処理」を書かなければならないところをもっと圧縮して記述する事が可能となる模様です。

>実際には実装なんで、あながち間違いでもなかったのかも知れませんけど。(^^;

そうですね。
恐らくLispは「記号処理に優れた」と言う特徴があるんで、それをそのまま活かすには実装そのものを組み入れた方がラクだ、って判断があったのかもしれません。

投稿: cametan | 2009年9月29日 (火) 02時38分

なかなか興味深い話で。
会社で暇だったんで、ちょっとだけScheme調べてたりしました。
というのも、やっぱりuimがイイ感じなんで、カスタマイズが、schemeで記述するもんなら、覚えておいても損はないかな、って感じで。(笑)

で、その後、子音の取りこぼしに関して、もっと突っ込んだ定義しているのを見つけまして。
でも、そのマクロを使ってなくて、結構力技で定義してあるんですよ。
でまあ、これ使えないとIMとしては美味しくないので、調べながら書き直そうかな、と思ってます。
cametanさんの解説で、ある程度イメージは付いてきましたので、あとは、もう少し簡単な文法サンプルを勉強して、挑戦してみようかな、と。
Lispも同様の思想で組めるなら、ここらでいっちょ慣れとくと、今後いいことあるかも知れませんしね。
#emacsとか。

ちなみに、ここにあるやつです。
http://vagus.seesaa.net/article/108510198.html
マクロを使った関数定義に書き直そうかな、と思ってます。
#製作者ご本人も、力技と書かれていますので。
引数を一個取る物と、2個取る物の二つに分かれるんだろうな、と考えてますが。
何かヒントでもあれば。(^^;

投稿: かおりん | 2009年9月29日 (火) 22時26分

>やっぱりuimがイイ感じなんで、カスタマイズが、schemeで記述するもんなら、覚えておいても損はないかな、って感じで。(笑)

一応言っておきますと、かおりんさんってC++の使い手ですよね?確か元々。
恐らく、C++みたいな複雑な言語を駆使してらっしゃるなら、Schemeはたった3日で覚えられる可能性さえあります。僕は苦労してますけど(笑)。
これは冗談じゃなくって、Schemeの、少なくともR5RSって呼ばれるポピュラーな言語仕様書がたった50頁しかないから、なんです。以前書いたかもしれませんが。
ANSI Common Lispの場合、仕様書が1,000頁以上あるんで、全貌把握するのは困難ですが、Schemeの場合、ホント、最短時間で3日だろう、ってのは嘘じゃありません。そう言う意味ではPythonやRubyよりも覚えるのが早い可能性さえある、んです。
Schemeの言語仕様書は次になります。

R5RS:
http://www.unixuser.org/~euske/doc/r5rs-ja/r5rs-ja.pdf

実はこの後、3倍に膨れ上がったR6RSってのがあるんですが(150頁程)、現存のScheme処理系が全部そっちを採用するかどうか分かってません。いまだ揉めてる、って状況です。
ですから、当面R5RSさえ読んでおけば良い、と思います。

Scheme処理系ってこの世で数が多いんですけど(ホントにどの言語、例えばC/C++処理系に比べても数が多い)、これも「仕様書が小さい」んで、フリーソフトウェア作家等が比較的ラクに「プログラミングの力試しがし易い」って事があるんです。

>#製作者ご本人も、力技と書かれていますので。

うん、確かに力技っぽいですよね。
これ後半がアレですよね。
多分、組み合わせだから「パスカルの三角形」作ってリストを操作した方がいいんじゃないかな・・・・・・?
例えば次のような関数を定義します。

(define (combination k data)  ; パスカルの三角形を用いた定義
 (and (positive? k)        ; 最低条件はkが正の整数である事
   ( > (combination 2 '("b" "c" "d"))
(("b" "c") ("b" "d") ("c" "d"))
>

とかこんな感じになるでしょ。
んで、このリストの出力をまた定形パターンになるように別の関数作って「参照渡し」すれば幾分シンプルになるんじゃないか、って思うんですけどね。

投稿: cametan | 2009年9月29日 (火) 23時55分

あ、何かプログラムの定義が飛んでる。おかしいな。

こんな感じですね。ネタ元はパスカルの三角形です。

(define (combination k data)
 (and (positive? k)
   (<= k (length data))
    (cond
     ((= k 1)
      (map (lambda (c) (list c)) data))
     ((= k (length data))
      (list data))
     (else
      (append
       (map
        (lambda (c) (cons (car data) c))
        (combination (- k 1) (cdr data)))
       (combination k (cdr data)))))))

投稿: cametan | 2009年9月29日 (火) 23時59分

おっと、早速のご提示、ありがとうございます。(笑)
ご提供頂いたサンプルと、言語仕様を元に、ちと勉強してみます。

まあ、確かにワタクシ、元々の専門はC言語と、C++です。
最近は、C#とJavaScriptばっかりでけどね。(笑)

投稿: かおりん | 2009年9月30日 (水) 00時22分

う~ん、多分全体的にはこうなるんじゃないか、と。

;; ここから

(require "japanese.scm")

(define *data*
 '("b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
  "B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "P" "Q" "R" "S" "T" "V" "W" "X" "Y" "Z"))

(define (foo data)
 (map (lambda (c)
     `(((,c)) (,c ,c ,c)))
     data))

(define (combination k data)
 (and (positive? k)
    (<= k (length data))
    (cond
     ((= k 1)
      (map (lambda (c) (list c)) data))
     ((= k (length data))
      (list data))
     (else
      (append
       (map
        (lambda (c) (cons (car data) c))
        (combination (- k 1) (cdr data)))
       (combination k (cdr data)))))))

(define (bar data)
 (map (lambda (c)
     (let ((x (car c))
        (y (cadr c)))
      `((,c . ()) ((,x ,x ,x) (,y ,y ,y)))))
     data))

(set! ja-rk-rule
 (append (foo *data*) (bar (combination 2 *data*)) ja-rk-rule))

;;; ここまで

先の例と違って、"b"~"Z"までの「組み合わせ」を全部計算させてますけどね。
それで良いのなら、この形式になるんじゃないか、って思います。

投稿: cametan | 2009年9月30日 (水) 00時29分

すげぇ。回答でちゃった。(^^;
組み合わせ全部入ってないと、落ちる子音があるようで、その辺足さないとならんなぁ、とか思ってたんですけどね。

ま、回答は回答としてありがたく使わせていただくつもりですが。(笑)
自分でも考えて見ますね。

投稿: かおりん | 2009年9月30日 (水) 00時45分

>すげぇ。回答でちゃった。(^^;

いや、早いのはSchemeのお陰です(笑)。テストのサイクルが早いんで、雛形さえ分かってればプログラムを作るのはラクなんですよ。

>組み合わせ全部入ってないと、落ちる子音があるようで、その辺足さないとならんなぁ、とか思ってたんですけどね。

あ、やっぱそうなんですか。
例のコード見てたら、作者の人、途中で辞めちゃったのかなあ、とか思っていました(笑)。

>ま、回答は回答としてありがたく使わせていただくつもりですが。(笑)
>自分でも考えて見ますね。

はい。

一応、書いておくと、最初に*data*として大域変数を設定しておいて、関数を幾つか定義して、最終的にrequireで読まれただろうja-rk-ruleを再定義する方針にしています。
appendは引数をいくつも取れるんで、例えば、

> (append '(a b c) '(d e f) '(g h i))
(a b c d e f g h i)
>

なんて事が可能です。
従って、3つの引数の最初二つの「それぞれ」が、*data*を引数に取った関数の「返り値」を噛まして行って・・・・・・ってのがアイディアですね(最後は元のja-rk-ruleですけど)。特に複雑な事はしてません。
関数fooとbarは殆ど同じです(笑)。面倒なんでこう言う形にしました(笑)。
ええと、barって

(define (bar data)
 (map (lambda (c)
     (let ((x (car c))
        (y (cadr c)))
      `((,c) ((,x ,x ,x) (,y ,y ,y)))))
     data))

でもいいですね。
Lispだと、例えば

(2 . ())

ってのは

(2)

と同じなんで、ドットリスト表記はいらないですね。うん。
設定ファイルもそれで良いのでは、と思います。

ちなみにcarってのはリストの最初を取る関数、

> (car '(1 2 3))
1
>

cadrってのはリストの2番目を取る関数、

> (cadr '(1 2 3))
2
>

cdrってのはリストの最初を削除したリストを返す関数の事です。

> (cdr '(1 2 3))
(2 3)
>

ただし、「削除」とは言っても元データの書き換えは基本的にありません。
原則、その手の操作関数はイミュータブルな操作が前提になっています。
上のコードだと、唯一の例外はset!で、これは「代入」しています。Schemeでは代入は元データを書き換えるので「破壊的操作」って呼ばれてるんですが、その手の関数にはエクスクラメーション(!)が付く、って慣習になっています。
リスト自体がCのアルゴリズムで出る「連結リスト」が元になってるようで、大体のリスト操作はCで言うポインタ操作になっています。

投稿: cametan | 2009年9月30日 (水) 01時08分

参考資料です。

「Lisp脳」の謎に迫る - Schemeプログラマの発想:
http://karetta.jp/book-node/gauche-hacks/023107

世界のナベアツにGauche(Scheme)で挑戦する:
http://d.hatena.ne.jp/yshigeru/20080418/1208523696

投稿: cametan | 2009年9月30日 (水) 17時13分

あ、ついでにこんなビデオもありました。

Shibuya.lispテクニカルトーク#1 LT1 世界のナベアツにGaucheで挑戦する:
http://www.nicovideo.jp/watch/sm5046245

この作者の人、使用OSがUbuntuですね(笑)。
良かった、繋がった(笑)。

投稿: cametan | 2009年9月30日 (水) 19時43分

いろいろとご紹介頂いているので、なるべく今週末にでもまとまった時間が取れればいいなぁ、と。(笑)
ま、なかなかね。
んでも、uimの件は、マジメに弄くってみようと思います。
#ま、時間は作るもんだしね。

投稿: かおりん | 2009年10月 1日 (木) 00時33分

え〜、追っかけてみました。(笑)

で、結果として、問題点があり、それがどこかは解ったんですが、直し方が解りません。(爆)

関数combinationがdataリストの再帰呼び出しを行い、関数barで処理する2次元リストを作成しているところまで解りました。
で、combinationがたすき掛けをするために、一文字づつリストを減らして、2次元リストを作成しているのですが、期待されているのは、「同じ文字だけは対象外」とする2次元リストなので、再帰呼び出しで、どんどん引数から最初の文字を削除してしまうと、期待した最終的な2次元のリストが出来上がらないことになります。

例えば、( b c d )のリストがある場合に、現在の実装だと以下のリストが返ります。

((b c) ((b b b)(c c c)))
((b d) ((b b b)(d d d)))
((c d) ((c c c)(d d d)))

実際に期待されているのは、自分自身以外を除いたリストなので以下の用になります。
((b c) ((b b b)(c c c)))
((b d) ((b b b)(d d d)))
((c b) ((c c c)(b b b)))
((c d) ((c c c)(d d d)))
((d b) ((d d d)(b b b)))
((d c) ((d d d)(c c c)))

当たりは付いたのですが、直し方が解りませんでした。orz
たぶん、処理中の文字kと、引数に渡されたリストを処理している部分で、ピンポイントでkを削除してあげればいいんじゃないかと思うんですが…。

すんません、教えてください。(^^;>cametanさん

投稿: かおりん | 2009年10月 3日 (土) 16時52分

違った。kってリストそのものだ。
だとすると、直さら解りません。orz

投稿: かおりん | 2009年10月 3日 (土) 16時53分

ちょっと見てみますね。

投稿: cametan | 2009年10月 3日 (土) 19時00分

あ、ちなみにkは「リストそのもの」じゃなくって得られるリストの「要素数」です。

つまり、combination(2 '(b c d))ってのは「(b c d)と言うリストから要素を2つ選んだ組み合わせを全て返せ」って事ですね。
combination(3 '(b c d))は「(b c d)と言うリストから要素を3つ選んだ組み合わせを全て返せ」って事です。->結果((b c d))と一個返る。
数学に従って汎用的に書きました。

投稿: cametan | 2009年10月 3日 (土) 19時06分

うん?これって……。
要するに、今までのコードで

((b c) ((b b b)(c c c)))
((b d) ((b b b)(d d d)))
((c d) ((c c c)(d d d)))

が得られるトコに、追加でこれらの逆順

((c b) ((c c c)(b b b)))
((d b) ((d d d)(b b b)))
((d c) ((d d d)(c c c)))

が追加されればいいだけ、なんですか?
だったら関数を一個追加してappendしてやるだけで終了だと思います。

;;; ここから

(require "japanese.scm")

(define *data*
 '("b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
  "B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "P" "Q" "R" "S" "T" "V" "W" "X" "Y" "Z"))

(define (foo data)
 (map (lambda (c)
    `(((,c)) (,c ,c ,c)))
   data))

(define (combination k data)
 (and (positive? k)
   (<= k (length data))
    (cond
     ((= k 1)
      (map (lambda (c) (list c)) data))
     ((= k (length data))
      (list data))
     (else
      (let ((x (car data))
         (y (cdr data)))
       (let ((z (combination (- k 1) y))
          (w (combination k y)))
        (append (map (lambda (c) (cons x c)) z) w)))))))

(define (bar data)
 (map (lambda (c)
     (let ((x (car c))
        (y (cadr c)))
       `((,c) ((,x ,x ,x) (,y ,y ,y)))))
    data))

(define (baz data)       ; 新しく関数bazを追加
 (map (lambda (c)
     (let ((x (car c))
        (y (cadr c))
        (z (reverse c))) ; 引数リストcを逆順にする
       `((,z) ((,y ,y ,y) (,x ,x ,x))))) ; zを利用し、barと逆パターンでリストを捏造
   data))

(set! ja-rk-rule
 (append (foo *data*)
      (bar (combination 2 *data*))
      (baz (combination 2 *data*)) ; ここを追加
      ja-rk-rule))

;;; ここまで

これで要求を満たしますか?確かめてください。

投稿: cametan | 2009年10月 3日 (土) 19時27分

プログラム的に正しい(期待する)リストが得られることは確認しました。

ありがとうございました。
逆順で処理すれば、期待する結果になるって発想がなかったです。orz

確認は、
http://codepad.org/
で、scheme選択して実行して結果を得ました。
結構便利ですね、こういうサイト。


投稿: かおりん | 2009年10月 3日 (土) 22時37分

>逆順で処理すれば、期待する結果になるって発想がなかったです。

多分、その辺が「代入を多用する」手続き型言語の人の考え方と、「全ての関数はフィルタとして働き、元データを直接弄らない」関数型言語の人の考え方の差、なんですよね。ちょっとパラダイムが違う、と言うか。
恐らく、データ操作をしよう、って時点で「データの書き換え」が発生するんじゃないか、って感覚的に感じたんじゃないか、と予想します。だから「逆順にしちゃえ」とか思えなかったのでは、と。

僕は全然オブジェクト指向とか分かんないんですけど、やっぱりネックはこの辺なんですよね。「データ構造の雛形」はコピーするんですが(継承)、ここに新しくデータを追加したり、あるいは操作する、って時、基本、考え方は「手続き型」の「代入」(破壊的操作)でしょ?んで、「あれれれれ?」って思う事ばっかです。だからオブジェクト指向、ってどうにも慣れない。
単にパラダイムが違うんですよね。ある意味「土台としている世界観が違う」と言うか。

まだ、上はコード的には冗長な部分があるかもしれませんが、ある程度「追加するデータが確定した」って辺りで大幅に短く書き換えても良いんじゃないのかな、って思います。

>結構便利ですね、こういうサイト。

ああ、便利ですよね(笑)。
そこのSchemeの中身はPLTのMzSchemeらしいんですけど。

PLT Scheme:
http://www.plt-scheme.org/

投稿: cametan | 2009年10月 3日 (土) 23時02分

>多分、その辺が「代入を多用する」手続き型言語の人の考え方と、「全ての関数はフィルタとして働き、元データを直接弄らない」関数型言語の人の考え方の差、なんですよね。ちょっとパラダイムが違う、と言うか。

たぶん、個人のレベルの問題じゃないですかね。(^^;
単にワタクシのレベルでの発想ではなかった、という話で。
手続き型言語を使ってる人でも、発想は可能だったんじゃないかと思います。
なので、ワタクシのレベルの低さが露呈しただけ、ってことで。(笑)

>まだ、上はコード的には冗長な部分があるかもしれませんが、ある程度「追加するデータが確定した」って辺りで大幅に短く書き換えても良いんじゃないのかな、って思います。

scheme使いではないので、細かく言及は出来ないんですが、ロジックとしては十分効率がよいと思うんですけどね。
リスト生成に再帰呼び出しになってるし。
あとは、元のdataの定義の工夫とその処理だけじゃないかな、と思うんですが。
あんまし冗長部分はないような気もしますが。
#関数の定義その物が複数あるのが冗長ということならば、これは言語間の認識の相違な気がします。
C系でも、あんな感じになるか、無理に関数減らすとIF文の嵐になりそうな。

投稿: かおりん | 2009年10月 4日 (日) 00時44分

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/500703/46328981

この記事へのトラックバック一覧です: イマサラながらuimを使ってみる。:

« ext4にしてみた。 | トップページ | ぼちぼちβ版ですな。 »