Top / Alan への誘(いざな)い

Introduction to
Alan v0.31

Alan への誘(いざな)い

Last updated: 2008-01-07
Created: 2004-12-11


by Fumisky Wells
ふたりは手をとりあって、
こえをそろえていいました。
「バルス!」
そのとたん、木のねに
つつまれた、あの大きな
飛行石がぴかりと光り、
たちまち黒くかわっていったのです。
....
ラピュタは、中しんから
がらがらとこわれていきます。

--天空の城ラピュタ より

CONTENTS

  1. Alan って何?
  2. はじめの一歩
  3. 例
    1. 例1 "Hello, World"
    2. 例2 シンプルな grep
    3. 例3 関数呼び出し
    4. その他のサンプル
  4. ラピュタの呪文
  5. バグレポート、ご質問、ご提案など
  6. 用語
  7. 補足

Alan って何?

Alan は、プログラム言語です。 わたくしこと Fumisky Wells が趣味で作っているものです。
  1. Alan で何ができるか
  2. 概要

Alan で何ができるか

(v0.31) class でコンストラクタ・ディストラクタ・メンバ関数が使えるようになりました。ただし、メンバ関数内で型パラメータはまだ使えません。また、オブジェクト指向はまだサポートされていません。
(v0.30) class (とは言ってもまだ構造体レベル)で総称型が使えるようになりました(例: class Complex[T] ... end)。ただし、メンバ関数内で型パラメータはまだ使えません。
(v0.29) class (とは言ってもまだ構造体レベル)を組み込み総称型(array, list, map)の中で使えるようになりました。
(v0.28) class (とは言ってもまだ構造体レベル)が記述できるようになりました。
(v0.15) WikiMini が記述できるようになりました。
(v0.10) DNS で名前検索をしたり(Netパッケージ)、結果をキャッシュしたりできるようになりました。
(v0.09) Webサーバのログ解析ぐらいは何とかできるようになりました。
(v0.08) 古世代の BASIC 程度のことがやっとできるようになりました(^^;)。

骨組み(例外処理、名前空間、など)の作成を優先したので、 提供されている関数やデータ型はまだ包括的でも直交的でもありません。

何ができないか、は 制約事項 をご参照下さい。



まだ制約だらけですが、機能拡張はこれから徐々に行っていく予定です。

概要

概要は以下のようなものです。

勉強

今は仕事&趣味で C++ と Perl を使用していますが、 段々と不満がたまってきました(笑)。 「こんな言語ってないかな」と思って探してみましたが、 なかなか見つかりません。 そんな中、勉強を兼ねて作ってみるのも1つの方法と思い、 実行に移して見ることにしました。 まあ、過去何度か頓挫しているので、今回もどこまでできるかは?ですが。 将来的には C++ & Perl (のうち、仕事&趣味で使用する範囲のサブセット) を Alan に置き換えられるといいかな、 と考えています。

(2006/05) 仕事で Ruby を使い始めました。 Ruby を最初に知っていれば Perl を使わなかったかもしれません(^^;)。 言語としては Ruby の方が Perl より好きです。
ライブラリとドキュメントに関しては perl にあと一歩及ばないようでもあります。

(2007/08) ...などと昨年書いてしまいましたが、Rails を使って考えが 変わりました。Rails 本(AWDwR) と Rails API サイトで、やりたいことが 大体出来てしまいます。驚き!

名前の由来

名前 "Alan" は、単に "A language", "Another language" ぐらいの意味です。

今インタプリタ、目標コンパイラ

Alan は「今のところ」インタプリタです。 「今のところ」というのは、本来コンパイラを作ってみたかったのですが、 バイナリの生成など難しそうなので、とりあえずインタプリタにした、という 安直な理由からです。

静的型言語

C++(型あり)とPerl(型なし)の両方を経験しましたが、個人的には型が あった方がよいと思っています。なので、Alan も型あり言語とします (というか、動的型言語や型なし言語を使うなら Ruby や Perl が既にあるではないか)。 型に関する私見を 「Technical Document」の 「設計方針」の章の 「型について」の節 に書いています。

例外処理

例外処理の在る無しはコーディングに大きく影響するのと、 気軽に例外処理を使用できる言語が欲しかった、という理由から、 例外処理は早いうちからサポートしたいと考えています。 現時点ではまだ制約が多いですが、骨組み部分は実装できました。

はじめの一歩

Alan のインストールがまだの場合は そちらを先に行ってください。

ここからは、簡単な入門編として Alan の遊び方について述べます。

  1. Alan スクリプトを入力してみましょう
    $ alan
    put("Hi")
    Ctrl-D
    
    なお、上の Ctrl-D は、Unix系での 入力の終りを示す Control-D です。
    この例は "Hi" と印字する Alan スクリプトです。

  2. 結果はこのようになります:
    $ alan
    put("Hi")
    Hi
    $
    
    "Hi" と表示されたでしょうか?なお、最後の $ はプロンプトです。

  3. alan が実行できることを確認できたら、次に、適当なエディタ (vi, emacs, など)で下のような alan プログラムを書き、適当な ファイル名で保存します。ここでは tst.al とします:
    put("Hello, World!\n")
    
    次いで、
    $ alan tst.al
    
    として、画面に
    $ alan tst.al
    Hello, World!
    $
    
    と表示されたら、成功です! 1行の簡単な alan プログラムですが、正しく実行され 終了しました。
    あとは次章 "例" 以降をご覧になってみて下さい。

  4. エラーとなった場合。
    もし
    $ alan tst.al
    cannot open tst.al
    
    とでも出たら、ファイル名の指定ミスです。 ファイル(ここの例では tst.al)が存在するか、 ファイル名のタイプミスか、確認してみてください。
    もし
    $ alan tst.al
    error: syntax error
      0001 put("Hello, World!\n"
                                ^
    
    となった場合、文法エラーです。最初の 0001 はファイル tst.al 中の行番号を表しています。また、上矢印(又はハット(^))で示した 個所がエラーの発生した場所を指しています。 上の例では、最後の閉じ括弧で syntax error(文法エラー) となっていますね。詳しくは次章以降で説明しますが、この場合は 閉じ括弧が抜けています。
    エラーは様々なものが発生しうるので全てのケースをここで 示すことはできませんが、他に発生しうる典型的なケースを あと2つ載せます:
    $ alan tst.al
    error: undefined ID(pt)
      0001 pt("Hello, World!\n")
           ^
    
    ↑これは、「ptなんて識別子(ID; Identifier)はないよ」と言っています。 印字関数 put のスペルミスですね。
    $ alan tst.al
    error: string literal is ending without closing by double-quotation(")
      0001 put("Hello, World!\n);
               ^
    
    ↑これは、「文字列が行の終りで閉じてないですよ」 今のところケアレスミスを防ぐ目的で、複数行に渡る文字列は 許していません(これではまった記憶がある)。

例

  1. 例1 "Hello, World"
  2. 例2 シンプルな grep
  3. 例3 関数呼び出し
  4. その他のサンプル

例1 印字

おきまりですが、Hello,World! を印字するプログラムは:
put("Hello, World!\n")
です。たった一行ですが、下記のような Alan の仕様が分かるかと思います:
  1. 印字は print ではなく printf でもなく cout でもなく put としました(*1)。
  2. putという手続きに Hello,World 文字列をパラメータとして渡しているのですが、 パラメータには括弧が必要ということ (ただし、パラメータがない場合は括弧が省略できます) (*2)。
  3. 文字列は double-quote で囲います。
  4. 改行は文字列中の \n で行います(C/Perl系ですね)。
  5. 文の最後にセミコロンはありません。 v0.14 までは C/C++ と同様セミコロンで終端していましたが、 v0.15 で文と式の区別をなくした結果、セミコロンだと都合が悪いことに 気付き、セミコロンを廃止してみました。 言語仕様のデザインの顛末は リリースノート をご覧下さい。

例2 シンプルな grep

Alan Ver0.09以降でファイル型(file)と正則表現型(rex)を備えています (言語仕様/データ型 参照)。 grep と同等の機能の Alan スクリプトは下記のようになります:
for str:s in stdins do
   if s in /[Hh]ello/ then
      put(s)
   end
end
このスクリプトは、stdins(Perl の <> に相当)からファイルを読み、 文字列 hello 又は Hello にマッチする行を印字します。 各行を解説します:

例3 関数呼び出し

1からnまでの値を足す「等差級数の和」を処理する関数の例です。 公式を使用すれば一発で答えはでますが、ここでは再帰呼び出しで 実装しています。
# 'sum' function

int:sum(int:n)
   if n==1 then
      1
   else
      n + sum(n-1)
   end
end

# Main
put(sum(10))
  1. 関数定義の文法は
    戻り型 : 関数名(引数宣言) ... end
    です (*4)。
  2. 関数の戻値は関数の最後の式の値です。
    returnで途中から関数を抜ける場合、return の直前の式が 関数の戻値となります (C/C++ 等の return 式; という記述はできませんのでご注意下さい (*5) )。

その他のサンプル

その他、テスト的に作成したサンプルが sample/ にありますので、ご参考までに。

以下は、一例です:

ラピュタの呪文

天空の城ラピュタは今でも私の好きな映画の1つです。

映画の最後の方で、シータは祖国ラピュタを捨てパズーと共に 大地に降りて生きて行くことを選んだのでした。 そのとき、シータが謎の呪文を唱えてラピュタを崩壊させたシーンは印象的です。

「バルス!」

この呪文そのものにラピュタを崩壊させる力があったのでしょうか?

多分、そうではないでしょう。呪文をスイッチとして、 あらかじめラピュタに仕組んであった自己崩壊のための機構が作動したと考えられます。

ひとつの言葉をきっかけに、あらかじめ仕組んであった機構が働き出す...。 そう、これはまさしくプログラミングの世界です。

「バルス」に相当するものを Unix/Linux で言えば、"sudo rm -r /" でしょうか。「スゥドゥー アールエム マイナスアール スラッシュ」 ...怪しい呪文ですね。良い子の皆さんは決して真似しないでください(^^;)。

プログラミングをレゴに例えると、無限のブロックのようなものです。 ブロックが足りなくなってつまらない思いをすることはありません。 レールや電池・モータまでついてきます^^。 部屋いっぱいの城や町やロボットや車など、好きなように構築できます。 そして、そこに好きな呪文を与えることで、好きなように動かすことができるのです。

Alan もそうやって作ってみた、呪文を唱えるための呪文、のようなものです。

用語

Alan では基本的に C/C++ の用語を使用します。
フリー関数
クラスに属さない関数。C言語の sin(3), printf(3)など。
→メンバ関数
メンバ関数
クラスに属する関数。他言語で言うメソッド・feature。
→フリー関数

補足

「ユーザズ・ドキュメント」という観点からは本質的な内容ではありませんが、 Wells の主観などをここでコメントさせていただきます。

(*1) 印字 = put文

まあ、名前の違いは本質的ではありません。 マイナー言語 Turing の影響を受けたところではあります。

(*2) 変数定義文法と手続き呼出し

Fortran/C/Algol68 系の変数定義(宣言) "type var" を採用した結果、 手続き呼出しを括弧無し "proc parm" とすると文法として矛盾してしまった、 というところです。Pascal系の手続きが括弧無しなのは他の文法規則と 矛盾してないためです。こんなところに、なぜ C の手続きで括弧がいるのかの 理由があるようです。複雑なロジック(字句解析に字句情報を feedback するなど) を導入すれば回避できるのかもしれませんが、そこまではしませんでした。

(*3) 変数宣言の文法

変ですか?変ですよね。C/C++ 的でもなければ Pascal的でもない。 が、要は慣れです、慣れ(やや苦しい言い訳)。

(*4) 関数定義

(v0.15) begin を省きました。

C系とPascal系のブ格好な組み合わせのようで、 私自身、あまり好きではありませんが、 他の案も思いつかないのでとりあえずこのまま進めます。

(*5) return文

当初、Eiffelの result 構文を採用していたのですが、 意外に使いにくい。result文は、「入り口1つ・出口1つ」の原則 と密接につながっています。 が、この原則自身が、言語の形式的意味論をより簡単にするための ものです。 他方、return文は「これ以降は処理を中断して関数を抜けて欲しい」 と考える人間の思考の性質を表現したものであるため、 「入り口1つ・出口1つ」の原則とは水と油みたいですね。 結局、後者 return文 を採用しました。

(*6) loop文

Turing言語からの拝借です。

(*7) 関数の入れ子

C に習って、Alan でも関数のネストは実装していません。

関数のネストを廃止したのは、C の大きな功績だと私は思っています。 このおかげで、コンパイラが単純になり、また生成されるコードも 単純になるだけでなく、実用性はあまり失われていません。

全てを直交的にする必要はない、ということだと私は理解しています。

私は、Pascal(関数の入れ子をサポートしている)で少々と C/C++ で多くのプログラムを組みましたが、その経験上、 C/C++で「関数の入れ子があったらなあ」と思ったことは ほとんどありませんでした。また、あっても、すぐに 他の解決方法がすぐに見つかったものです。

そういうわけで、Alan でも「可能な限り単純に」の原則に乗っ取り、 関数の入れ子は採用しないことにしました。

(*8) 関数引数はデフォルトで「読み出し専用参照渡し」

これも Turing言語からの拝借です。 C++ で言うところの "const type &var" をデフォルトとしている、 ということです。

まず、参照渡しを default としたのは、サイズの大きい変数(オブジェクト) を関数に渡すケースが増えてきたことへの対処です。

次に、readonly を default としたのは、呼出し側で、引数が 関数の中で変更されないことを明示したいためです。

全体

学習・アプリ開発・アプリ保守、の合計という観点でコストを下げたい、 と考えています。まあ、私の見積もりミスもあるかもしれませんので、 その際はコメント頂ければ幸いです。




//以上

Top / Alan への誘(いざな)い





Alan ver0.31