文法

簡略化した文法

list:
	{exp,..,exp}
	
exp:
	exp operator2 exp
	term

term:
	primary...primary
	primary

primary:
	literal
	(exp)
	identifier
	identifier (exp,...,exp)
	list



c.f. lisp方式
exp:
	exp list
list:
	{exp,...,exp}
ex.
={a, +{ *{2,x}, 1}}
内部構造はこれに近い。

もう少し詳しい文法


compExp:
	arithmetic [> < ==] arithmetic [> < ==] .... arithmetic

arithmetic:
	[nul + -] exp ... [+ -] exp  

mExp:
	operatorExp [*/] ... [*/] operatorExp

operatorExp:
	powerExp ... powerExp  (右から左)

powerExp:
	Exparithmetic
	Exp^Exp 

underscoreExp:
	expsequence
	exp_exp

dotExp:
	term . term


コメント:

オペレータ積 l_value r_value
もしl_valueがoperatorであればoperator(r_value)が評価される。
もしl_value*r_valueが定義されていればそれになる。

A.iとA[1,2,3]の等価性はとりあえずなし。

M.iとM.sunとかの違いはどうするか。
仮にこのように決定する。
M_expはexpを評価して渡す。
M.expはexpを評価せずに渡す。


term: 
	INTEGER_LITERAL
	FLOAT_LITERAL
	IDENTIFIER
	IDENTIFIER ( sequence )			function call
	STRING
	( exp )
	list

コメント:

termには現状'[' exp ']' がある。

function( sequence )でもfunction callがなされるが
operator (sequence)でもfunction callがなされる。
さしあたりfunctionはオペレータとしても使えるし
オペレータはfunctionとしても使える。


sequence:
	exp , ... , exp 
	exp

id_sequence:
	id, ... , id
	id

list:
	{ sequence }
	{}		: const empty list


statement_squence:
	statement [CR ,] ... [CR ,] statement


Statement演算子群

assignStat:
	operatorExp = compExp

define identifier (id_sequence) list
while (condExp) list
if (condExp) list
if (condExp) list else list
return [nul exp stat]
break 


コメント:
変数などの状態を変えるものはstatementに入る。
statementの多くには何らかの遅延評価が係っている。

assignExpの形式
id = exp	: expが評価されて、変数idに代入される
id x = exp :  仮引数xは評価されない。expは、仮引数以外は評価される。
id(seq) = exp : 仮引数列をひいて関数を定義。
id.exp1 = exp: exp1の要素に代入

ex.
a = quote {
	statement
	statement
}
define f(x) a

define H(){
	f(x)=x+1
	return f
}
は無名の関数が返される。
return f(x) はローカル変数xの値をいれて評価された物が返される。
return f(x)=x+1 は式 f(x)=x+1が返される。

関数定義の3形式
define f(x){...return y}
define f(x) = x+1
f(x) = x+1
第一形式はstatement listは完全な遅延評価であり、グローバル変数などは取り込まれない。
第二形式は第一形式と同じ。第三形式は、x以外は出来るだけ評価する。



まだ決めていないこと:
新たな型の宣言、メンバ変数の隠蔽、オペレータの定義方法

新しい型のデータ構造はtype=使われていない数で中身はlist。
それぞれの演算子に(type, type, function_name)という構造のテーブルを用意する。type=nulだと何でも取り入れるということ。

データ型

原始データ型

整数 浮動小数点数 複素数 文字
数式、プログラム型
関数(仮引数列とプログラムの二要素)

コンテナ

リスト
配列

派生データ型

ベクトル
行列
イメージ(ピクセルマップ)
時間をキーにした連続関数

派生コンテナ

集合
構造体(識別子をインデクスにした配列)
ハッシュ表
連想記憶

言語の特徴(未実装のfeatureを含む)

できるだけ自然な数学表記ができること。

2x+1 とか x2+z とか sin 2πn とか y = Σi xi yi のような自然な数学表記ができます。

プログラム自体も一つのデータ型です。

数式やプログラムを操作の対象にできます。関数は関数を返すことができます。コンピュータの真の力はコードの自己改変にありますが、多くの言語ではそれに到達するためにその言語の中でインタプリタを書かなくてはなりません。この能力は危険とともにある種の仕事を劇的に速くします。

集合演算を中心に、最大限の並列性の記述

行列Aとベクトルxに対して y = A x と表記するだけで積が行えます。imageに対して y = a + b という計算を行うことができます。listに対してlist特有の操作以外の操作を加えれば全ての要素に対して同じ操作が加えられます。MatLabやIDLを使ったことのある人なら分かるとおり、これによってループの大部分は明示的に書く必要がなくなります。またインタープリタであっても充分な速度を得ることができます。

アルゴリズム変形支援

GUIフロントエンドは種々のアルゴリズム変形支援機能を持ちます。

たとえば、変数名、関数名は文法の知識を利用して一発で変更することができます。sedのように文字列の一部が偶然に一致しただけで置き換えられたりはしません。また、一本の数式の中の項の順番をマウスドラッグで入れ替えたり、ループのネスティングをドラッグで入れ替えたりする事ができます。

この変形支援に必要な複雑なアルゴリズムは(速度が必要な部分以外)それ自体、この言語で記述され、ユーザが拡張する事もできます。

またフロントエンドのイベントハンドリングのような速度の必要ない部分は全てこの言語自身で記述されます。

symbolic manipilationができます

アルゴリズム変形支援(リファクタ支援)とsymbolic manipulationの合一。

アルゴリズムとデータ型の分離

配列とリストのような異なるデータ型でも宣言文を置き換えるだけで後のプログラムを書き換えず動きます。その他の多くのデータ型でも同様のことがいえます。クラスが定義できる言語ではメンバ変数が入れ替わってもメソッドが変わらない限り自由に置き換えが可能なことと同じです。

一般的なコンテナ、つまりたくさんの要素をいれるデータ構造についても
1,要素数が変動するか。
2,要素数の上限に静的な限界をもうけてよいか
3,配列の先頭や途中に要素を挿入、削除する必要があるか。
3,ランダムな読み出しは必要か
4,要素の追加と読み出しの比率はどれくらいか
5,要素の全てのデータ型は同じ型か。またバイト数は同じか。
などの要求によって千変万化なデータ型があります。たとえばC言語では静的配列、整数変数、ポインタとmalloc()を組み合わせて全ての面倒をユーザが見ることになります。そして、後から効率が悪いことが分かっても、大量のコードの書き直しが発生するために現実に書き直すことができません。またmalloc()されたメモリの管理は苦痛です。
この言語では、原始レベルで

この二者をサポートする。そして標準ライブラリ内で以上の二つを組み合わせることによって上記のような種々の要求に対応した一次元データ構造を定義し、演算子オーバロードによって直交したアクセスを提供する。これによってデータ実装の変更は宣言を一つ書き換えるだけで可能になるようにする。(ただし、極端にパフォーマンスの悪い演算子は実装しないで置くかも。直交性に反しても。)

(Cよりは)豊富なデータ型

原始データ型: 整数 浮動小数点数 複素数 文字、数式、プログラム型

コンテナ:リスト 配列

派生データ型: ベクトル 行列
イメージ(ピクセルマップ)
集合
構造体(識別子をインデクスにした配列)
ハッシュ表 連想記憶
時間をキーにした連続量

任意の程度で静的な型づけや静的な限界を導入(そしてチェック)

(LISPほどは)単純でない文法

かけ算は足し算よりも優先されます。

静的な限界のないプログラミングスタイル

科学者の日常のデータ処理と計算に使うことを考えるとCの問題点は何にでも静的な限界があることです。

配列などは基本的に大きさにあらかじめ限界を設けません。また変数の型も存在しません。

しかし安全のためと、速度のために静的な修飾子をつけることはいつでもできます。また修飾子が十分な水準に達した時、自動的にマシンコードまでコンパイルする実装が許されます。

計算アルゴリズムと計算内容の分離

アルゴリズム変形支援は究極的には、アルゴリズムと計算内容の分離につながります。(c.f. 計算内容と型の制限の分離。)

プログラマが書いたアルゴリズムはコンパイラに対してのヒントでしかなく、結果の同一性が保証される限りにおいてどのようなアルゴリズムの変形も行う権利が保留されます。ただしこれは当面実装されません。また、現実的にはアルゴリズムの変形は自動ではなくプログラマによってヒントとして与えられます。結果の同一性はシェルによって確認されます。これがアルゴリズム変形支援です。変形支援はこの言語自身で記述されます。

統一病からの訣別

たとえば関数型か手続き型か踏み絵をしてどちらかにきめて、それ以外の成分を除去しようとはしません。

また例えば某OSでAPIを統一するためにハードデバイスでさえファイルにしてしまったことなども統一病の一種でしょう。

むしろ言語の核やライブラリのコード量が小さくなる方を優先します。

OSを無視した統一環境を用意しようと考えません。

ライブラリ:

Hardwareを触ることはいとわない。

OSにさわれる完全な方法を用意する。

Cのコードをプラグインとして利用できる方法を提供する。

しかしOS independentなライブラリもコードが大きくならない範囲で行う。

ライブラリ演算子

Σ
forall
∂
a= { 0  (x<1)
	 { 1 (else)

文法の変わったところ

積に演算子が必要ない。オペレータ積ができる。括弧のないオペレータ。
行末に;はない。
f(x)=x+1のような関数定義ができる。

検討中の事項

二項以上の演算子の後付定義、既存文法の動的変更

リストへの要素追加の文法

list<-a
a->list
listからの引き抜きは?

メッセージ式 "|"

aWindow | create | name "figure" | show_self

ポインタ(参照)とコピーの抑制、ガベージコレクション

さしあたり、ポインタは用意しない。Cでサブルーチンへ渡すデータのコピーの抑制の為に使うようなポインタの使い方はインタープリタ/コンパイラに最適化として委任される。

ユーザレベルでのポインタは用意されない。処理系が面倒を見ているポインタをユーザに解放したらリークを始め幾らでも深刻な問題が発生するので、これは一切公開されない。

ポインタ変数の導入は本質的にtracing ガベージコレクションの実装まで行かずにはすまされない。


2003年4月作成
最上 嗣生
| Home |
e-mailはmogami@brain.riken.jpヘ