プログラミング言語Mercuryのゲームライフ

プログラミング言語Mercuryの実験の一環として、また最近繰り返し取り上げられているゲームのテーマの印象の下で、Life( 1、2、3 )は、この興味深いプログラミング言語で実装を書きたいと考えていました。



水銀についての簡単な説明です。 この関数論理プログラミング言語は、プロローグの改善として考案されました。 改善点は、プロローグに静的型付けを導入することです(および決定論の体制を宣言します)。 その結果、コンパイラは効果的な実行可能コードを作成する機会が増え、コンパイル段階での制御が強化されます。 プロローグ愛好家はおそらく冗談を知っています:

Q:電球を交換するには何人のPrologプログラマーが必要ですか?

A:間違っています。



プロローグの領域では、 Visual Prologは入力ユーザー向けの堅実なニッチです 。 しかし、Visual PrologとMercuryのアプローチは非常に異なることに注意してください。



VIPキャンペーンはより保守的で、水星はより過激です。 たとえば、アサート/リトラクト、障害駆動ループなど、古典的なプロローグのすべての必須機能は水銀から投げ出され、I / Oを操作する方法はHaskellの方法に似ています。出力は、この関数を呼び出す前と後の外界の状態を記述するWorldInとWorldOutの2つの追加変数を受け入れる必要があります。 これら2つの変数は、2つの連続した関数呼び出し間のパラメトリックな関係を指定するために使用され、コンパイラーがそれらを再配置することを防ぎます。 このような依存関係がない場合、コンパイラーは、結果のプログラムを最適化するために、関数/述部の呼び出しを自由にシャッフルできます。 対照的に、VIP開発者は必須の機能を削除するだけでなく、Prologの実装にOOPを追加しました。



一般的に言っておくべきことはたくさんありますが、コードに移りましょう。 (必要に応じて、Mercuryトピックに関する追加情報を、 公式Webサイト 、またはこのロシア語のWebサイトで見つけることができます)。



実装は、実際に次のYouTubeビデオに示されているAPLソリューションアプローチに基づいています。

1行のAPLコードでのゲームライフ



PrologとErlangの専門家は、Mercuryの構文を非常によく知っていると確信しています。



:- module life. :- interface. :- import_module io. :- pred main(io, io). :- mode main(di, uo) is det. :- implementation. :- import_module int, list, require. :- type row == list(int). :- type grid == list(row). :- type sign ---> sum; mul; or_. :- type lr ---> left; right; no. :- type ud ---> up; down; no. eq([R | RR], N) = [eq_row(R, N) | eq(RR, N)]. eq([], _) = []. eq_row([H|T], N) = [(H=N->1;0) | eq_row(T,N)]. eq_row([],_) = []. sum(M1, M2) = R :- R1 = agg(M1, M2, sum) -> R = R1 ; error("can't sum"). or(M1, M2) = R :- R1 = agg(M1, M2, or_) -> R = R1 ; error("can't or"). mul(M1, M2) = R :- R1 = agg(M1, M2, mul) -> R = R1 ; error("can't mul"). sum_lst(L) = R :- ( L = [M1,M2|MM] -> R = sum_lst([sum(M1,M2)|MM]) ; L=[M] -> R = M ; error("sum_lst") ). :-func agg(grid, grid, sign) = grid is semidet. agg([R1 | RR1], [R2 | RR2], Sign) = [agg_rows(R1, R2, Sign) | agg(RR1, RR2, Sign)]. agg([], [], _) = []. :-func agg_rows(row, row, sign) = row is semidet. agg_rows([E1 | EE1], [E2 | EE2], Sign) = [agg_elts(E1, E2, Sign) | agg_rows(EE1, EE2, Sign)]. agg_rows([], [], _) = []. agg_elts(E1, E2, sum) = E1 + E2. agg_elts(E1, E2, mul) = E1 * E2. agg_elts(E1, E2, or_) = E1 \/ E2. hor([H | T], LR) = [hor_row(H, LR) | hor(T, LR)]. hor([], _) = []. head_det(L) = E :- ( L = [], error("empty list") ; L=[E1|_], E = E1 ). gen(T, N) = R :- ( N=0 -> R = [] ; R = [T|gen(T,N-1)] ). vert(M, up) = [zeros(M) | without_last(M)]. vert(M, down) = without_first(M) ++ [zeros(M)]. vert(M, no) = M. zeros(M) = gen(0, length(head_det(M))). without_first(L) = R :- ( L = [], error("without_first fail") ; L=[_ | T], R=T ). without_last(L) = R :- ( L=[], error("without_last fail") ; L=[_], R=[] ; L=[H,H1|T], R=[H|without_last([H1|T])] ). hor_row(L, left) = [0 | without_last(L)]. hor_row(L, right) = without_first(L) ++ [0]. hor_row(L, no) = L. :- func move(grid, ud, lr) = grid. move(M, UD, LR) = hor(vert(M, UD), LR). neighbours(M) = sum_lst([ move(M, up, left), move(M, up, no), move(M, up, right), move(M, no, left), move(M, no, no), move(M, no, right), move(M, down, left), move(M, down, no), move(M, down, right) ]). %% this is GoL algorithm %% next(M) = or(eq(MN,3), eq(mul(M,MN),4)) :- MN = neighbours(M). %% grid pretty-print %% print_m([H|T]) --> print_r(H), nl, print_m(T). print_m([]) --> []. print_r([H | T]) --> print_el(H), print_r(T). print_r([]) --> []. print_el(H) --> print(H=0->".";"#"). trace(M, N) --> ( {N = 0} -> [] ; print_m(M), nl, trace(next(M), N-1) ). m1 = [ [0,1,0,0,0,0,0,0,0,0], [0,0,1,0,0,0,0,0,0,0], [1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0] ]. main --> trace(m1,25).
      
      







実際、アルゴリズム全体の要点は次のとおりです。



 %% this is GoL algorithm %% next(M) = or(eq(MN,3), eq(mul(M,MN),4)) :- MN = neighbours(M).
      
      







つまり、セルは、自身を含む近隣の数が3であるか、自身を含む近隣の数が4であり、セルが生存している場合、次のステップで生存します。



水銀のもう1つの興味深い特徴は、haskellのように型を推測する能力です。 これを行うには、-infer-allスイッチを使用してコンパイルします。



 D:\stuff\test\mercury>mmc.bat --infer-all -s hlc.gc life.m life.m:021: Inferred :- func eq(list.list(list.list(T2)), T2) = life.m:021: list.list(list.list(int)). life.m:024: Inferred :- func eq_row(list.list(T2), T2) = list.list(int). life.m:027: Inferred :- func sum(list.list(list.list(int)), life.m:027: list.list(list.list(int))) = list.list(list.list(int)). life.m:028: Inferred :- func or(list.list(list.list(int)), life.m:028: list.list(list.list(int))) = list.list(list.list(int)). life.m:029: Inferred :- func mul(list.list(list.list(int)), life.m:029: list.list(list.list(int))) = list.list(list.list(int)). life.m:031: Inferred :- func sum_lst(list.list(list.list(list.list(int)))) = life.m:031: list.list(list.list(int)). life.m:047: Inferred :- func agg_elts(int, int, life.sign) = int. life.m:051: Inferred :- func hor(list.list(list.list(int)), life.lr) = life.m:051: list.list(list.list(int)). life.m:054: Inferred :- func head_det(list.list(T)) = T. life.m:060: Inferred :- func gen(T, int) = list.list(T). life.m:066: Inferred :- func vert(list.list(list.list(int)), life.ud) = life.m:066: list.list(list.list(int)). life.m:070: Inferred :- func zeros(list.list(list.list(T))) = list.list(int). life.m:072: Inferred :- func without_first(list.list(T)) = list.list(T). life.m:078: Inferred :- func without_last(list.list(T)) = list.list(T). life.m:086: Inferred :- func hor_row(list.list(int), life.lr) = list.list(int). life.m:093: Inferred :- func neighbours(list.list(list.list(int))) = life.m:093: list.list(list.list(int)). life.m:110: Inferred :- func next(list.list(list.list(int))) = life.m:110: list.list(list.list(int)). life.m:115: Inferred :- pred print_m(list.list(list.list(int)), io.state, life.m:115: io.state). life.m:115: Inferred :- mode print_m(in, di, uo) is det. life.m:118: Inferred :- pred print_r(list.list(int), io.state, io.state). life.m:118: Inferred :- mode print_r(in, di, uo) is det. life.m:121: Inferred :- pred print_el(int, io.state, io.state). life.m:121: Inferred :- mode print_el(in, di, uo) is det. life.m:123: Inferred :- pred trace(list.list(list.list(int)), int, io.state, life.m:123: io.state). life.m:123: Inferred :- mode trace(in, di, di, uo) is det. life.m:131: Inferred :- func m1 = list.list(list.list(int)).
      
      







(このキーがない場合、すべての署名はコードで指定する必要があります)。

さて、実際にはグライダーの進化を示す打ち上げ:



 D:\stuff\test\mercury>life.exe .#........ ..#....... ###....... .......... .......... .......... .......... .......... .......... .......... #.#....... .##....... .#........ .......... .......... .......... .......... .......... .......... ..#....... #.#....... .##....... .......... .......... .......... .......... .......... .......... .#........ ..##...... .##....... .......... .......... .......... .......... .......... .......... ..#....... ...#...... .###...... .......... .......... .......... .......... .......... .......... .......... .#.#...... ..##...... ..#....... .......... .......... .......... .......... .......... .......... ...#...... .#.#...... ..##...... .......... .......... .......... .......... .......... .......... ..#....... ...##..... ..##...... .......... .......... .......... .......... .......... .......... ...#...... ....#..... ..###..... .......... .......... .......... .......... .......... .......... .......... ..#.#..... ...##..... ...#...... .......... .......... .......... .......... .......... .......... ....#..... ..#.#..... ...##..... .......... .......... .......... .......... .......... .......... ...#...... ....##.... ...##..... .......... .......... .......... .......... .......... .......... ....#..... .....#.... ...###.... .......... .......... .......... .......... .......... .......... .......... ...#.#.... ....##.... ....#..... .......... .......... .......... .......... .......... .......... .....#.... ...#.#.... ....##.... .......... .......... .......... .......... .......... .......... ....#..... .....##... ....##.... .......... .......... .......... .......... .......... .......... .....#.... ......#... ....###... .......... .......... .......... .......... .......... .......... .......... ....#.#... .....##... .....#.... .......... .......... .......... .......... .......... .......... ......#... ....#.#... .....##... .......... .......... .......... .......... .......... .......... .....#.... ......##.. .....##... .......... .......... .......... .......... .......... .......... ......#... .......#.. .....###.. .......... .......... .......... .......... .......... .......... .......... .....#.#.. ......##.. ......#... .......... .......... .......... .......... .......... .......... .......#.. .....#.#.. ......##.. .......... .......... .......... .......... .......... .......... ......#... .......##. ......##.. .......... .......... .......... .......... .......... .......... .......#.. ........#. ......###.
      
      







おそらくそれが今日のすべてです。



その他のリンク:

  1. Windows水銀言語の配布は、 code.google.com / p / winmercuryから入手できます。
  2. このYPに関するさらに2つの例: langexplr.blogspot.com/search/label/mercury
  3. プロローグの更新: 1、2
  4. kとq(APLの子孫、 kx.com )でのゲームライフの2つのワンライナー: kq




All Articles