ラベル Common Lisp の投稿を表示しています。 すべての投稿を表示
ラベル Common Lisp の投稿を表示しています。 すべての投稿を表示

2012-06-28

if (条件A || 条件B) の条件文が長くなったら、どこでコードを折り返すか?

先日、Twitter でタイトルの様な質問に出会った。この問いに簡単に答えたのだけど、140 字では全てを伝えきれないので、改めてブログのエントリーにする。

前置き

短い if 文をこう書くとする。

if (条件A || 条件B) 省略

if 文の中が長くなった時、読みづらい。

if (とっても長〜〜〜い条件A || とっても長〜〜〜い条件B) 省略

この時、どう書くのが良いか? 一例としてこんなのがある。

if (
    とっても長〜〜〜い条件A ||
    とっても長〜〜〜い条件B
) 省略

|| を条件式の後ろに置く書き方。

私見

ぼくは || を条件式の前に置く書き方を好む。

if (
    とっても長〜〜〜い条件A
    || とっても長〜〜〜い条件B
) 省略

インデントが少し崩れる。これはデメリットとして認める。

それよりも、「OR」である事が行頭を見るだけで分かるメリットを強調したい。「前置き」に例示した行末に置くやり方だと、行末まで目を動かさないと、条件式が || で繋がっていることを確認できない。

ぼくらは最初から if (条件A || 条件B) というコードを見ているので「OR」だと分かっているけれども、実際にコードを読む時はそれが「OR」なのか「AND」なのか分かっていない。行頭に置けば、初めて読むコードでも一目瞭然になる。

if (
    とっても長〜〜〜い条件A
    || とっても長〜〜〜い条件B
    || とっても長〜〜〜い条件C
    || とっても長〜〜〜い条件D
    || とっても長〜〜〜い条件E
) 省略

条件文が複雑になった時も、読みやすい。理解しやすい。

if (
    (
      とっても長〜〜〜い条件A
      || とっても長〜〜〜い条件B
    )
    &&
    (
      とっても長〜〜〜い条件C
      || とっても長〜〜〜い条件D
      || とっても長〜〜〜い条件E
    )
) 省略

分かりやすい、ということはバグが減るということ。コーディング一つ取っても、少し気を配るだけでバグを減らせる。

あとがき

本来、こういった長い条件文は、別関数にするのが定石。

ただ、プロファイルを見たらループの中の if 文の条件文がネックになってて、関数呼び出ししないコードにすることでプログラムの致命的な遅さが解決する... なんて泥臭いケースがある。マクロ (Lisp など) やインライン関数 (C99, C++ など) が使える言語なら幸せだけど、そういう言語を使っていない場合もある。

そういう場合に備えて、一つ頭の隅に入れておいてもらえれば。

なお、これはあくまでぼくのやり方にすぎない。他に良い方法があれば、是非、ブログの記事にして欲しい。

2010-05-13

実用 Common Lisp を買ってしまった

「実用 Common Lisp」が昨日届いた。原著は「Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp」。作者は Peter Norvig。初版は 1992 年に発売されたという。今、2010 年だから、18 年も前。プログラミングの本では古典の部類に入るかもしれない。推薦の言葉は、あの竹内郁雄氏。

Common Lisp という題名だけ見て注文した。

届いた箱のサイズに驚いた。大きい。こんな大きな包装必要なの? 箱を空けて納得。893 ページの大著だった。値段が 9,200 円 (税抜) もするから変だとは思っていたんだ...

目次はこんな感じ

  1. Common Lisp 入門
  2. 初期の AI プログラム
  3. ツールと技法
  4. 高度な AI プログラム
  5. LISP の続き

この本の凄いとされるところを竹内氏の推薦の言葉から引用する。

Common Lisp の解説書の枠を完全に飛び出している。入門書としてはちょっと敷居が高いかもしれないが、経験を積んだプログラマだったら最初の部分がちょうどいいレベルの導入になっており、そこから先一気に、多くのプログラマには未体験の領域のプログラミングの世界へ踏み込ませる。

第一部の「Common Lisp 入門」が既に「入門書としてはちょっと敷居が高い」というのは恐れ入る。

サブタイトルには AI のケーススタディと謳われているが、実音は一般の問題解決の手段としての (問題記述からデバッグまでをカバーする) 広義のプログラミングの指導書になっている。問題をどう整理し、どう記述すれば、設計とプログラミングが容易になり、プログラムの構造がきれいになるかを、お題目ではなく、具体例でしっかり学ぶことができる。

邦題は「実用 Common Lisp: AI プログラミングのケーススタディ」となっているが、原題を直訳すると「AI プログラミングのパラダイム: Common Lisp によるケース・スタディ」となっている。むしろ、原題直訳の方がよろしかったんじゃないかな?

あとがき

そんな訳で、また Common Lisp の本が一冊本棚に並んでしまった。まだ読んでない沢山の本をどうしよう? この本も、きっとそんな積読の一冊になるんだらうなぁ。Common Lisp 熱は上がるばかりで、身に入っていない。もう少しプログラミングで遊ぶ時間を作らないと...

実用 Common Lisp (IT Architects’Archive CLASSIC MODER)

2010-04-19

Closure (クロージャー) って何だろう?

何年か前に Closure って何? って質問を受けた。当時、ぼくはその質問に答えることは出来なかった。今も出来る自信がない。だから少し勉強してみた。

初歩の初歩を噛じっただけだけど、考えをまとめるためにエントリーにしてみる。

参考文献

Closure と言えば Lisp ということで、Common Lisp の本を参考にした。

  • 「ANSI Common Lisp」(Paul Graham) pp.96-99
  • 「実践 Common Lisp」(Peter Seibel) pp.66-67

Closure

クロージャは「関数と環境を一緒にしたもの」。これがクロージャーの説明として一番良く聞く文言。

クロージャを知っている人にはこれで十分なのでせう。でも、ぼくにはこの説明はまるで霞を掴むように思える。

更に、「ANSI Common Lisp」から引用する。

関数が外部で定義された変数を参照するとき、その変数をフリー変数と呼ぶ。フリー・レキシカル変数を参照する関数はクロージャ (closure) と呼ばれる。そこでは関数が有効である限り、変数も有効であり続ける。

まだ良く分からない。でも一つ分かった。クロージャは関数だということ。その関数は、フリー・レキシカル変数を参照している。

レキシカル変数とは何か? 今度は「実践 Common Lisp」を引用してみる。

レキシカルなスコープを持つ変数は、束縛フォームの内部にあるコードだけが参照できる。Java、C、Perl、Python にはレキシカルなスコープを持つ「ローカル変数」があるので、こういった言語でプログラムした経験があるならレキシカルスコープにもなじみが深いはずだ。

レキシカル・スコープとは何ということはない。ありふれたスコープのこと。C 言語なんかで「ローカル変数は括弧の中でしか生きられない」とさんざ言っている。難しいことじゃなかった。レキシカル・スコープという名前に馴染みがなかったというだけの話。

クロージャはレキシカル・スコープな変数を参照するけど、その変数は関数の外部で定義されている。

ここで、「ANSI Common Lisp」のサンプル・コードを見てみる。

(let ((counter 0))
  (defun reset ()
    (setf counter 0))
  (defun stamp ()
    (setf counter (+ counter 1))))

関数 reset と stamp が定義されている。この 2 つの関数は、関数の外側の let 式で定義された変数 counter を参照している。なるほど、確かに counter という変数は let 内のレキシカル・スコープに収まっている。その counter を、関数外部の変数として関数 reset と stamp は呼んでいる。この時、関数 reset と stamp はクロージャになる。クロージャが関数と環境 (この場合、外の変数を指しているのだよね?) を一緒にしたもの、というのも何となく分かる気がする。

せっかくなので、stamp と reset を呼んでみやう。こんな感じに使うことができる。

> (list (stamp) (stamp) (reset) (stamp))
(1 2 0 1)

「ANSI Common Lisp」は「同じことは大域カウンターを使ってもできるが、上のようにすると、カウンタが不注意による書き換えから保護される」と続ける。なるほど。奥が深い。

Ruby で書いてみる

同じコードを Ruby で書いてみる。

class Counter
  def initialize
    @count = 0
  end
  def stamp
    return @count += 1
  end
  def reset
    return @count = 0
  end
end

c = Counter.new()

p c.stamp
p c.stamp
p c.reset
p c.stamp

実行例はこちら。

$ ruby count.rb 
1
2
0
1

Object 型の言語を見て思うのは、まずメンバー変数ありきで、そこにメソッド (関数) が付いているということ。昔、どこかで「Object 言語は構造体に関数を足したもの、クロージャは関数に変数を足したもの」というのを見た記憶がある。当時はよく分からなかったけど、今なら少し分かる気がする。

ANSI Common Lisp (スタンダードテキスト)実践Common Lisp

2009-08-20

Lisp 本「Let over Lambda」を注文した

ホットコーナーの舞台裏さんが、Lisp 本の新刊を紹介なさっていたので、思わずポチリとしてしまった。

LispとScalaの日本語の新刊が出ています。まだまだ、翻訳してくれる人が いて、出してくれる出版社がある。素晴らしい! ありがたいことです。ありがたや、ありがたや。

LispとScalaの日本語新刊: ホットコーナーの舞台裏 より引用

LET OVER LAMBDA Edition 1.0

この本はどうやらマロクの解説本らしい。またまたホットコーナーの舞台裏さんの書評を引用。

Common LispをCommon Lispたらしめている強力なマクロの解説本ですね。

Schemeもマクロ入りましたけれど、おれの場合、慣れの問題で、Lispのマク ロといえばCommon Lispのマクロなんですよね。

この本の出版は、2008年4月。アメリカでは、いまでも脈々とLisp本の新刊が出ますね。

Common Lisp本「Let Over Lambda」: ホットコーナーの舞台裏 より引用

「On Lisp」(グレアム著の Lisp のマクロを解説した本) も面白かったので、Let Over Lambda も期待。といっても、まだ Common Lisp のコードなんてほんのちょっとしか書いてないのだけども ^^;

On Lisp

2008-09-26

Shibuya.lisp -- Lisp ユーザーのコミュニティ

Shibuya.lisp なる Lisp ユーザー (開発者?) 向けのコミュニティーが起ち上がった。

Lisp とその派生言語の楽しさと素晴らしさを伝えるために

Shibuya.lisp より引用

対象は Lisp をベースとした言語。すなわち、Common Lisp と Scheme。そして、Arc, Clojure, Emacs Lisp, etc...。

コミュニティー・メンバーになった

ぼくは Emacs Lisp でプログラムの道に入った。C や Ruby や JavaScript をいじりつつも、自分は (Emacs)Lisper だと思っている。

でも、生粋の Lisper とは名乗れない。名乗りたいと思って、何度も Scheme や Common Lisp に手を出した。そのたびに挫折した。教科書程度のプログラミングから先に進めていない。

気がつくと、Emacs Lisp も最近あまりいじってない。

一念発起。一つ上を目指すために、Shibuya.lisp のメンバー登録をした。

メンバー登録

Shibuya.lisp のメンバーになる方法は簡単。

こちらの Google グループに参加するだけ :p

あとがき

10/13 には、第一回のテクニカル・トークが開かれる。第一回は既に満員ということだけど、少しずつこの手のイベントにも参加して真の Lisper に近づきたい。

ref

2007-08-18

on Lisp 勉強会#1

明日、2007-08-19 の午後 1 時から、「on Lisp」の読書会があるってね。「on Lisp」は、Common Lisp のマクロ活用法に焦点を絞った、どちらかというと応用的な本。

場所は大阪。イベント情報は、cotocoto.jp に載っている。

ブログ界隈だと、趣味的にっきの ha-tan さんや Sumibi の kiyoka さんが参加を表明してらっしゃる。

ぼくも、興味ありあり。だけど場所がねぇ。大阪はちょっと遠いかな。それと他に先約もあるんだよね。というわけで参加は無理。皆さんの参加レポートを、待っています。

On Lisp―Advanced Techniques for Common Lisp

2006-11-28

Emacs で快適に Lisp / Scheme ソースを編集する

Emacs には EmacsLisp のインタープリターが内蔵されている (正確には EmacsLisp の処理系の上に Emacs というエディターが構築されてる) ので、EmacsLisp のソースを編集しながら評価が可能。EmacsLisp 程強力ではないけれど、同じようことを Common Lisp (あるいは Scheme) でもやれる。

※以下の説明は、Emacs 22 用のもの。Emacs 21 で同じことが出来るかは確かめてない。

Common Lisp の場合

まず、Emacs から呼び出す Common Lisp の処理系を .emacs で設定する。clisp を使うなら、こんな感じ。

(setq inferior-lisp-program "clisp")

Lisp のソース・ファイルを開いたら、次のコマンドを実行。

M-x run-lisp

すると、shell モードの Lisp バージョンが起動する。こんな感じ。

  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2004


[1]> 

これを inferior lisp モードと呼ぶらしい。ここでは、簡便に lisp shell と呼ぼう。

ソース・ファイルを編集して、括弧の後ろで C-x C-e すると、直前の S 式が lisp shell に送られる。例えば、

(reverse '(3 2 1))-!-

上のコードをソース・ファイルに書いて、-!- の位置で C-x C-e してみやう。すると、lisp shell で上記 S 式が評価され、その結果が表示される。

[1]> (1 2 3)
[2]> 

数引数を付けると (C-u C-x C-e)、C-x C-e 後に lisp shell に switch-buffer する。

ちなみに、M-C-x は、Emacs Lisp mode と同じように、トップレベルの S 式を lisp shell に送る。リージョンの実行は、C-c C-r

Scheme の場合

Common Lisp の場合とほぼ同じ。相違点だけ書いておきませう。

Scheme の処理系は、以下のやうに設定する (下の例は Gauche を使う場合)。

(setq scheme-program-name "gosh -i")

M-x run-lisp の代わりに、次のコマンドを実行する。

M-x run-scheme

後は、Scheme のソースを書きながら、C-x C-e, M-C-x, C-c C-r で楽しい Scheme life をどうぞ。

追記: Scheme と Emacs の連携については、次のページも参考になる。