« June 2014 | Main | August 2014 »

July 29, 2014

プログラミングを始めるには(11)

プログラミングを始めるには、たいていの人が言語仕樣書やその言語に關する學習書を買うに違いない。閒違ってもこのブログを讀んで勉强しようなどと考える人は居ない。しかし、言語仕樣書を讀むことほど退屈なことは無い。これはプログラミング言語書籍の宿命みたいなもので、書いた人がどれほどユニークで面白いこと發想したり考えたりする人であっても、書籍を書くと面白くも何ともなくなる。まあ、たまに吉田弘一郞のような人も居るわけだが...。

私のこれまでの經驗では、言語仕樣書でも言語學習書でも似たようなものだが、それを讀んでプログラムが書けるようになるわけではない...というと少し言い過ぎだろうか。もし假に、その本を讀んだだけでプログラムをスラスラ書けるようになるのなら、大ベストセラー閒違いなしだろう。

スコップを持ったことがない人に穴掘りが出來ないのと同樣に、プログラムを書いたことない人がどれほど素晴らしい言語書籍を讀んだとしても、ある日突然プログラムを書けるようになるなどということはあり得ない。習うより慣れろと常套句的に言われるが、プログラミングスキルはプログラムを書くことによって向上するのであり、讀んだ本の多寡によるものではない。

さて、Lispを學び始めるときに最初にやるのが純Lisp(最小のLisp)というやつらしい。これでプログラムを書くことがLispらしいプログラムを書く早道なのかもしれないが、私はこれに贊成ではない。その理由として、再歸的なロジックを書くことを前提にしているようなフシがあるからだ。中には再歸でなければアルゴリズムではないと考えている人も居るような氣がする。

その例として「Lispでエラトステネスのふるい」(神戸大学)というのを檢討してみる。

(defun range (m n)
  (if (> m n)
      ()
    (cons m (range (+ m 1) n))
    ))
range

(range 2 332)
(2 3 4 5 6 7 8 9 10 11 12 13 ...)

このrangeという關數は自身を再歸的に呼び出して、m~nまでの數値のリストを作り出す。例として2~332で實行しているのは、それ以上のリストを作ろうとするとmax-lisp-eval-depthというEmacs特有の制限値にひっかかってエラーになるからである。この制限値は再歸の深度を制限するもので、無限に再歸呼び出しをしてしまわないためのストッパーのようなものだ。

で、再歸に關しては、内部でループ處理に變換される處理系であれば安全とかいう話以前に、そもそも再歸は好きではない(私は別に學者でも識者でもないので批判はしない)。

(defun range (m n)
  (do ((i m (1+ i))
       (to nil (cons i to)))
      ((> i n) (reverse to))))
range

(range 2 65535)
(2 3 4 5 6 7 8 9 10 11 12 13 ...)

ただ、こう書けば良いのに...と思うだけだ。これならばnを65535だろうが10000だろうが、處理が終わるまでに機械的な閒はあってもエラーにはならない。

(defun filter (n xs)
  (if (null xs)
      ()
    (if (= (% (car xs) n) 0)
        (filter n (cdr xs))
      (cons (car xs) (filter n (cdr xs)))
      )))
filter

(filter 2 (range 2 284))
(3 5 7 9 11 13 15 17 19 21 23 25 ...)

(defun filter (n xs)
  (dolist (elm xs xs)
    (and (= 0 (% elm n))
	 (setq xs (delete elm xs)))))
filter

(filter 2 (range 2 65535))
(3 5 7 9 11 13 15 17 19 21 23 25 ...)

エラトステネスのふるいSTEP2は、range關數で作成した數値リストから、nで割り切れる數値を取り除くfilter關數の作成である。例によって、再歸版とそうでない版を。再歸版の方はrangeのmaxを285以上にすると深度深過ぎエラーになるが、そうでない版の方はエラーにならない代わりにmazeったかな?というくらい時閒がかかる。もちろんこれはmaxを65535にしているからで、285だったら一瞬で終わる。

(defun sieve (xs)
  (if (null xs)
      ()
    (cons (car xs) (sieve (filter (car xs) (cdr xs))))
    ))
sieve

(sieve (range 2 2212))
(2 3 5 7 11 13 17 19 23 29 31 37 ...)

(defun sieve (xs)
  (do ((top (car xs) (car xs))
       (ans nil (cons top ans)))
      ((null top) (reverse ans))
    (setq xs (filter top xs))))
sieve

(sieve (range 2 65535))
(2 3 5 7 11 13 17 19 23 29 31 37 ...)

そして、このステップでエラトステネスのふるいが完成する。本當のふるいは數値リストの先頭がmaxの平方根より大きくなったらそこで探索をやめて良いが、その終了チェックは省かれている。

ちょっと長くなってきたが、私を含めedebugという便利なものを知ってしまった俄かLisperには、なぜ諸先輩方が再歸でプログラムを書くのか分からないかもしれない。實は元來Lisp屋さんというのは、どういうリストを處理すれば目的に達するかという發想でプログラムを書いている。

たとえば最初のrange關數で言えば、(range 2 10)の場合、(cons 2 (cons 3 (cons 4 (cons 5 (cons 6 (cons 7 (cons 8 (cons 9 (cons 10 ())))))))))というリストを評價すれば良いと考えるわけだ。このリストと再歸版のrange關數を見比べれば合點がいくと思う。たしかにこういう考え方で書くことに慣れていくとマクロも見い出し易いのであろう。さらに、元々emacs-lispのようにエディタと一體になった處理系などというのは無く、もちろんedebugなんていうデバッガはなかったわけで、處理の不具合を見つけるにはtraceを使って走行確認するしかなかった。
======================================================================
1 -> sieve: xs=(2 3 4 5 6 7 8 9 10)
| 2 -> filter: n=2 xs=(3 4 5 6 7 8 9 10)
| | 3 -> filter: n=2 xs=(4 5 6 7 8 9 10)
| | | 4 -> filter: n=2 xs=(5 6 7 8 9 10)
| | | | 5 -> filter: n=2 xs=(6 7 8 9 10)
| | | | | 6 -> filter: n=2 xs=(7 8 9 10)
| | | | | | 7 -> filter: n=2 xs=(8 9 10)
| | | | | | | 8 -> filter: n=2 xs=(9 10)
| | | | | | | | 9 -> filter: n=2 xs=(10)
| | | | | | | | | 10 -> filter: n=2 xs=nil
| | | | | | | | | 10 <- filter: nil
| | | | | | | | 9 <- filter: nil
| | | | | | | 8 <- filter: (9)
| | | | | | 7 <- filter: (9)
| | | | | 6 <- filter: (7 9)
| | | | 5 <- filter: (7 9)
| | | 4 <- filter: (5 7 9)
| | 3 <- filter: (5 7 9)
| 2 <- filter: (3 5 7 9)
| 2 -> sieve: xs=(3 5 7 9)
| | 3 -> filter: n=3 xs=(5 7 9)
| | | 4 -> filter: n=3 xs=(7 9)
| | | | 5 -> filter: n=3 xs=(9)
| | | | | 6 -> filter: n=3 xs=nil
| | | | | 6 <- filter: nil
| | | | 5 <- filter: nil
| | | 4 <- filter: (7)
| | 3 <- filter: (5 7)
| | 3 -> sieve: xs=(5 7)
| | | 4 -> filter: n=5 xs=(7)
| | | | 5 -> filter: n=5 xs=nil
| | | | 5 <- filter: nil
| | | 4 <- filter: (7)
| | | 4 -> sieve: xs=(7)
| | | | 5 -> filter: n=7 xs=nil
| | | | 5 <- filter: nil
| | | | 5 -> sieve: xs=nil
| | | | 5 <- sieve: nil
| | | 4 <- sieve: (7)
| | 3 <- sieve: (5 7)
| 2 <- sieve: (3 5 7)
1 <- sieve: (2 3 5 7)
このようにtraceを使うと、sieve關數やfilter關數をどう呼び出したかが分かる。Emacsのようなエディタでなく端末からLispを使っていた人たちは、こうやってプログラムをデバッグするしかなかったのだ。なので、再歸でプログラムを書いて何が面白い?などという言い方は全くのお門違いだったということになるわけだ。

| | Comments (0) | TrackBack (0)

July 27, 2014

プログラミングを始めるには(10)

elispでプログラムを書くには大きく二通りあると思われる。一つは、大きめのプログラムになる場合で、やりたいことをいくつかの關數に分けて書く方法。もう一つは關數を書かずに直接手續きを書いてしまう方法。

Ws000087

この例では、どちらの書き方をしても大差ないし、この程度の機能でこの先再利用可能なモジュールを見いだせるわけでもないので、普通は後者のような書き方をするのではないかと思われる。しかし、elispを使ってこれからプログラムを書き始めようとする人がこの例のような書き方を最初からするとは思えない。足し算にcalc-evalを使っているのは、elispではオーバーフローを起こすような入力があると計算出來ないからである。

Ws000088

elispでプログラムを書くことに慣れていない人は、下側のような書き方をするのではないかと思われる。この二つの違いは何だろうか。

このプログラムは數字をCOUNT數分入力してその總和を求める。上側のプログラムは文字通りその說明通りに書いただけである。下側のプログラムは、要件を實現するためにいくつか變數を使いながら手續きを考えて(設計して)書いている。どちらも同じ結果になるし、下側のプログラムの方が處理手順が分かりやすいので、こっちの方が良いと考える人の方が多いかもしれない。

しかし、elispのプログラムを書き慣れていくと、どんどん上側の書き方に近づいていくと思われる。それはLisp系のプログラミング言語には要件に忠實に書ける能力があるからだ。要件通りに書けなければ、その要件をどういう手順で處理すれば良いか考えないといけない。そこで勘違いやミスが發生し易くなる。一つ一つの式が單純でプログラムが見やすいというのは、括弧のネストにアレルギーを感じるからではないだろうか。

上側のプログラムでは、まさにCOUNT數分數字を入力して、その數字のリストを作っている。そして入力が終わったら、そのリストにある數字を合計している。プログラムの構造はこちらの方が分かりやすいし、人閒の思考レベルに近い。これを可能にしているのがリストという便利なデータだ。これが入力のタンキングを容易にし、入力處理と合計處理の完全分離を可能としている。つまり、データをどう變化させるかという觀點で見通しの良い構造になっていると言える。よって、まず入力處理を書き、數字のリストが出來ることを確認した後で、合計處理を書くことが出來る。

Ws000089

下側のプログラムについて、入力と合計を分離して書くとこんな感じになるのだろう。そして、要件レベルのデータフローに忠實に考えることに慣れ、リスト操作やマッピング(mapconcat)などの便利な機能を覺えると、どんどん上側のようなプログラムになっていくのである。ちなみに、COUNTにゼロ以下の數字を入力すると上側のプログラムではcalc-evalに空文字列が渡るというバグがあった。しかしcalc-evalは(0 "Expected a number")を返し、ランタイムエラーにはしない仕樣になっている。素晴らしい...ということで少し修正しておいた。

| | Comments (0) | TrackBack (0)

July 26, 2014

プログラミングを始めるには(9)

プログラミングを面白いと感じるには、やはり自分でプログラムを書いて、書いたプログラムを自分で動かして、それを實感しなければならない。さらに面白いと思えるのは、誰かが「こういうこと出來ないかなあ」とつぶやいていたことをササッとやってのける。これほど痛快なことは無い。

最近はほとんどのパソコンのCPUが64ビットになってきたが、64ビットの最大値ってどういう數値なんだろう?と漠然と考えたことは無いだろうか。答えは「1844京6744兆737億955萬1615」である。20桁もあるので流石に單位を付けないと分かりにくい。まあしかし、このくらいならWindowsアクセサリの電卓でも簡單に表示してくれる。

Ws000082

ちなみにC言語でどこまでべき乘計算が出來るか試そうと思ったのであるが、Ubuntu14、Fedora20ともにうまくいかなかった。pow關數の使い方が閒違っているのか...。

Ws000083

ま、C言語はどうでも良い。elispだとこんな感じになる。

Ws000084

calc-evalという關數はGNU Calcというモンスター計算機の中の一つの關數である。文字列編集で作り出した數式を評價してくれる非常に便利なものだ。C言語だとCPUによる計算に縛られたような結果しか出せないが、Lispはそうではない。その分性能は良くないが、2の64乘くらいの計算なら、どっちでやっても大差はない。しかし、2の128乘とかになると讀むことも出來ないような大きな數値になり、電卓でも自然數として表示することは出來ない。elispでは數値は24ビットなので、それを超える數値は計算出來ない。そのためGNU Calcは數文字列として計算しているようだ。

Ws000085

このへんまではほぼ瞬閒的に計算出來る。もはやパッと見ても桁數すら分からない(2467桁)ような數値だが。

| | Comments (0) | TrackBack (0)

July 22, 2014

20140722

最近氣が付いたんだけど...このブログ、アクセス數よりコメント數(スパム)の方が多い。なんで?

| | Comments (0) | TrackBack (0)

July 21, 2014

プログラミングを始めるには(8)

プログラミングを始めるにはそれが何よりも面白くなければならない。さらに、面白いと感じるまでに手閒や時閒がかかってはいけない。しかしいくら面白いものでも、ずっとやり續ければ飽きてくる。美人だって3日で飽きる。もし飽きたのなら他の面白いことをやれば良い。そして他のことに飽きたら、またプログラミングに戾れば良いのである。まあ、こんなことは別に人に言われなくても誰もが自然にやっている。

通常、プログラミングはシステム開發の中の小さな工程として行なうことが多い。そして、開發の中で行なうプログラミングは面白いものではない。面白いと感じる餘地がない。とくに詳細設計とかモジュール設計と呼ばれる工程を經てプログラムを作る作業は最惡だ。生產技術というものにうるさい會社になると、モジュール設計でさえ特定のプログラミング言語に依存しないよう實施しなければならないことになっている。プログラムを書くためにする設計をプログラミング言語に依存させないというのは、一體どういうことなのか。それはプログラムを書くためではなく、工程管理や品質管理のためにやっているようなものだ。ある程度の規模のシステム開發はウォーターフォール型で行うことが多く、モジュール設計をする人とプログラムを作る人が別々になることを想定する必要がある。深刻な進捗遲延が起きているプロジェクトなら、リーダはそういうことを考えなければならない。その結果、そもそもそういうリスクがあるのならモジュール設計はプログラミングが出來ない人でも出來た方が良いし、製造工程ではモジュール設計通りにプログラムを作れば良いという作業標準が出來上がる。

しかし普通のプログラマだったら、プログラムのことを考えないで書かれた設計書の通りにプログラムを作るなんてナンセンス極まりないと思うに違いない。ビジネスロジックレベルで分割した機能の中の設計をプログラミング出來ない人がやったら、たいていの場合かなり荒いモジュール構成にしてしまうだろう。1個1個のモジュールが大き過ぎてしまうのだ。それでもウォーターフォール型ではそのモジュール設計は正しいという前提なので、その通りに作らないといけないし、プログラムレビューではモジュール設計通りに作られているかどうかを檢査される。さらにモジュールテストはモジュール設計を元に行わなければならないので、プログラマはモジュール設計に異を唱えることが全く出來ないようになっている。このような實情がある中で、プログラミングを樂しいと思う人が居るだろうか。

| | Comments (0) | TrackBack (0)

July 20, 2014

プログラミングを始めるには(7)

言い忘れていたが、MeadowをフルインストールするとGNU Emacs 21.3版に對應したGNU Emacs Lispマニュアル2.9版の日本語版が入っている。もちろん同バージョンのGNU Emacsマニュアル日本語版も入っている。これらはEmacsのInfoというドキュメントシステムから參照可能だ。"C-h i"とタイプすると起動する。

Ws000072

これがEmacsのInfoを起動したところ。

Ws000073

これがEmacsのInfo。

Ws000074

これがGNU Emacs LispのInfoである。

この2つのドキュメントに限らずEmacsのInfoは元々texinfoという形式のソースになっていて、TeXで印刷可能だ。その製本版は書店で賣っている。以前は何册か買ったが、GNUへの寄付金が含まれているので値段は少々高めだ。GNUへ手っ取り早く寄付したい人には良いかもしれない。書店で賣りものになるほどの分厚い本がこのエディタに同梱されているのだ。

さて、tやnilというシンボルが出てきたが、マニュアルの目次を見るとシンボルのことはもっと後の方で語られている。最初からシンボルに深入りすると都合が惡いということなのだろう。しかしこの2つシンボルの値は變更出來ないということだけ書かれている。

Ws000075

たしかに變更しようとするとエラーになる。

Ws000076

さらにnilというシンボルについていろいろ試してみると、シンボルの値はnil、シンボルのファンクションはvoid(エラー)、シンボルの定義元はnil(通常はそのシンボルが定義されているlispディレクトリ内のソースファイルを指している)、シンボルの名前は"nil"、シンボルのプロパティリストは...意味不明、ということになっているらしい。C言語では變數名や關數名に當たるものであるが、その中にこれだけの情報を持っている。よって、シンボルは單なる變數名や關數名ではない。

Ws000077

ちなみに、こんなことは試す必要はないが...定數の値は變えられないといっても、こんなことは出來るらしい。Lispリーダは123はそのままだとシンボルではなく數値とみなすが、エスケープすると數値ではなくなり、シンボルとして扱うことが出來る。文字列も"123"ではなく\"123"\はOKらしい。ただし、調子に乘ってeqとかcarみたいな基本的なシンボルのファンクションを變更するとEmacsが動けなくなるかもしれないので注意した方が良い。つまり、たとえば(fset 'eq 'equal)というリストを作り出して評價してしまう可能性のあるようなプログラムを書く場合は試驗に細心の注意が必要ということだ。

シンボルのことをどう理解したらよいかを考えていくと、どんどん深みにはまっていくので、たしかにこの場ではこのくらいにしておいた方が良いと思われる。

| | Comments (0) | TrackBack (0)

July 19, 2014

プログラミングを始めるには(6)

おそらく現在もっとも手輕にプログラミングを始める方法は手元のPCにMeadowをインストールことではないかと思う。そうすれば、Emacs Lispを動かすことが出來る。Meadowのインストール方法はいたるところに書かれているのでそちらを參照して慾しい。要するにMeadowインストール用のsetup-ja.exeをダウンロードしてきて實行すれば良い。インストーラーの操作性はCygwinのセットアップと同樣だ。

Ws000065

起動すると上のような畫面が表示される。ここからバッファを*scratch*に切り替えるとEmacs Lispを評價することが出來る。Emacsの操作に慣れていない人は、最初に日本語チュートリアルを一讀すると良い。

Ws000067

どのプログラミング言語でも最初に試してみるべきHello World!はこんな感じ。しかし、GNU Emacs Lisp Manualの最初にはHello World!の演習があるわけではない。最初にあるのはnilとtについての說明である。簡單に言えば、FALSEとTRUEという眞僞値のことであるが、とくにnilはそれ以外の意味を持っている。

Ws000068

*scratch*バッファでどちらを評價しても結果は元の値と同じである。これがEmacsのLispリーダが評價した結果だ。普通の計算機であれば僞は0であり、眞は僞でない値(1であることが多い)ということになるが、Lispの場合はそういう値は表示しないということらしい。

Ws000069

こっちの方が分かりやすいかもしれない。0と1はイコールでないため僞であり、1と1はイコールなので眞になる。それぞれnilとtが評價結果になっている。ここまでは評價結果のところに⇒を表示したが、以降は面倒なので表示しない。

で、マニュアルには「シンボル`nil'には3つの異なる意味があります」と書かれている。さっきまでnilのことを眞僞値と書いていたが、Lisp上のnilはシンボルであり、眞僞値falseであり、空のリストなのだ。こんなことを最初に書く言語マニュアルはあまり見たことがないが、おそらくEmacs Lispのマニュアルを讀むような人はこれが最初のプログラミング言語ではないという想定なのだろう。

Ws000070

nilやtがシンボルだというのなら、そのシンボルの値を確認したくなるが、結果はさっきと同じだ。

| | Comments (0) | TrackBack (0)

プログラミングを始めるには(5)

とりあえず前囘はコアダンプするプログラムになっていたのを修正。ただ、起動パラメータの個數チェックを入れただけであるが...。

Screenshot_from_20140717_110839


ところで、C言語でリスト型のデータを扱うということに關して、少し脫線し過ぎた。別にC言語でもこうすれば出來るということを言いたかったのではないし、そもそもC言語にリスト型のデータなどというものは存在しない。曲りなりにデータ型というのであればそれをサポートする標準的な言語機能があってしかるべきだ。さらにC言語には、あるデータが何型なのかを問う機能すら無い。ただ、何をするにも非常に面相臭いし、ちょっとでも閒違えれば暴走してクラッシュ(例外が發生してコアダンプ)した擧句、エラー理由もわからない。

そのようなプログラミング言語で何か目的を達成するためのプログラムを書こうとする場合、どういうデータをどう處理すれば良いかが分かっても、さらにそれをどう書けばよいか考えなければならず、その枝葉末節を考えているうちに本來の目的を見失ったり、餘計なところに時閒がかかったりする。その人のセンスによるところが大きいが、とくに末端の關數を作る場合に必要最低限で良いのか、ある程度汎用ライブラリ的なものを目指すのかによって、要する時閒が大きく變わる。必要最低限の機能にとどめるにしても、その上位層の前提が崩れたときに作り直しになる可能性が高くなるというリスクもあるし、汎用性を目指したからといってもそれがどの程度他へ轉用が可能かは未知數だ。まして、そのようなことで惱んでいるうちにITエリートがプログラマでいられるフェーズはアッという閒に終わってしまうのだ。

長い人生でたかが數年しかないプログラマのフェーズで、C言語の開發をマスタしても、數年經てば書き方も作り方も忘れてしまう。だとすると、その後も長く觸れる可能性が高いツールでプログラミングに直結しているものを習得した方が良いに決まっている。私が20年來Emacsを使い續けている理由はまさにこれだ。

私が初めてEmacsに觸れたのはたしか平成2年(1990年)だったと思う。當時の社内開發環境といったら、ほとんどの人はPC98からSunのSPARC Stationに端末ログインしてUNIX(SunOS4)を使うというものだった。その環境でメールやネットニュースを讀むとなると、Emacs以外にロクなツールは無かった氣がする。當時のEmacsはバージョンがGNU Emacs 18.58に日本語パッチであるNemacs-3.3.2を當ててビルドしたものだった。日本語入力はWnn4+Egg+boild-eggだったが、クラッシュすることが多かったのでSJ3を使っていたこともある。その後、GNU Emacs 18.59をベースにしたMule 0.9.8が出て、以降會社のEmacsを自分でビルドするようにもなった。ちょうど同じころ、PCのOSまだMS-DOSだったがDOSエクステンダーを使ったDemacsというのが出てきて、UNIXマシンにログインしなくてもGNU Emacsを使えると騷がれたが、社内ではあまり普及しなかった。

2000年以降は開發ターゲットがPC系になったこともあり、Mule for Win32を使ったり、Cygwin上のEmacsを使ったりしていた。そうこうしているうちにMuleはGNU Emacsに取り込まれ、Mule for Win32はMeadowになった。2007年以降はGNU Emacsのtrunkをcheckoutしてきて自分でビルドして使っていたが、現在PC上ではもっぱらMeadow-3.00、たまにxyzzyを使用している。VMware上ではUbuntuを好んで使っていて、その上でも自分でビルドしたEmacsを使用している。

Emacsのビルドは、Nemacsの頃はまだautoconfが作り出すconfigureを使ってMakefileを作成するという形式になっていなかったので、X11やWnn4のライブラリをリンクする設定などをするのにMakefileを編集する必要があった。PC上で初めてコンパイル(bootstrap)したときは數時閒かかったが、今ではPCの性能が良くなってきているので數分で濟むようになっている。要するに誰にでも出來るようになってきたということだ。バイナリをダウンロードして動かすのに抵抗がある人は自分でビルドすると良い。


| | Comments (0) | TrackBack (0)

July 18, 2014

プログラミングを始めるには(4)

リストデータをC言語で扱うのは非常に面倒だ。しかし、それは面倒な手順をその都度書かなければならないような氣がするからであって、C言語でリストを扱う場合はプログラミング思考を妨げない程度の粒度で便利な關數を書くものだ。

Screenshot_from_20140717_102823

たとえばこんな關數を書いてみる。かなり胡散臭いが...。

Screenshot_from_20140717_102910

そうすると、オブジェクトを作成したら多少Lispらしい粒度の記述になる。

Screenshot_from_20140717_103029

結果はこの通り。

つまり、オブジェクトやコンスセルもどきの作成と設定を共通關數的に書いてやれば、C言語でもある程度のことまでは出來るかもしれない。しかし、ひとつ閒違えばエリア破壞を起こし、その原因を見つけるまでに惱むこともある。現に、このプログラムもコンパイル後に動かしてみたら案の定コアダンプした。そこでgdbでステップ實行して原因を見つけ、修正後にやっと動いた。Lispならそんなデバグは必要ない。

それは人閒が普通に思考出來るデータフローの粒度でプログラムを書けるからだ。Lispが人閒の思考を妨げないプログラミング言語と言われる所以である。

ちなみにこのプログラムは引數無しで起動するとコアダンプするのご注意を(笑)

それと、なんでC++で書かないの?とかのツッコミも要りません。


| | Comments (0) | TrackBack (0)

July 16, 2014

プログラミングを始めるには(3)

あなたは今いくつかの業務を經て、システム開發とはどういうものかがおぼろげ乍らに分かってきているとする。そして、このままJavaだのC#だのでプログラムを書いていれば、それで良いのだろうか?と疑問を持ち始めているかもしれない。

プログラミングに限らず、それを1個だけしか知らなければ、それ自體を客觀的に見ることは出來ない。やはり何か別のものを經驗した後に初めて評價可能になる。ただ別のものを知れば良いと言っても、C言語を習得した後にPascalの勉强をしたところで、C言語を客觀視するのはむずかしいだろう。似た者同士なら習得は容易かもしれないが、それでプログラミングスキルが向上するかどうかは分からない。どちらかと言えば、かなり特殊なもの、特異なものの方が未知の觀點をより多く得られるのではないか。

そう考えたときに、CやJavaなどのプログラマにとってLispはパッと見でかなり特異なプログラミング言語ではないだろうか。たまに自分で書いたelispのプログラムを周圍のSEに見せると、まるで宇宙人を見るような顏をされることが多い。ほとんど變態扱いである。そして、たいていの人はこんなの分かるわけがないし、こんなプログラムを書けるようになるとは思えない、といった印象を持つ。

しかし、人は見かけによらないと言われるように、プログラミング言語も意外と見かけによらないものだと思う。では、ゆるりと始めましょうか...elisp談義。


Lisp(List Processing)というからには、さぞかしリストを扱うのが得意だろうということだが、Lispはリストを扱うどころか、プログラム自體がリストなのだ。それに比べて、Javaのリスト機能?であるArrayListの何とも貧弱なこと。あれじゃあC言語の配列より扱いにくい氣がするし、あんなもの、とてもリスト機能と呼べるようなシロモノじゃない。

まあリスト機能というのなら、とりあえずこんなことくらいは簡單に出來ないとお話にならない。

Ws000064

Lispなんだからリストの操作が得意なのは當たり前であるが、この中でもっとも驚くべきことは、一番最初のリストをtest-valueという變數に設定しているところである。リストのデータをこんなふうに設定出來るのはLisp系の言語(Schemeとか)やperlなどのスクリプト言語くらいだ。これのことをread表現とprint表現の一致と呼んだりする。Lispの關數の擧動を確かめるのに、このように適當にリスト變數を作れるのは非常に便利だ。これをC言語でやろうと思ったらゾッとする。

Screenshot_from_20140713_132318

たったこれだけのことを、

Screenshot_from_20140713_132418

Screenshot_from_20140713_133548

C言語だとこんなに書かないと出來ない。まして複雜なリスト操作を行おうものなら、ものすごく面倒なことになるのは容易に想像がつくだろう。さらに、これではアルゴリズムの妙を樂しもうなどと考える餘裕など無くなる。ちなみにこんなプログラムを書くのは何年ぶりかなので、コンパイルが通るまでに結構時閒がかかったりした(笑)


| | Comments (0) | TrackBack (0)

July 14, 2014

プログラミングを始めるには(2)

MacOSやWindowsのようなGUIを持ったOSが登場する前は、ファイル操作をはじめとするすべてのことをシェルとかコマンドプロンプトからコマンドを入力して行なっていた。その當時、UNIX上で何かしたい場合はこう言われていた。

(1)シェルのコマンドラインで出來ないか試す。
(2)コマンドで出來ないことはスクリプトを書いて試す。
(3)スクリプトで出來ないことはCのプログラムを書いて試す。

いまどきの若手SEはWindows以降の世代なので、Linux上でファイルの移動やコピーをするにもGUIでやろうとする。なので、シェルから複雜なコマンドを入力して何かしようなどとは考えない。そうなると上記のような3段階の發想にはならないので、GUIで出來なかったらそこで行き止まりとなる。そして「そんなむずかしいことを自分で出來るようになる必要はない」などと考えて、變に安心したりする。

この3段階の發想を地で行くのがEmacsというエディタだ。

(1)テキストの編集をする場合はまずコマンドで出來ないか試す。
(2)コマンド出來ないことはelispでコマンドを書いて出來ないか試す。
(3)elispで出來ないことは...。

テキストの編集をコマンドでと言うと、我々よりもさらに先輩の方々はexのようなラインエディタを思い浮かべるのかもしれない。そして彼らは重たくなるという理由でEmacsの使用を極度に嫌がった。ワークステーションのCPUがMC680X0とか初期のSPARCで、メモリもメガバイト單位だった頃の話だ。嫌ならインストールしなければ良いのに、必ずといって良いほどEmacsはインストールされていた。

Emacs上で文字を入力したり檢索したりする場合、それはコマンドとして動作している。普通にabcと入力する場合、それを1文字ずつself-input-commandというコマンドが處理しているのだ。そしてその他數多くの編集機能もすべてコマンドとして動くようになっている。さらに、それらの豐富な編集コマンドを驅使しても出來ないことがある場合に、elispで書くというわけだ。ということで、(3)に該當するようなことはほとんど無いといって良い。

さて、いくらelispが素晴らしいと言っても、さすがにこれを最初に學ぶプログラミング言語にしたいという人はほとんど居ないと思われる。おそらくは、成り行きで擔當することになった開發で使ったプログラミング言語は習得出來たが、これで良いのだろうか?という疑問を持ち始めたときに、物陰からすっと入ってくるタイプのものなんだろうという氣がする。


| | Comments (0) | TrackBack (0)

July 12, 2014

プログラミングを始めるには

常日頃、會社の若手社員や付き合いのあるベンダの若手SEにelispの面白さや便利さを敎えてあげようとしているのだが、やってみようという人はなかなか現れない。

若い人で、仕事として(生きる糧として)プログラムを作ったことがない人が、何かプログラミング言語を習得しようと思ったときに、どのプログラミング言語を選ぶのか。これは「プログラミングの話」というタイトルで、プログラミング言語を習得する際に言語選擇の餘地など無いのが常だということを書いた。というのも、ほとんどのプログラマがどれかのプログラミング言語について習得したと言えるほど習熟するには、仕事としてそれを實踐する以外に方法が無いからだ。

仕事でプログラムを作るのと、そういう經驗のない人がプライベートでプログラムを作るのでは何が違うのか。簡單に言えば、仕事でプログラムを作る=開發であり、要件定義、仕樣檢討、機能設計、詳細設計、プログラム製造(プログラムコーディング、コンパイル、單體試驗)、結合試驗、總合試驗、運用試驗という工程(開發プロセス)を經て出來上がる。この中で、何も知らない人がイメージするところのプログラムを作るという作業はプログラムコーディングにあたるが、それが占めるウエイトは開發全體の10%に滿たないことが多い。なので、プログラムを書く前にかなり時閒をかけていろいろ考えないと、どう書けば良いのか分からないのだ。

だから、プライベートで何かプログラミング言語を習得したいと思っても、何を書いたら良いか分からないし、具體的にこういうことが出來るようになりたいと思ったとしても、すぐにプログラムをすらすらと書けるわけではない。假に世の中の多くの若者が憧れるカリスマプログラマでも、何かシステムと呼べるほどの規模のプログラムを作ろうと思ったら、上記の開發プロセス通りに事を進めるしかないし、そうでなければマトモに動くシステムは出來上がらない。

ここまで讀んでも、プログラマになりたい若者には小賢しい能書きとしか思えないかもしれない。そこでさらに具體的に掘り下げてみよう。

どのようなプログラムであれ、極論すれば入力した情報を加工して別の情報を出力する。2つの數字を足し算するプログラムは、2つの數値を入力して、足し算し、その結果を出力する。そんな簡單なプログラム?と思うかもしれないが、それは要件によって大きく變わってくる。もしも、その2つの數字がWEBブラウザから入力され、それをサーバで受け取って計算し、入力每に結果を蓄積して、好きな時にその結果一覽を參照したいという要件だとしても簡單に作れるだろうか?

おそらく學校でやるようなプログラム演習の解答例はせいぜい以下のようなものだろう。

Ws000058

いや、もしかしたらこれで良しとする場合だってあるだろう。

Ws000062

elispならば、(mylib-plus-two-numbers 1 2)とタイプして評價すれば結果が得られる。しかし、C言語だとそういうわけにはいかない。C言語で同じように書いても、これだけでは動作しないからだ。

Screenshot_from_20140713_113120

これをコンパイルしても、實行出來るプログラムを生成することが出來ない。最近のgccって、こんなにいっぱいエラーメッセージを出してくれる。

Screenshot_from_20140713_114231

で、エラーが出ないよう、思いっきり手拔きの實行可能プログラムを書いてみたのだが、あまりに久しぶりなので、こういうワーニングが出てもすぐに對處が出來ない。

Screenshot_from_20140713_115641

/usr/include配下のヘッダをprintfでgrepすると、stdio.hに外部宣言があったのでインクルードしてみた。實行ファイルは生成されているが、これでワーニングは解消する。

Screenshot_from_20140713_120853

結果はこの通り。

Screenshot_from_20140713_121232

途中から環境を假想マシン上のLinux(Ubuntu)に變更した。一應、最新のEmacsをコンパイル出來る程度には整備してあるので、C言語のプログラムをあれこれ試すのは朝飯前だ。

ところで、話がだいぶ逸れた。「2つの數字をWEBブラウザから入力して」云々のプログラムは、C言語では出來そうになく、WEB系のプログラムはやり方を知らないし、調査するのも面倒だ。しかし、同樣のことをelispで試すのは非常に簡單だ。

Ws000063


| | Comments (0) | TrackBack (0)

« June 2014 | Main | August 2014 »