すなぶろ

Pythonistaを目指しているつもりが、Hyのおかげで無事脱線。Clojurian目指すことになりました。

Clojure 入門者による【チャットボットづくり】 Part5

大幅に更新が遅れてしまいました。実は腰痛で入院していまして、無事手術を終えて先日退院してきたところです。

入院中あまりにも暇なのでずっと Programming Clojure (第三版)を読んでいたんですが、 Clojure の奥義をそんな簡単に伝えていいの? と思うくらい濃い内容です。

ネット上の(日本語の)情報が少ない、あるいは古いのが難点だと言われがちな Clojure ですが、そもそも何かを勉強したいと思ったら、どんな言語であれ本を読んだほうがいいと痛感しました。例えば mapfilter, reduce は他の言語でも実装されていることが多いですが、Clojure の場合は戻り値を遅延させたり、即時適用してパフォーマンスを上げたりと、使い方が複数あります。その根底にあるのはいわゆる「Clojure らしさ」とでも言うべきもので、全体を通じて設計思想を学べる本は一度目を通しておいたほうが良さそうです。

ちなみに Programming Clojure の第三版は英語ですが、いまは自動翻訳がそれなりに賢いので、技術用語がわかれば苦労せず読めるはずです。第二版は通称「孔雀本」と呼ばれる日本語訳がありますが、Clojure 1.3 ベースであるため、最近追加された機能には言及していないという弱点があります。とはいえそれほど激しく仕様が変わる言語ではないため、第二版の内容がまったく通用しないということはないと思います。

さて、かくいう私はまだ半分も読んでいませんが、ひとつ言えることがあります。 Clojure 初心者はここに書いてある内容とコードを信用してはいけない、と。 本を読んだ結果、とてもお手本になるようなコードではないということが判明してしまったため、「オブジェクト指向から来た人間が関数型をなんとなくで書くとこうなる」というケーススタディとして、ニヤつきながら眺めることをおすすめします。

というわけで、今回は正規表現形態素解析を使って PatternResponder を実装……する予定でしたが、長くなってしまったので先んじて 形態素解析 を実装します。

続きを読む

Clojure 入門者による【チャットボットづくり】 Part4

前回は respond :random を実装しました。辞書も Map にしようというところまでは決めましたが、それをどう使っていくかに関しては説明していません。

ということで今回は『ランダム辞書の学習』『辞書ファイルの読み書き』をコーディングしていきます。同時にコード量も増えていくことが予想されるので、『ソースファイルの分割』についても。

目次

続きを読む

Clojure 入門者による【チャットボットづくり】 Part3

大切なことを言い忘れていました。このチャットボットの元ネタは、Ruby 向けの書籍『恋するプログラム』で紹介されていた unmo という名前のチャットボットです。今ではあまり聞きませんが、一昔前にチャット専門の AI がちょっとしたブームになった頃、そのトンチンカンな返事を揶揄して『人工知能』ならぬ『人工無能』と呼ばれていました。この MunoアナグラムUnmo となり、雲母(うんも・きらら)という宝石の名前にかかっています。

2005 年に刊行された古い本ですが、思考エンジンをひとつひとつ追加して完成に近づけていく感覚が楽しく、新しい言語を学ぶときはいつもこれを実装することにしています。著者の方が急逝されたのが残念でなりませんが、現在は電子書籍として復刊されているので、この記事でチャットボットに興味を持った方はぜひ手にとってみてください。

というわけで今回は『辞書』および『ランダムレスポンス』を実装していきます。

続きを読む

Clojure 入門者による【チャットボットづくり】 Part2

Coders At Work (原著: Peter Seibel, 翻訳: 青木靖)という本があります。第一線級のハッカー達に「エディタは何を使ってます?」「デバッグはどうしてます?」といった基礎的な質問から、「プログラマ全員が読むべき本はありますか?」といった抽象的な質問まで、Peter Seibelががっつり食いついてインタビューしている濃い本なのですが、Erlang の開発者であるジョー・アームストロングがこんなことを言っていました。

ーー  コードを書く前に多くの時間を考えて過ごすということですが、そのときには実際どんなことをするんですか?
アームストロング  ああ、メモを書きます。ただ考えているわけではありません。紙にいろいろ落書きします。(中略)もう1つ重要なことは、同僚に「君だったらこれをどう解く?」と尋ねることです。同僚のところに行って、「こうやればいいのか、ああやればいいのか迷っている。AかBか選ばなきゃいけない」と言い、そのAとBについて説明している途中で、「ああ、Bだね。ありがとう。助かったよ」というようなことがよくあります。

これを読んで不思議な気持ちになりました。私も質問の前の説明段階で自己解決してしまうことはよくありますし、他の人が勝手に納得して席に戻っていくのも見たことがあります。「あるあるネタ」ではありますが、そういうことはプログラマーとして力をつけていくと、すっかり無くなることだと思っていたのです。世界レベルの言語とフレームワークを作り上げる人にも、私と同じように脳みそが入っているらしいということが、妙にリアルに感じられました。

ーー  あるコンピュータサイエンス学科では教官の部屋にぬいぐるみがあって、教官を患わせる前にそのぬいぐるみに向かって自分の問題を説明しなければならないという決まりになっているそうです。「あの、クマさん、私が取り組んでいるのはこういうことで、このようなアプローチをしているんですが、……そうか! 分かりました」
アームストロング  本当ですか? 私もやってみるべきですね。

ーー  あなたのあの猫に話されるといいですよ。
アームストロング  猫にね。いやまったく! 私より若干年上で非常に頭のいい人と一緒に仕事をしているのですが、私が彼の部屋に行って質問をすると、どの質問に対しても彼は、「プログラムはブラックボックスだ。入力と出力がある。そして入力と出力の間には関数的な関係がある。君の問題の入力は何? 出力は? その2つの間の関数的な関係は?」と聞くのです。そして会話の途中のいずれかの時点で、私は「ああ、君って天才だよ!」と言って部屋を飛び出すことになるのですが、彼のほうは驚いて頭を振りながら、「いったい問題は何だったんだろう。あいつちゃんと説明したためしがない」とつぶやくのです。だから彼は問題を説明して聞かせるクマと一緒ですね。

前回は記事本文を書きながら「コードをリファクタリングせねばならぬ……!」という謎の使命感に燃えておりました。文章化するからにはせめて自分で納得行くコードを載せたいという虚栄心がそうさせたのですが、動機がどうであれエディタの操作を覚えたり、イディオムを検索したのは事実。

そう考えると、私にとってのクマのぬいぐるみはこのブログであり、読者ということになります。Rich Hickey 効果で図らずも別ベクトルの注目を集めた気がする前回のことは忘れて、今回も「なんでこういう仕様にしたんだっけ」と自問自答しながら、ちまちまコードを載せていきます。

Coders at Work プログラミングの技をめぐる探求

Coders at Work プログラミングの技をめぐる探求

続きを読む

Clojure 入門者による【チャットボットづくり】 Part1

最近 Clojure にハマっています。JVM 上で動くバイトコードコンパイル可能な Lisp 族で、 なんか書いてて楽しい です。とりあえず作者である Rich Hickey のアツい一言をご覧ください(参考1参考2)。

コンパイラ相手に「型が合っています」と言わせて満足するのがプログラマーなのか? 違うだろ? あくまでもユーザーの要望に応えるのが仕事じゃないか。『ユーザーが意図・期待するものを作り出す』のが本質なわけで、少なくとも俺は顧客に「型チェックが通りませんよ」なんて言われたことはない。


静的型システムそのものは面白いと思うよ。ただ単純に俺から見ると「それはプログラミングそのものではないよね」ってこと。(バートランド・ラッセルの言い分は)要するに「コンピュータ科学分野において数学の地位が向上している」という発言であって、それ以外の何物でもない。仮にペースメーカーの内蔵ソフトウェアが型安全だからといって、ペースメーカーそのものが安全とは限らないだろ? 数学という分野から逸脱してしまうから安全だと断言できない。それが、静的型システムはプログラミングではないと思う根拠だ。


コンパイルが通ったからたぶん動く」という言葉は真実だ。C++でも Haskell でも。ただしそれは「満足の行くプログラムが書けた」とイコールにはならない。解くべきは型パズルではなく、現実問題なのだから。


そもそも Maybe 型ってなんだよ。社会保障番号を表現するのは String であって、Maybe String であるわけがないだろ。したがって、Maybe なんて一銭の得にもならない。これ系のことをさんざん考えさせられた結果、俺は「静的型システムはアンチパターンである」という結論に至った。

もうね…… まるでテロリストですよ。 静的型付け言語(というか主に Haskell)に真っ向から喧嘩を売るなんて私には恐ろしくてとてもできませんが、こういう人だからこそ Clojure は魅力的な言語になっているのかもしれません。一応宣言しておくと、私は Maybe 型を初めて見たとき「見事な解法だなぁ」と思ったクチです。でも Rich Hickey の言うことにも一理あると思います。言語開発者って、すごい。

というわけで、そんな Clojure を使って以前 Python で書いたチャットボット sandmark/unmo を再実装してみました。 勉強用なので間違った説明がある危険があります。ツッコミ歓迎です。 完全なソースコードsandmark/unmo-clojure にあります。

続きを読む

Hy の macroexpand が S 式じゃない→直した

Python へ直接コンパイルできる Lisp 方言 Hy が楽しいです。 しかし Lisp 族のつもりでいると思わぬ落とし穴があったり( let, cons がないなど)するので、 とりあえず macroexpand の結果を S 式にしてみます。

例えば let をマクロで定義してみましょう。 let の正体は lambda というか関数なので、 無名関数を使って実装します。

(defmacro let [values &rest body]
  (setv var-names (list (map first  values))
        var-vals  (list (map second values)))
  `((fn [~@var-names] ~@body) ~@var-vals))

デフォルトの macroexpand-1 の挙動はこんな感じ。

=> (macroexpand-1 '(let ((var 1)) (print var)))
HyExpression([
  HyExpression([
    HySymbol('fn'),
    HyList([
      HySymbol('var')]),
    HyExpression([
      HySymbol('print'),
      HySymbol('var')])]),
  HyInteger(1)])

待って読めない。

もうちょっと Lisper 向けの表現(= S-expression)に近づけてほしいので、 hy コマンドを起動するときに引数をつけてあげます。

  • hy --repl-output-fn=hy.contrib.hy-repr.hy-repr

これで macroexpand してみると、今度はこんな感じに。

=> (macroexpand-1 '(let ((var 1)) (print var)))
'((fn [var] (print var)) 1)

なぜか一行で表示されましたが、それでもこちらのほうが何倍も読みやすいです。

私は Emacs 使いなので hy-mode 経由で hy シェルを起動しているんですが、その場合は hy-shell-interpreter-args (デフォルト "--spy" )を変更すればよい感じです。

(add-hook 'hy-mode-hook
          (lambda ()
            (setq hy-shell-interpreter-args
                  (concat "--repl-output-fn=hy.contrib.hy-repr.hy-repr "
                          hy-shell-interpreter-args))))

Hy がもっと繁栄しますように。

Spacemacs + Python で快適コーディング環境を整える

最近spacemacsにハマってます。「Spacemacs とはなんぞや」についてはいろんな方々が 解説してくださっているので、その魅力についてはぜひそちらをご参照ください。 かくいう私もそういった記事を読んで手を出し、そのまま戻れなくなった身です。

今回は Python のコーディング環境を整えてみます。条件は以下。

  • Python 3.6.6
  • Spacemacs (develop branch)
  • virtualenvwrapper を使用している
  • pyenv を使用している (optional)

Spacemacs + Python + LiveCoding + IPython

Spacemacs では .py という拡張子のファイルを開くだけで Python コーディング用の様々なパッケージが自動インストールされる1のですが、 pip で特定のパッケージをインストールするとさらにパワフルになります。 しかも自動で。

サポートされている機能はこんな感じです。参考: spacemacs/Python layer

  • コードの自動補完
  • ドキュメント検索
  • テスト実行
  • virtualenv のサポート
  • PEP8 互換のコードチェック・自動整形
  • 不要な import 文のハイライト
  • import 文をアルファベット順で自動ソート
  • ライブコーディング
  • REPL
  • Python で書かれた Lisp 方言 hy との互換性
続きを読む