概して、私は長い間、どの言語で書くかを気にしません(私は1989年からプログラミングをしており、この間に多くの言語を試しました)。 しかし...すべて同じで、他の言語よりもいくつかの言語で作業する方が快適です-ここでのポイントは、一部の言語が他の言語よりも優れているということではなく、異なる言語が異なる思考スタイルに適しているということです。
PerlからLimboへの移行は非常に対照的です。 言語はまったく異なります。Perlはまったく入力されませんが、Limboは強く入力されます。 Perlは通常のスレッドサポートを持たず、多重化によって非同期を実現する必要があります。Limbo-マルチスレッドプログラムを書くことをほぼ強制します( Rob Pikeのプレゼンテーションを見た場合、素数のマルチスレッド検索のクールな例がありました)。 など それにもかかわらず、私はLimboが本当に好きで、すぐにLimboで作業コードを書き始めました。
私はCをあまりよく覚えていませんが、Cとの違いの観点からLimboを正確に説明しようとします-ほとんどの聴衆にとっては簡単だと思います(PHPについては一言ではありません!:))。
一般的な情報
Cとの構文の類似性、バイトコードの移植性の高さ、並列プログラミングのシャープ化、モジュールの動的なロード/アンロード、実行時を含む配列のタイプと境界のチェック、ガベージコレクターの存在など、Limboの機能については、既に説明しました。
また、Limbo用に多数のさまざまなライブラリ(Infernoに含まれています)が記述されているため、グラフィックス、数学、データベースなどの操作が簡単になります。
例を理解するには、変数の型宣言がPascalスタイルで行われることを追加する価値があります。
-
:
-発表 -
=
-割り当て -
:=
-同時割り当てによる宣言、タイプは割り当てられたオブジェクトのタイプによって決定されます
データ型
通常の数値型、構造、およびユニオンに加えて、Limboは文字列と、リスト、配列、タプル、パイプなどのいくつかのより具体的なデータ型をサポートしています。 (特別なタイプの「モジュール」もあります。インターフェースについて説明したときに以前に言及しましたが、言語機能の観点からは重要ではありません。)これらのデータ型はすべてファーストクラスの変数です。 変数に保存したり、チャネルを介して送信したりできます。
通常の数値型は相互に変換できます。また、文字列も数値に変換でき、その逆も可能です。 ただし、すべての変換は明示的に指定する必要があり、暗黙的な型変換はありません。
行
string
はバイト配列に変換でき、その逆も可能です。
さらに、文字列はスライスをサポートしています。
my_string[5:15]
ように、特定の文字または文字のシーケンスを参照できます。
リスト
list
は、スタックのような操作に最適化された1つのタイプの要素のシーケンスです(リストの先頭に要素を追加し、リストの最初の要素を取得し、リストの残りを取得します(最初の要素を除く))
リストを操作するための3つの演算子があります。
-
::
-新しいリストを作成します。左のオペランドは1つの要素で、右のオペランドは同じタイプの要素のリストです -
hd
リスト自体を変更せずにリストの最初の要素を返します -
tl
たリストの2番目以降の要素で構成されるリストを返します。 最初の要素を「噛む」
例:
l : list of int; l = 10 :: 20 :: 30 :: nil; # 3- l = 5 :: l; # i := hd l; # int 5, l2 := tl l; # 10 :: 20 :: 30 :: nil l2 = tl l2; #
リストの操作がこのような操作によって制限される理由は明らかです。効率的に実装するのは非常に簡単で、そのようなリストは非常に迅速に機能します。 そして実際、非常に多くの場合、既存の機能に完全に適合する構造で作業する必要があります。
配列
array
には、同じタイプの固定数の要素が含まれます。
配列のサイズは、変数の型を宣言するときではなく、作成/初期化するときに示されます-つまり 配列はいつでも動的に作成できます(配列の必要なサイズがわかったとき)。
実際、Limboにはメモリを動的に割り当てる方法は2つしかありません。変数を使用して必要なサイズを指定して配列を作成し、リストの先頭に新しい要素を追加します。
当然、配列もスライスをサポートしています。
タプル(タプル)
tuple
は、任意のタイプの2つ以上の要素のリストのようなものです。 そして、これは単なるリストではなく、他のデータ型と同じデータ型です。タプルの型自体は、実際には要素の型と含まれる順序によって決まります。 例:
i_s : (int, string); i_s = (5, "five"); # i_r_s_s (int, real, string, string) i_r_s_s := (5, 0.5, "five", "comment");
さらに、タプルを通常の変数のリストに割り当てることにより、そのコンポーネントに「逆アセンブル」できます。
# i int s string # 5 "five" (i, s) := i_s;
ところで、Limboの2つの変数の値の交換は次のように行われます。
(i, j) = (j, i);
チャンネル
チャネル(
chan
)を使用すると、特定のタイプのオブジェクトをアトミックに渡すことにより、ローカルプロセス間でIPCを編成できます。
チャネルの読み取り/書き込みはブロッキング操作です。 読み取り/書き込みステートメントは矢印のように見えます。
c := chan of int; # c <-= 10; # i := <-c; # int <-c; # c = nil; #
チャネルはバッファリングされます(バッファのサイズは配列のサイズと同じ方法で指定します)。 バッファリングされたチャネルへの書き込みは、バッファがいっぱいになるまでブロックされません。 バッファはFIFOキューとして機能します。
チャネルを多重化する場合、Limboには2つの方法があります。チャネルの配列から読み取るか、特別な演算子altを使用してチャネルを選択できます。
alt { i := <-inchan => sys->print("received: %d\n", i); outchan <-= "message" => sys->print("message sent\n"); }
実際、チャネルはLimboで唯一のIPC方式であり、データ転送とストリームの同期の両方に使用されます。一般的に、すべてのミューテックス、セマフォ、共有メモリなどの完全な代替品です...
彼らのパフォーマンスに関しては...チャンネルを介して何かを送信するとき、メモリ内のアドレスは単に送信されます、すなわち コピーは実際には行われず、すべてが飛ぶだけです。
複合タイプ
cool : array of chan of (int, list of string);
これは、intと文字列のリストで構成されるタプルが送信されるチャネルを格納する配列です。 配列のサイズはここでは決定されず、実行時に配列が初期化されるときに設定されます。
Unicode
Limboは、I / OにUTF8を使用し、メモリ内の文字列を表すためにUTF16を使用します。
つまり、たとえば、ディスクからモジュールのソースコードを読み取るときに、UTF8をコメント、行、およびシンボル定数で使用できます。
バイトの
array of byte
)があり、それが文字列に変換される場合、配列のバイトはUTF8として処理され、UTF16の文字列に変換されます。 また、文字列をバイト配列に変換すると、逆が変換され、UTF8が配列に含まれます。
機能
関数は、パラメーターを関数リンクに渡すことができます。
OOP
オブジェクトはデータ型構造(
adt
)を介してシミュレートされ、その要素は通常のデータ型に加えて関数になります。 実際、これはもちろん、非常に去勢されたOOPです-継承はなく、ロボットが住みません。 (c):)しかし、私は嘘をついています。 多態性です。 しかし、少し奇妙です。C++のテンプレートに似ています 。
スレッド
特定の関数を別のスレッドで実行するために、Limboは組み込みのspawn演算子を使用します。
エラーと例外
例外サポートは、標準の文字列型とカスタム型の両方で利用できます。 残念ながら、ほとんどのシステムおよびライブラリー関数は、例外の代わりにtuple:
(errcode, result)
使用してエラーを返します。 もちろん、タプルは-1の結果の形式でエラー情報をPOSIXから返すことに関して大きな前進ですが、...代わりに例外を使用したいと思います。
参照資料
まあ、スナックのために、 ロシア語でリンボの完全な説明 。 実際、これはLimboによる英語ドックの約99.9%完全なリテールであり、それ以外の場合は構造化されています(Perlプログラマーとして、データ型とその操作に集中したかったのですが、そうでなければ、型付き言語から抜け出すことができました)。