シフト通訳を書く
編集:あなたの一部が疑ったように、公式インタープリターにバグがありました:の構成の順序.が逆になりました。私は2つのバージョンのインタープリターを持っていて、ここでは間違ったバージョンを使用しました。例は、この誤ったバージョン用にも書かれています。リポジトリのインタープリターと以下の例を修正しました。の説明>も少しあいまいだったので修正しました。また、時間がかかることをお詫びし、実生活に巻き込まれました。 EDIT2:私のインタプリタの実装にはバグがあり.、例に反映されていました(未定義の動作に依存していました)。この問題は修正されました。 前書き Shiftは、数年前に作成した難解な関数型プログラミング言語ですが、今日公開されました。スタックベースですが、Haskellのような自動カレーも備えています。 仕様 Shiftには2つのデータ型があります。 任意の正のアリティ(入力数)を持ち、出力のリストを返す関数。たとえば、唯一の入力を複製する関数にはアリティ1があり、2つの入力を交換する関数にはアリティ2があります。 ブランクはすべて同一であり、機能以外の目的はありません。 シフトプログラムは0個以上のコマンドで構成され、各コマンドは単一のASCII文字です。合計で8つのコマンドがあります。 !(適用)スタックから関数fと値をポップしx、に適用fしxます。場合はfアリティ1を持って、リストにはf(x)、スタックの先頭に追加されます。アリティがあるn > 1場合、新しい(n-1)-ary関数gがスタックにプッシュされます。入力を受け取り、戻ります。x1,x2,...,xn-1f(x,x1,x2,...,xn-1) ?(blank)スタックに空白をプッシュします。 +(clone)は、入力を複製する単項関数をスタックにプッシュします。任意の値xがにマップされ[x,x]ます。 >(shift)はn-ary関数を受け取る単項関数をスタックにプッシュし、最初の引数を無視し、残りの引数を呼び出し、結果の前にタックfする(n+1)-ary関数gを返します。たとえば、は入力を受け取ってを返すバイナリ関数です。xfxshift(clone)a,b[a,b,b] /(fork)は、3つの入力を受け取る3項関数をスタックにプッシュし、が空白の場合はそれ以外a,b,cを返します。[b]a[c] $(呼び出し)は、関数fと値をポップするバイナリ関数をスタックにプッシュし、そうxするのfとxまったく同じように適用され!ます。 .(鎖)スタックにプッシュ二つの機能をポップバイナリ関数fとgし、その組成を返す:関数hと同じアリティを有しf、通常はその入力をとるには、適用されるfそれらにし、次いで完全適用g結果に(コールそのアリティが指示する回数だけ)、の出力からの未使用のアイテムはの結果にf残りhます。たとえば、それfが2番目の引数を複製するバイナリ関数で、gがcallであるとします。スタックが含まれている場合は[f,g,a,b,c]、私たちが行う.!!、それが含まれています[chain(f,g),a,b,c]。!!次に行う場合、f最初にに適用されa,b、[a,b,b]、それからgその最初の2つの要素に適用され[a(b),b]ます[a(b),b,c]。そのアリティは2であるため、生成し、スタックは最終的にになります。 @(言う)単純に入力を返す単項関数をプッシュし、0それが空白1か、関数かを出力します。 !値をスタックにプッシュする以外のすべてのコマンドは、入力を実行する方法がなく、何かを出力する唯一の方法はを使用すること@です。プログラムは、コマンドを1つずつ評価し、「say」が呼び出されるたびに0sまたは1sを出力して終了することによって解釈されます。ここで説明されていない動作(空白の適用、長さ0または1のスタックの適用、空白での「チェーン」の呼び出しなど)は定義されていません。インタープリターがクラッシュしたり、警告なしに失敗したり、入力を要求したりする場合があります。 タスク あなたの仕事はシフトの通訳を書くことです。STDIN、コマンドライン、または関数の引数から解釈されるShiftプログラムを取得し、STDOUTに出力するか、0sおよび1sの結果の出力(おそらく無限)を返す必要があります。関数を作成する場合、何らかの方法(Pythonのジェネレーター、Haskellの遅延リストなど)で無限長の出力にアクセスできる必要があります。または、別の入力である数値を受け取り、それよりも長い場合はn少なくともn出力の文字を返すことができますn。 最も低いバイト数が優先され、標準の抜け穴は許可されません。 テストケース このシフトプログラムは次のように出力します01。 ?@!@@! 左から:空白を押し、「発言」を押してから、発言を空白に適用します。これは出力します0。次に、sayを 2回押して、2番目の発言を最初の発言に適用します。これは出力します1。 このプログラムは永久にループし、出力を生成しません。 $+.!!+!! プッシュ呼び出しとクローンを作成し、それらにチェーンを適用します(チェーンはバイナリ関数である!ため、2つのが必要です)。これで、スタックには1つの引数を取り、それを複製して、2番目の最初のコピーを呼び出す関数が含まれています。では、この関数を複製してそれ自体を呼び出します。+!! このプログラムは印刷します0010: ?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!! 空白を押して言ってください。次に、2番目の引数をコピーするバイナリ関数を作成してからb、最初の引数をコピーしaてそれ自体で作成し、次にそのコピーをのコピーに適用してb、を返し[a(a(b)),b]ます。適用言うと、ブランク、その後、適用発言権をスタック上に残りの二つの要素に。 このプログラムは印刷し0ます。!!!追加したそれぞれについて、追加のを出力し0ます。 ?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!! 空白を押して言ってください。次に、f,g,x入力としてを返す3項関数を作成します[f,f,g,g(x)]。その関数のクローンを作成し、それ自体、たとえば、および空白に適用します。このアプリケーションはスタックを変更しないため、必要な回数だけ関数を再度適用できます。 このプログラムは無限シーケンスを出力します。s 001011011101111...の数は1常に1ずつ増加します。 @?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!! リポジトリには注釈付きのバージョンが含まれています。