Land of Lisp 本、Kindle 版 Steve Jobs、Parallels Desktop 上の Ubuntu 11.10 に PC-G850VS 用 G850ターミナルでリモートログイン。

iOS 5 のダウンロード、iPhone 4S の発売、iCloud の開始時に、 2011年11月5日 Steve Jobs 氏が亡くなったことが発表されました。56歳でした。

ご冥福をお祈りします。

前回、Learning GNU Emacs を読んだ感想を書きましたが、もう少し Lisp について学びたくなりました。そんな中、Lisp 創案者の John McCarthy 氏の訃報を知り、驚きました。

以前、Practical Common Lisp (Books for Professionals by Professionals) の読破に挫折していたので、何か易しい良書がないか探していました。日本語の Lisp 本は、だいたい持っているので、洋書を選ぶことにしました。折角、iPad を所持しているので、Kindle 版の電子書籍にしました。

それで Land of LISP: Learn to Program in Lisp, One Game at a Time! を購入してみしました。魅かれた点は、実際にプログラムを組みながらゲームを作成するところです。

Lisp の実行環境は、Cocoa Eamcs 上の SLIME と sbcl を使用しました。

SLIME: The Superior Lisp Interaction Mode for Emacs
http://common-lisp.net/project/slime/

sbcl のインストールには homebrew を用いました。

Homebrew ― MacPorts driving you to drink? Try Homebrew!
http://mxcl.github.com/homebrew/

まだ、読み始めたばかりです。Lisp の基本的な部分の理解が深まりました。

Lisp の表記には、Code Mode と Data Mode の2つあります。

P36
Location 1247
> (+ 1 2)
3
> (expt 2 3)
8
> 2
2

Code Mode は、実際に式が評価されます。上の例では (+ 1 2)、(expt 2 3)、 2 がそれぞれ Code Mode として評価されます。

> '(+ 1 2)
(+ 1 2)
> '(expt 2 3)
(EXPT 2 3)
> '2
2
> '(one two three)
(ONE TWO THREE)
> 'one
ONE
> '(1 2 3)
(1 2 3)

式の先頭に ‘ を追加すると Data Mode になります。これまで理解できなかった部分が明解になりました。

nil、()、'()、’nil の扱いについても、はっきりしました。

P51
The Four Disguise of ()
> (eq '() nil)
T
> (eq '() ())
T
> (eq '() 'nil)
T 

また、ドット対記法も理解できました。

> '(1 2 3)
(1 2 3)
> (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
> '(1 . (2 . (3 . nil)))
(1 2 3)
> (cos 1 (cons 2 3))
(1 2 . 3)
> '(1 . (2 . 3))
(1 2 . 3)

リスト (1 2 3 ) は、最後が nil で終わるリスト。(1 2 . 3) は、最後が 3 で終わるリスト。

リストを図にすると上のようになります。図で表すと理解しやすいと思います。

Land of LISP: Learn to Program in Lisp, One Game at a Time! を読んでいる途中、Amazon.comKindleスティーブ・ジョブス氏の伝記が発売開始になりました。即購入しました。値段は $18.09 です。日本語版のように上下2冊にわけられるのではなく、1冊のようです。Apple 関連の本は、いろいろ読んでいるので、おおまかな内容がわかっています。そのため、英語ですが、割と読みやすいです。特に NeXT 関係の箇所を楽しみにしています。まだまだ先ですが、すごいページ数です。(汗)

また、Ubuntu 11.10 (日本語 Remix CD) を 仮想化ソフト Parallels Desktop 7 for Mac にインストールしたついでに、以前から試したかった PC-G850VS と Linux をシリアル接続し、Ubuntu 11.10 ( Linux ) にリモート・ログインできるターミナル (端末)

PC-G850/G815/E200用ソフトウェア
G850ターミナル
http://www16.ocn.ne.jp/~ver0/g800/index.html#g850term
http://ver0.sakura.ne.jp/g800/index.html#g850term

G850ターミナルを試してみました。

Parallels Desktop 7 上の Ubuntu 11.10 にリモートログインし、w3m、vi などの動作にも成功しました。次回紹介したいと思います。それにしてもすごいプログラムですね!

Ubuntu 11.10 login

w3m

ls

GNU Emacs、Emacs Lisp 版 Minesweeper、Cocoa Emacs 日本語表示

最初に Emacs に触れたのは学生時代購入した X68000 上の Micro Emacs です。もしかしたら Sun のワークステーションの方が早かったかもしれません。インターネットもない時代だったので、本屋で立ち読みしたり、少ない小遣いで購入した書籍で、一生懸命操作を学びました。それ以来、あまり上達していません。X68000 の Micro Emacs では、便利な機能があらかじめ設定されていたので、ファンクションキーを多用していたのを覚えています。

今回、Learning GNU Emacs, Third Edition を読み終えたので、久しぶりに Parallels DesktopWindows XPX68000 エミュレータ XM6 を起動して Micro Emacs (em.x) を実行してみました。

もちろん廉価版なので、本家と違うところがいろいろあるのですが、今思うとすごく良くできていますね。ソースは覗いていませんが、OS に依存しているところは分離されているのかな?

Learning GNU Emacs, Third Edition を読んでる途中で

縦分割や

Window と Frame の違いも理解しました。恥ずかしながら、初めて知りましたが Meta Key として Alt (Option) キーも使えるんですね。Micro Emacs から使い始めたので、てっきり ESC キーだけかと思ってました。

Learning GNU Emacs, Third Edition を読みながら、ATOK Pad にメモした箇所がたくさんあります。ちょっとだけ、紹介しておきます。

GNU Emacs には、強力なヘルプがあります。

Help
C-h ?                   ヘルプ一覧
C-h a PATTERN    正規表現 PATTERN に一致する名前を持つコマンド一覧表示
C-h d PATTERN    PATTERN にマッチする関数、変数などを表示
C-h k

Window 操作も C-x と数字を入力するだけで、いろいろな動作をします。

Window
C-x 0       ウィンドウの削除
C-x 1       選択されているウィンドウ以外のウィンドウをすべて閉じる
C-x 2       ウィンドウを上下2つに分割する
C-x 3       ウィンドウを左右2つに分割する
C-x 4 f     他のウィンドウでファイルを開く
C-x 5 2    フレームの作成
C-x 5 o    他のフレームに移動

ディレクトリエディタ dired で、g キーを押せば、ディレクトリの内容を最新の状態に更新します。

dired
C-x d      dired 起動
u             フラグを外す (Remove mark)
d             削除フラグを付ける (Flag of delection)
x             削除フラグがついたファイルを削除 (Delete)       
g             ディレクトリ再読み込み (Immediate Refresh)
=            比較
C            指定したファイルをコピー (copy)
R            ファイル名変更 (Rename file)
v             View モードで表示 (View file, read-only)
s             ファイル名または日付でソート。トグル。
Enter      スクロール (Scroll down)
#            auto-save files にフラグを付ける
~            Backup files にフラグを付ける
* *          excitable files にフラグを付ける
L            ファイルを読み込む (Load file)
%m         正規表現に当てはまるファイル名にフラグを付ける

決まったファイルを編集するには Bookmark に登録しておくと便利です。

C-x r m  bookmark-set
C-x r l   List bookmarks

GNU Emacs の Window 上に shell も起動することができます。

M-x shell
M-p            最後のコマンドを表示
M−n           次のコマンドを表示

検索と置換には、正規表現も使えます。

検索
C-s
置換
M-%
SPACE    置換して次に移動
DEL        置換しないで次に移動
,             置換して結果を表示。移動はしない
正規表現検索
C-M-s
C-M-r
C-M-%

キーは割り当てられていませんが、指定した領域をコメントアウトするには

M-x comment-region
M-x uncomment-region

が便利です。C や Ruby など、ほとんどの言語が対応しています。

C-@ でマークし、カーソルキーで選択します。

M-x comment-region を実行すると、上図のように各行を /* */ でコメントアウトしてくれます。

コメントアウトを取り除くには、上図のように同じく領域を選択し、

M-x uncomment-region を実行します。

Learning GNU Emacs, Third Edition で、簡単な Emacs Lisp Programming も学んだので、どんな環境でも最初に挑戦するマインスイーパを作成してみたくなりました。Google で検索してみると

EmacsWiki: Mine Sweeper
http://www.emacswiki.org/emacs/MineSweeper

すでに存在するようです。私の理解の仕方が足りないのか、うまく動作させることができません。それで少し mine-sweeper.el を変更してみることにしました。まず、.emacs ファイルに

;; .========== .emacs ==========
;; load-path
(add-to-list 'load-path "~/lisp/")
;; minesweeper
(autoload 'mine-sweeper "mine-sweeper" nil t)
(autoload 'mine-auto "mine-sweeper-auto" nil t)
(add-hook 'mine-sweeper-mode-hook
(lambda ()
(define-key mine-sweeper-mode-map "a" 'mine-auto)))

を追加しました。ホームフォルダlisp フォルダを作成し、その中に mine-sweeper.el、mine-sweeper-auto.el ファイルをそれぞれ置きました。

mine-sweeper.el ファイルの mine-sweeper 関数から

(get-buffer-create "Mine")
(set-window-buffer (selected-window) "Mine")

をコメントアウトし

 (pop-to-buffer "*Mine*" nil)

を追加しました。mine-sweeper 関数は、下記のようになります。

;;; main
(defun mine-sweeper ()
"mine-sweeper
SPC  open
b    mark
m    mark
q    quit"
(interactive)
(setq max-lisp-eval-depth 3000)  ;for recursive call of open.           
(setq max-specpdl-size 3000)     ;for recursive call of open.
;;  (get-buffer-create "Mine")
;; (set-window-buffer (selected-window) "Mine")
(pop-to-buffer "*Mine*" nil)
(setq overwrite-mode t)
(setq major-mode 'mine-sweeper-mode
mode-name  "Mines")
(use-local-map mine-sweeper-mode-map)
(run-hooks 'mine-sweeper-mode-hook)
(mine-start)
(setq buffer-read-only t))

次に mine-clean-and-quit 関数を

(defun mine-clean-and-quit ()
(interactive)
;;  (switch-to-buffer-other-window "*Mine*")
(delete-window)
(kill-buffer "*Mine*"))

に変更しました。これで M-x mine-sweeper を実行すると、マインスイーパで遊ぶことができます。

最初にミニバッファ上で縦横のサイズ、地雷の数を入力します。( デフォルトの値を使用する場合は、Return キーを押すだけです。)
画面が表示されると

カーソルキー     セルを移動
スペースキー     セルをオープン
m キー              マーク
a キー               自動で解く

上記キー操作で遊ぶことができます。a キーを押すと mine-sweeper-auto.el の mine-auto 関数が呼ばれ、マインスイーパを自動で解いてくれます。人間が解くようにコンピュータが解くので、ある程度セルが開いている必要があるようです。条件によっては解けない場合があります。a キーを使って自動で解いた後にプログラムを終了させるとミニバッファに無意味な文字列が表示されます。私が、mine-sweeper.el を変更したのが原因のようです。

自作の Emacs Lispマインスイーパを作ってみたいですね。

GNU Emacs 上の日本語が綺麗に表示できるように、Google で検索していろいろ試しましたが、中々上手くいきません。結局、

IPAフォントのダウンロード || OSS iPedia
http://ossipedia.ipa.go.jp/ipafont/index.html

IPAフォントを使いました。表示結果は

のようになりました。.emacs ファイルは、下記リンクでダウンロードできるようにしておきました。よかったら使ってください。

GNU Emacs 設定ファイル (.emacs) サンプル:  emacs.zip (4K)
http://kyoshiaki.sakura.ne.jp/osx/Download/emacs.zip

Homebrew をちょこっと解析、Cocoa Emacs インストール。

前回書いたように、パッケージシステムとして MacPorts から Homebrew に変更してみました。

Installation - GitHub
https://github.com/mxcl/homebrew/wiki/installation

Homebrew をインストールするには、上記ページの Installation で表示されているスクリプト

/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

をコピーし、ターミナル上でペーストして実行するだけです。ただし、上記に記載されている通り、事前に Xcode をインストールしておく必要があります。

Safari で直接、https://raw.github.com/gist/323731にアクセスすれば、Homebrew をインストールする Ruby スクリプトを見ることができます。 (curl コマンドでもダウンロードできます。)

curl は、サーバから、あるいはサーバへ、データ伝送を行うツールです。プロトコル HTTP、HTTPSFTP などに対応してます。上のスクリプトの場合、指定した URL [ https://raw.github.com/gist/323731 ] が返す Ruby スクリプトをダウンロードします。各引数は、ターミナルで man curl を使って確認してください。(man curl | col -bfx > curl.txt でファイルに変換して、open curl.txt で中身を確認すると便利です。)

その後、/usr/bin/ruby -e コマンドで Ruby スクリプトを実行します。

スクリプトの内容は、簡単に説明すると

/usr/local/.git ディレクトリの中身が空じゃない時、スクリプトを終了。

/usr/local/
bin/
Cellar/
etc/
include/
lib/
Library/
sbin/
share/
var/
.git/

のそれぞれのディレクトリが存在しない時、/bin/mkdir で新規作成、存在する時は属性を変更。

ディレクトリ /usr/local に移動し、https://github.com/mxcl/homebrew/tarball/master から mxcl-homebrew-xxxxxxxx.tar.gz ファイルをダウンロードして展開する。

これで終了です。

Homebrew のディレクトリのおおざっぱな中身は

/usr/local/
bin/
brew
Cellar/
Library/
Aliases
Contributions
brew_bash_completion.sh
brew_fish_completion.fish
brew_zsh_completion.zsh
examples/
brew-bottle.rb
brew-depstree.rb
brew-dirty.rb
brew-graph
brew-grep
brew-leaves.rb
brew-linkapps.rb
brew-man
brew-missing.rb
brew-pull.rb
brew-readall.rb
brew-server
brew-switch.rb
brew-unpack.rb
brew-upgrade.rb
brew-which.rb
manpages/
Formula/
emacs.rb
wget.rb
.
.
Homebrew/
blacklist.rb
cleaner.rb
compatibility.rb
download_strategy.rb
exceptions.rb
formula.rb
formula_installer.rb
global.rb
hardware.rb
install.rb
keg.rb
keg_fix_install_names.rb
utils.rb
cmd/
---cache.rb
--cellar.rb
--config.rb
--env.rb
--prefix.rb
--repository.rb
audit.rb
cat.rb
cleanup.rb
create.rb
deps.rb
diy.rb
doctor.rb
edit.rb
fetch.rb
help.rb
home.rb
info.rb
install.rb
link.rb
list.rb
log.rb
options.rb
outdated.rb
prune.rb
search.rb
test.rb
uninstall.rb
unlink.rb
update.rb
uses.rb
extend/
ARGV.rb
ENV.rb
pathname.rb
string.rb
test/
share/

です。

また、キャッシュとして

~/Library/Caches/Homebrew 

フォルダが利用されます。Library フォルダは不可視になっていますが、ターミナル上で

~ $ open Library

で開くことができます。

brew コマンドのヘルプは、

man brew
brew help

で確認できます。

ここでは、wget のパッケージをインストールするコマンド

brew install wget

の動作を簡単に説明したいと思います。間違っている個所もあるかもしれません。

実行ファイル /usr/bin/brew は、rubyスクリプトです。

#--- /usr/local/ibin/brew ---
cmd = ARGV.shift # => 'install'
cmd = aliases[cmd] if aliases[cmd] # cmd = :install

cmd に :install が代入され

#--- /usr/local/ibin/brew ---
elsif require? HOMEBREW_REPOSITORY/"Library/Homebrew/cmd"/cmd
Homebrew.send cmd.to_s.gsub('-', '_')

/usr/local/Library/Homebrew/cmd/install.rb が読み込まれ、module Homebrew は /usr/local/Library/Homebrew/cmd/install.rb に宣言されています。

send (Object) - Rubyリファレンス
http://ref.xaio.jp/ruby/classes/object/send

Homebrew.send は Homebrew モジュールの install メソッドを呼ぶことになります。

#--- /usr/local/Library/Homebrew/cmd/install.rb ---
module Homebrew extend self
def install
ARGV.named.each do |name|
msg = blacklisted? name
raise "No available formula for #{name}\n#{msg}" if msg
end unless ARGV.force?
install_formulae ARGV.formulae
end

ARGV は

#--- /usr/local/bin/brew ---
require 'global'

#--- /usr/local/Library/Homebrew/global.rb ---
require 'extend/pathname'
require 'extend/ARGV'
require 'extend/string'
require 'utils'
require 'exceptions'
ARGV.extend(HomebrewArgvExtension)

から /usr/local/Library/Homebrew/extend/ARGV.rb で拡張されています。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---
module Homebrew extend self
def install
ARGV.named.each do |name|
msg = blacklisted? name
raise "No available formula for #{name}\n#{msg}" if msg
end unless ARGV.force?
install_formulae ARGV.formulae
end

/usr/local/Library/Homebrew/blacklist.rb の blacklisted? でインストールできないパッケージを判断。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---
install_formulae ARGV.formulae

ARGV.formulae は Arrray 型で、インストールする Foumla が入っています。今回は Class Wget が1つ入っています。Class Wget は、/usr/local/Library/Formula/wget.rb で宣言されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def install_formulae formulae
formulae = [formulae].flatten.compact
return if formulae.empty?
check_ppc
check_writable_install_location
check_cc
check_macports
formulae.each do |f|
begin
installer = FormulaInstaller.new f
installer.ignore_deps = ARGV.include? '--ignore-dependencies'
installer.go
rescue FormulaAlreadyInstalledError => e
opoo e.message
end
end
end

f は、Formula クラスを継承した Wget クラスが入っています。FormulaInstaller の @f にも格納されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def go
if @f.installed? and not ARGV.force?
raise FormulaAlreadyInstalledError, @f
end
unless ignore_deps
needed_deps = @f.recursive_deps.reject {|d| d.installed?}
unless needed_deps.empty?
puts "Also installing dependencies: "+needed_deps*", "
needed_deps.each do |dep|
FormulaInstaller.install_formula dep
end
end
begin
FormulaInstaller.check_external_deps @f
rescue UnsatisfiedExternalDependencyError => e
onoe e.message
exit! 1
end
end
FormulaInstaller.install_formula @f
end

FormulaInstaller.install_formula @f を呼び出すことになります。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def self.install_formula f
@attempted ||= Set.new
raise FormulaInstallationAlreadyAttemptedError, f if @attempted.include? f
@attempted << f
ENV['HOMEBREW_ERROR_PIPE'] = write.to_i.to_s
fork do
begin
read.close
exec '/usr/bin/nice',
'/usr/bin/ruby',
'-I', Pathname.new(__FILE__).dirname,
'-rinstall',
'--',
f.path,
*ARGV.options_only
rescue Exception => e
Marshal.dump(e, write)
write.close
exit! 1
end
end

fork、nice を使用していますが、簡単に説明すると

/usr/bin/ruby -I /usr/local/Library/Homebrew -rinstall -- /usr/local/Library/Formula/wget.rb

上記コマンド実行します。

上のスクリプトを実行する時に読み込んでいるライブラリ /usr/local/Library/Homebrew/install.rb の下のソースからプログラムが開始されます。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---
at_exit do
begin
raise $! if $! # an exception was already thrown when parsing the formula
require 'extend/ENV'
require 'fileutils'
require 'hardware'
require 'keg'
require 'compatibility'
ENV.extend(HomebrewEnvExtension)
ENV.setup_build_environment
puts "-----"
puts $0
install(Formula.factory($0))
rescue Exception => e
if ENV['HOMEBREW_ERROR_PIPE']
pipe = IO.new(ENV['HOMEBREW_ERROR_PIPE'].to_i, 'w')
Marshal.dump(e, pipe)
pipe.close
exit! 1
else
onoe e
puts e.backtrace
exit! 2
end
end
end

install(Formula.factory($0)) が実行している箇所です。$0 は、/usr/local/Library/Formula/wget.rb です。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---
def install f
# ・
# ・
# ・
# ・
else
f.prefix.mkpath
beginning=Time.now
f.install if not f.pourable?
FORMULA_META_FILES.each do |filename|
# ・
# ・
# ・
end

f.install の部分が wget.rb の Class Wget で install メソッドを呼び出して実際にインストールしている箇所です。

#--- /usr/local/iLibrary/Formula/wget.rb ---
def install
args = ["--disable-debug",
"--disable-dependency-tracking",
"--with-ssl=openssl",
"--prefix=#{prefix}"]
args << "--disable-iri" unless ARGV.include? "--enable-iri"
system "./configure", *args
system "make install"
end

これが、brew を使って wget をインストールするおおまかな流れです。

Cocoa Emacs も Homebrew を使ってインストールしてみました。Cocoa Emacs の Formula は、あらかじめインストールされているものより

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1109223

で公開されているものから、Forks されている最新版 Formula (emacs.rb : 入手先、インストール方法などが記載されています。)

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1128997

を利用しました。

Formula の URL は、ソースの右上 ‘raw’ 文字をクリックして確認できます。また、Option で –use-git-head を使わない場合、あらかじめ bazaar をインストールしておく必要があります。(残念ながら、git を使って最新版をダウンロードすると patch をあてることができませんでした。)

~ $ brew install bazaar
~ $ brew install https://raw.github.com/gist/1128997/347bb0d97155a294d9c50b6418c9130fadec8a5b/emacs.rb --cocoa --lion
~ $ cp -pR /usr/local/Cellar/emacs/23.3a/Emacs.app /Applications

日本語入力にも対応しています。command + space で日本語入に力切り替えることができます。.emacs ファイルに

;;------- .emacs -------
;; shell
(global-set-key [f5] 'shell)
;; IM
(setq default-input-method "MacOSX")

IM を追加してください。ついでに F5 キーでシェルを起動するようにしてみました。

Emacs を学び直してみようと思い、iTunes App Store

Learning GNU Emacs, Third Edition
カテゴリ/ブック
\600
http://itunes.apple.com/jp/app/learning-gnu-emacs-third-edition/id333188827?mt=8

を購入しました。

404 Blog Not Found:perl - O'ReillyのiPhoneアプリ本からepubをぶっこぬく
http://blog.livedoor.jp/dankogai/archives/51484907.html

上記スクリプトを使って epub に変換し、iPad で読んでいます。たった 600 円でオライリー本を入手できるので、iPad を所有している人には、ぜひお勧めです。