チューリング完全性のための最少(明確な)文字


107

概要:

どんな言語でも、あなたの言語がチューリング完全であるための一意の文字の最小量は何ですか?

チャレンジ:

任意の言語で、言語をチューリング完全にすることができる最小の文字のサブセットを見つけます。キャラクターのセットを何度でも再利用できます。


例:

  • JavaScript:+!()[]http://www.jsfuck.com

  • Brainfuck:(+<>[]ラッピングセルサイズを想定)

  • Python 2:(()+1cehrxなどのスクリプトから作成exec(chr(1+1+1)+chr(1))

得点:

このチャレンジは、バイトではなく文字でスコアリングされます。たとえば、例のスコアは6、5、および9です。


ノート:

  • この課題は、あなたの言語だけがチューリング完全であるという意味で他と異なります(必ずしも言語のすべての機能を使用できるわけではありません)。

  • 可能ですが、使用するキャラクターを減らすことなく回答を投稿しないでください。例:8文字のBrainfuck(他のすべての文字はデフォルトでコメントであるため)

  • サブセットがチューリング完全である理由について、少なくとも簡単な説明を提供する必要があります。


90
単項、1文字。ため息
デニス

4
@Dennis興味深い数論問題のための組み込みのJellyまたは05AB1Eとそれほど違いはありません。この課題は、まだターピット用に設計されていない言語では、面白くて自明ではない最適化問題のようです。
マーティンエンダー

7
@MartinEnder私は、JavaやCのような言語での回答を見て、特に興味があると思います
ジュリアンLachniet

9
ソリューションが言語のすべての有効な文字であるエソランにソリューションを投稿しないでください。それは興味をそそるまたは巧妙ではありません。
パベル

20
@Pavel面白くない、または賢いということは、それが支持されるべきではないということを意味するかもしれませんが、投稿されるべきではないことは確かです。
デニス

回答:


77

Haskell、4文字

()=;

では()=、我々はS、K及びIのいずれかで区切る必要があります定義を定義することができます;またはNLを。

(==)Sとして定義します(2行目はより読みやすいバージョンを示しています)。

((=====)==(======))(=======)=(=====)(=======)((======)(=======))
( a     == b      ) c       = a      c       ( b       c       )

(===) Kとして:

(=====)===(======)=(=====)
 a     === b      = a

そして(====)私として:

(====)(=====)=(=====)
(====) a     = a 

幸いにも(==)(===)(====)、などの有効な関数/パラメータ名です。

@ ais523が指摘しているように、Haskellのような強く型付けされた言語ではSKIで十分ではないため、固定小数点コンビネーターを追加する必要があります(=====)

(=====)(======)=(======)((=====)(======))
(=====) f      = f      ((=====) f      )

17
この構造は直接機能しません。Haskellのような強く型付けされた言語では、SKIは完全なチューリングではありません。ただし、同じ手法を使用してを定義することができ、強く型付けされた言語であっても、fixSKI + fix チューリング完全です。

ああ、あなたは各プログラムの始めにそれらの定義の前に付けますか?
PyRulez

@PyRulez:はい。デフォルトでは、指定された文字セットを使用して関数を構築するのに十分であると想定しています-完全なプログラムは必要ありません。
nimi

1
(==)デフォルトの等値演算子と衝突しないように、おそらく交換する必要があります
誇りに思ってhaskeller

@proudhaskeller:はい、実際にプログラムしたい場合は、名前を変更する方が良いでしょう(==)が、上記のコードは完全なチューリングの証明にすぎません。
nimi

61

JavaScript(ES6)、5文字

これを支援してくれた@ETHproductionsと@ATacoに感謝します。これはグループプロジェクトであり、元のアイデアは私のものでしたが、詳細の多くは彼らのものです。このJavaScriptサブセットがここで開発さたチャットディスカッションを参照してください。

[]+=`

どのJavascriptプログラムでも文字([]()+!)で記述できることはかなり確立されていますが、5文字では十分ではありません。ただし、これは任意のJavaScriptの作成に関する課題ではありません。チューリング完全言語を書くことについての挑戦であり、チューリング完全言語はDOMやインタラクティブなI / Oにアクセスする必要がないという事実を利用して、必要な機能をすべて備えたプログラムを書くことができることがわかります、evalまたは同等のものを実行する能力がなくても。

基本的なブートストラップ

JavaScriptは型に対して非常に柔軟です。たとえば、[]は空の配列ですが+[]、0であり[]+[]、ヌル文字列です。特に、この文字セットで0を生成できるという事実により、グループ化のための括弧の効果をシミュレートすることができます。(a)と書くことができます[a][+[]]。この種のトリックを使用して、次のもののみを使用してさまざまなキャラクターを作成できます+[]

  • [][+[]]is undefined(空の配列の最初の要素); そう
  • []+[][+[]]is "undefined"(の文字列化undefined); そう
  • [[]+[][+[]]]is ["undefined"](それを配列にラップする); そう
  • [[]+[][+[]]][+[]]is "undefined"(その最初の要素); そう
  • [[]+[][+[]]][+[]][+[]]is "u"(その最初の文字)。

uは作成するのが最も簡単なキャラクターの1つですが、同様の手法を使用して他のキャラクターの範囲を作成できます。同じリンクは、以前のように私たちとアクセス可能な文字の次のリストが表示されます+[](これはと同じリストである+[]()除く、,それは/優先度をグループ化する以外の目的のために括弧を使用する唯一の建設だから):

0123456789acdefinotuvyIN (){}.

この一連の文字から非常に多くの有用な単語を綴ることはできません(これは文字列として生成できる一連の文字であることに注意してくださいeval。そのため、別のキャラクターが必要です。を使用=します。これは後で役立つので、とりあえず、比較演算子のスペルに使用します==。これにより、文字列化してインデックスを付けることができるfalseand を生成しtrue、すぐlrsに文字列に含めることができる文字を追加できます。

断然、これが私たちが綴ることができる最も重要な言葉は、私たちが前にできなかったことですconstructor。JavaScriptには、次のようなプロパティアクセス構文があります。

object.property

ただし、次のように書くこともできます。

object["property"]

文字列リテラルではなく、計算されたプロパティを使用することを妨げるものは何もありません。したがって、私たちは

object["c"+"o"+"n"+"s"+"t"+"r"+"u"+"c"+"t"+"o"+"r"]

(上記のように生成された文字で、コードはすぐに非常に長くなります!); これはと同等でobject.constructor、任意のオブジェクトのコンストラクターにアクセスできます。

これを使ってできるいくつかのトリックがあります。ありふれたものから素晴らしいものまで:

  • オブジェクトのコンストラクターは関数です。特に、名前があり、その名前は関数の文字列化の一部です。したがって、たとえば、[[]+[]][+[]]["constructor"]名前がStringである文字列のコンストラクターを取得し、それを文字列化して大文字を取得することができSます。これにより、アルファベットが少し拡張され、後で新しい文字の一部が必要になります。
  • すべての配列には同じコンストラクターがあります。[]["constructor"] == []["constructor"]true[] == []falseである)とは異なります。これはマイナーに見えるかもしれませんが、値を永続的に保存する方法を提供するため、非常に重要です。コンストラクターでランダムプロパティを設定し、後でそれを読み取ることができます。(これは、我々が使用している理由の一つである=、特になく、生成するための他の方法のいずれかtruefalse。)例えば、我々は評価でき[[]["constructor"]["a"]=[]]読ま後に、そして[]["constructor"]["a"]、私たちはそこに格納されている同じ配列を取り戻します。

    これは、チューリング完全性に必要な要件の1つ、つまり任意の量のデータを保存および取得する機能を満たします。2要素配列を使用してコンスセルを作成し、コンストラクタープロパティストレージから値を取得してから、それらの値のいずれかの場所に格納し直して、メモリ内に任意の大きなデータ構造を構築できます。このストレージにアクセスするには、逆の操作を行います。必要なデータにアクセスできるようになるまで、データを1つずつ破棄します。読み取りは破壊的ですが、データを保存する場所が複数あるため、それは許容されます。読み取り中にコピーして、元の場所にコピーを戻すことができます。

  • これにより、関数のコンストラクターにアクセスできます(限られたアルファベットでアクセスできる関数がたくさんあります。[]["find"]つまり、Array.findは最も簡単にアクセスできますが、他にもあります)。なぜそれが役に立つのですか?まあ、実際にコンストラクタの意図された目的のためにそれを使用し、関数を構築することができます!残念ながら、この文字セットでは、計算された文字列をFunctionコンストラクターに渡すことはできません。ただし、を使用する`と、文字列リテラル(例[]["find"]["constructor"]`function body goes here`)を渡すことができます。これは、実行時にすべての動作で関数型のカスタム値を定義できることを意味します[]+=。ただし、その動作を完全に使用して表現できる限りです。たとえば[]["find"]["constructor"]`[]+[]`、null文字列を計算して破棄し、終了するかなり退屈な関数です。それ関数は有用ではありませんが、より複雑な関数は有用です。関数はパラメーターや戻り値を取得できませんが、コンストラクタープロパティストレージを使用して1つの関数から別の関数に通信できるため、実際には問題になりません。もう1つの制限は`、関数の本体では使用できないことです。

    これで、カスタム関数を定義できますが、この時点で私たちを妨げているのは、それらを呼び出すのが難しいことです。プログラムのトップレベルでは、を使用して関数``を呼び出すことができますが、トップレベルからのみ関数を呼び出すことができるため、どのようなループも実行できません。むしろ、お互いを呼び出すことができる関数が必要です。

    かなり気の利いたトリックでこれを達成します。S以前に生成した資本を覚えていますか?それでスペルができます"toString"。私たちはそれを呼ぶつもりはありません。[]それらを追加することで、文字列に変換できます。むしろ、私たちはそれを置き換えるつもりです。コンストラクターストレージを使用して、永続する永続配列を定義できます。その後、作成した関数を配列のtoStringメソッドに割り当てることができます。これらの割り当ても保持されます。今、私たちがしなければならないのは+[]、配列上で単純であり、突然、カスタム定義関数が実行されます。これは、文字を使用できることを意味します+=[]関数を呼び出すため、私たちの関数はお互いを呼び出すことができます-または自分自身。これにより再帰が発生し、ループが発生し、突然チューリング完全性に必要なものがすべて揃います。

チューリング完全性を提供する一連の機能の概要と、それらの実装方法を次に示します。

  • 無制限のストレージ:コンストラクターストレージのネストされた配列
  • 制御フロー:を使用ifして実装され、再帰:
    • if:ブール値を数値に変換し、2要素配列にインデックスを付けます。1つの要素がthen文字列化されている場合にケースの関数を実行し、もう1つの要素が文字列化されているelse場合にケースの関数を実行する
    • 再帰:コンストラクターストレージの適切な要素を文字列化する
  • コマンド・シーケンシング[a]+[b]+[c]評価しab、およびc左から右への(少なくとも私がチェックしたブラウザ上)

残念ながら、これはかなり実用的ではありません。文字列を最初の原則から文字ごとに構築する必要があるため、非常に大きいだけでなく、I / Oを実行する方法もありません(チューリング完全である必要はありません)。ただし、終了した場合は、少なくともコンストラクタストレージを後で手動で調べることができるため、プログラムをデバッグすることは不可能ではなく、完全に非通信的ではありません。


16
これに名前が付けられていない場合は、J5h * tをお勧めします。
CalculatorFeline

1
良いプログラム例は何でしょうか?プライムテスト?こんにちは世界?
CalculatorFeline

3
私は、これはそうであるワット良いホラー映画のようなおいしい答えは、...。
反時計回りに

4
Angular1のtoString()依存性注入への使用は、関数を使用する最も創造的な方法だと思いました。今、私は考えを変えました。
サニーパン

1
ここでは例を示します。pastebin.com/QGbjmB5Yは
Esolangingフルーツ

55

単項、1文字

0

文字の選択は実際には重要ではありません。プログラムの長さは、変換先のBrainfuckプログラムを定義します。仕様では0文字が必要ですが、ほとんどのトランスパイラーはこれをチェックしていないようです。


44
おそらく、仕様を検証するトランスパイラーの問題を解決する必要があります。これは非常に深刻な問題です。
キャプテンマン

5
びっくりしました。冗談かどうかを判断するには20分かかりました。
ピーターA.シュナイダー

3
@ PeterA.Schneider一部のグーグルは、理論的に誰かがこのようにクインを実際に実装したことを発見しますが、0の結果の文字列はおそらく実際のコンテキストでこれまでに見た最大の数であり、実際のマシンには決して実装できませんでした。
ダレンリンガー

12
そのゼロの文字列は、実際、どんなコンテキストでもこれまでに見た中で最小の数字です。
マシュー

1
...あなたは加法単位元としてあなただけのシンボルを定義するような愚かな何かをする場合、よく、LOL:P
ダレンリンガー

37

vim、9 8 7 6文字

<C-v><esc>1@ad

次のように、任意のvimscriptプログラムをビルドして実行できます。

  1. シーケンスaa<C-v><C-v>1<esc>dd@1<esc>ddddを使用して、<C-a>in register を取得します1

  2. で挿入モードに入りa、を挿入しますa。これは、後でマクロで挿入モードに再び入るときに使用されます。

  3. 目的のvimscriptプログラムの各文字について、

    1. <C-v><C-v>1<esc>リテラルシーケンスの挿入に使用します<C-v>1

    2. 使用@1(これ<C-a><cr>最終的にはここで、<cr>インクリメントするのに必要な回数だけによる最後の行であることに何もしません)1、所望の文字のASCII値に到達するまで

    3. で挿入モードに再度入りますa

  4. 行を(末尾の改行とともに)で1レジスタに削除します<esc>dd

  5. を使用して結果をvimキーストロークとして実行し@1、その後<esc>dd、前の手順で末尾の改行で入力された行を削除します。

  6. 結果の任意のバイトシーケンスをで実行しますdd@1。aで始まる場合:、vimscriptコードとして解釈され、からの改行が原因で実行されますdd

これは最小限の文字セットだとは思いませんが、チューリング完全であることを証明するのは非常に簡単です。


2
あなたが行うことはできませんi<C-v>1<ESC>書くために<C-a>、次にddあなたが使用できるように、@1任意の番号をインクリメントすると、使用する必要がありませんになりますか<C-a>
牛は

4
うわー、この答えはすごい!+1!
DJMcMayhem

@KritixiLithosそれは少しの再構築の後に機能することになります、ありがとう!
ドアノブ

2
@ mbomb007実際...興味深い実装の詳細のため、<C-v>10\ nではなくNULを挿入します(尋ねないでください)。いずれにせよ、そう、チューリング完全性に関しては問題ではありません。
ドアノブ


33

Perl、5文字

<>^es

他のスクリプト言語と同様に、アイデアはeval任意の文字列です。ただし、文字セットには引用符や連結演算子が含まれていないため、任意の文字列を作成するのはかなり複雑になります。eval^"処理ははるかに簡単ですが、もう1つの特徴があることに注意してください。

私たちの主なツールはでs<^><CODE>ee、これはevals CODE、そしてその出力を評価します。e予想される効果で、さらに追加することができます。

を使用して文字列を取得します<>。これは、そうでない場合を除き、グロブ演算子です。最初の文字は<(そうでなければ<<演算子のように見えます)、山括弧はバランスがとれている必要があり、少なくとも1つの非文字文字がなければなりません(そうでなければ、readline演算子として解釈されます)。

これらの文字列を一緒にxoringすることにより、^B^V^S(*-/9;<>HJMOY[`\^begqstv周りのゴミを受け入れる限り、文字の任意の組み合わせを取得できます(最初の3つは制御文字です)。

たとえば、を取得したいとします"v99"。取得する方法の1つですv99"><<" ^ "e>>" ^ "see" ^ "^^^"、の制約のため、これらの文字列を表すことはできません<>。代わりに、次を使用します。

<^<<^>><>>^<^^^^^<>>^<^^^^^^e>^<^^^^^^^>^<^^^^^e>^<^^^^e^>^<e^^es>^<^ee^^>^<^<^^^^^>>^<^<>^^^^>^<^^^^^^^e>^<^^^^^^^^>

上記の結果はY9;v99;、評価されたときに、プレーンv99(つまり、ASCIIコード99の文字)と同じ結果になります。

したがって、^B^V^S(*-/9;<>HJMOY[`\^begqstv文字セット全体を使用して任意の文字列を生成し、上記のように変換してa s<><CODE>eeeeに貼り付けて実行できます。残念ながら、この文字セットはまだ非常に制限されており、連結を実行する明白な方法はありません。

しかし、幸いなことに、星が含まれています。これにより*b、文字列に評価されるように記述できます"*main::b"。次に、*b^<^B[MMH^V^SY>(^ B、^ V、および^ Sはリテラル制御文字です)が(6, $&);返され、再度評価されると、Perlの一致変数の値が返されます$&。これにより、限定された形式の連結を使用できます:を使用する前に繰り返し追加$_s<^><THINGS>e、次にs<\H*><*b^<^B[MMH^V^SY>>eeeevalに使用できます$_\H水平方向の空白以外に一致します。文字セットにないドットの代わりに使用します)。

を使用すると9-/、すべての数字を簡単に生成できます。数字v、、および連結を使用して、任意の文字を生成できます(vXXXはASCIIコードXXXの文字を生成します)。そして、それらを連結できるので、任意の文字列を生成できます。だから何でもできるように見えます。

完全な例を書いてみましょう。独自のPIDを出力するプログラムが必要だとします。自然なプログラムから始めます。

say$$

これをv表記に変換します。

s<><v115.v97.v121.v36.v36>ee

これだけを使用して書き換えます^B^V^S(*-/9;<>HJMOY[`\^begqstv(空白は読みやすくするためであり、出力には影響しません)

s<^><
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-99/-9-99/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-9/9-9/9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><999/9-9/-9-9/-9-9/-9-9/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<\H*><*b^<^B[MMH^V^SY>>eee;
>eee;

最後に、上記のプログラムをのみ<>^espastebinに変換します。残念ながら、これによりPerlがクラッシュしますがExcessively long <> operator、これは単なる技術的な制限であり、考慮に入れるべきではありません。

ふ,、それはかなりの旅でした。誰かが物事を簡単にする5つのキャラクターのセットを思い付くのを見るのは本当に面白いでしょう。

編集:少し異なるアプローチを使用することで、の長さ制限に達することを回避でき<>ます。のみを使用して完全に機能するBrainfuckインタープリター<>^esオンラインで試してみてください!。自動化されたPerlの<>^estranspiler:ペーストビン


1
なるほど。あなたのキャラクターは2つのグループに分かれているので、エンコードは2次爆発になります。1つは偶数のベース文字のxor'ingによってのみ生成され、もう1つは奇数によってのみ生成されます。それらを切り替えるたびに別のグロブを追加します。プログラムを^他のベースキャラクターと結び付けられた短い評価可能なピースに分割できる可能性はありますか?
Ørjanヨハンセン

@ØrjanJohansenうん、それを見つけるのは良い仕事だ。私は現在、解決策に取り組んでいます。
グリミー

縮小した例をTIOリンクにすることができます。オンラインで試してみてください!
Ørjanヨハンセン

7
リクエスト:この「わずかに異なるアプローチ」を説明してください
電卓

32

Python 2、7文字

exc="%\n

Python 2プログラムは、これらの7文字を使用してエンコードできます(\n改行です)。

任意の文字列の構築

%単一の文字列に置換演算子を繰り返し適用することにより、連結を実行できます。たとえば、ifの場合a=1, b=2, c=3"%d%%d%%%%d" % a % b % c文字列が返されます"123"。幸いなことに、中の文字は、exec私たちへのアクセスを提供%xし、%c基本的であるhex()chr()。を使用%cすると、文字を表す必要な数がある限り、任意の文字列を作成できます。execキーワードを使用して、この文字列をpythonコードとして実行できます。

数字を作る

比較()により01すぐにアクセスできます==。数字の連結とモジュロの組み合わせにより、ASCII 43で表す数値を作成することができ+ます。これにより、コードに必要な数値を作成できます。

それを一緒に入れて

これらの制約の下でプログラムを作成する方法を理解するのに不可欠ではないため、この説明ではいくつかの詳細を省略しました。以下は、Pythonプログラムを、これらの7文字のみを使用する機能的に同等のバージョンに変換するPython 2プログラムです。使用されている技術は、kによるアナーキーゴルフに関するこの提案に触発されています。生成されたプログラムのサイズを妥当な範囲内に保つために、いくつかの簡単なトリックも使用されます。

import sys

var = {
    43: 'e',
    'prog': 'x', # the program will be stored in this variable
    'template': 'c',
    0: 'ee',
    1: 'ex',
    2: 'ec',
    4: 'xe',
    8: 'xx',
    16: 'xc',
    32: 'ce',
    64: 'cc',
    'data': 'cx', # source program will be encoded here
}

unpacker = 'exec"".join(chr(eval(c))for c in {}.split())'.format(var['data'])

source = sys.stdin.read()
charset = sorted(list(set(source+unpacker)))
codepoints = map(ord, charset)

output = (
    # create template for joining multiple characters
    '{}="%c%%c%%%%c%%%%%%%%c"\n'.format(var['template']) +

    # create 1
    '{0}={1}=={1}\n'.format(var[1], var['template']) +

    # create 0
    '{}={}==""\n'.format(var[0], var['template']) +

    # create 3
    # store it at var[43] temporarily
    (
        'exec"{0}=%x%%x"%{2}%{2}\n' +
        'exec"{0}%%%%%%%%=%x%%x%%%%x"%{1}%{2}%{1}\n'
    ).format(var[43], var[0], var[1]) +

    # create 4
    # this step overwrites the value stored at var[0]
    (
        'exec"{1}=%x%%x"%{0}%{1}\n' +
        'exec"{1}%%%%=%x%%x"%{2}%{0}\n'
    ).format(var[43], var[0], var[1]) +

    # create 43
    'exec"{0}=%x%%x"%{1}%{0}\n'.format(var[43], var[0])
)

# create powers of 2
for i in [2, 4, 8, 16, 32, 64]:
    output += 'exec"{0}={1}%c{1}"%{2}\n'.format(var[i], var[i/2], var[43])

for i, c in enumerate(codepoints):
    # skip if already aliased
    if c in var:
        continue

    # generate a new name for this variable
    var_name = ''
    if i < 27:
        for _ in range(3):
            var_name += 'exc'[i%3]
            i /= 3
    else:
        i -= 27
        for _ in range(4):
            var_name += 'exc'[i%3]
            i /= 3
    var[c] = var_name

    # decompose code point into powers of two
    rem = c
    pows = []
    while rem:
        pows.append(rem&-rem)
        rem -= rem&-rem

    # define this variable
    front = 'exec"{}={}'.format(var[c], var[pows.pop()])
    back = '"'
    for i, p in enumerate(pows):
        front += '%'*(2**i) + 'c' + var[p]
        back += '%' + var[43]
    output += front + back + '\n'

# initialise the unpacker
output += 'exec"""{}=""\n"""\n'.format(var['prog'])
i = 0
length = len(unpacker)
while i < length:
    if (length-i) % 4 == 0:
        # concat 4 characters at a time
        w, x, y, z = [var[ord(unpacker[i+j])] for j in range(4)]
        output += 'exec"{}%c={}%%{}%%{}%%{}%%{}"%{}\n'.format(var['prog'], 
                    var['template'], w, x, y, z, var[43])
        i += 4
    else:
        output += 'exec"""{}%c="%%c"%%{}"""%{}\n'.format(var['prog'],
                    var[ord(unpacker[i])], var[43])
        i += 1

# encode source data
output += var['data'] + '="""'
output += '\n'.join(var[ord(c)] for c in source)
output += '"""\n'

# execute the program
output += 'exec"exec%c{}"%{}'.format(var['prog'], var[32])

print output

オンラインで試す


入力プログラムがすでに必要な文字セットに制限されているかどうかを確認するためのチェックを追加できます。制限されている場合は、単にcatです。
mbomb007

26

Mathematica、5 4文字

I[]

は、専用のUnicode文字です。これはFunction、名前付き引数を使用して名前のない関数のリテラルを記述するための演算子として機能します。文字はMathematicaによく似ているので、わかりやすくするためにこの回答の残りの部分ではその文字を使用します。

これらを使用して、組み合わせロジックのSKおよびIコンビネータを実装できます。

I -> II↦II
K -> II↦III↦II
S -> II↦III↦IIII↦II[IIII][III[IIII]]

これらの構文上の問題の1つは、これらのコンビネータに引数を渡そうとすると問題になる非常に低い優先順位を持つことです。通常、のCような括弧でコンビネータをラップすることでそれを修正しますが、括弧(C)はありません。しかし、我々は使用することができますIし、[]ラップするためにC、我々は後でそれを使用することができ、十分に高い優先順位を持ついくつかの他の魔法に:

I[C][[I[[]]I]]

最後に、アプリケーションの書き込みにA x y zA上記のように「括弧の」コンビネータであり、およびxyzまたは括弧に入れられてもしなくてもよい、又は大きな式であってもよい)、我々は書くことができます。

A[x][y][z]

そのため、括弧と同等の機能が実際にどのように機能するのかという疑問が残ります。私はそれを思いついた順に大まかに説明しようとします。

ですから、構文的に何かをグループ化するために持っているのは括弧[]です。括弧は、Mathematicaでは2つの方法で表示されます。関数呼び出しとしてf[x]、またはインデックス演算子としてf[[i]](これは実際には単に省略形ですPart[f, i])。特に、どちら[C][[C]]有効な構文ではありません。その前に何かが必要です。理論的には何でも構いません。I既に使用している場合はI[C]、たとえば取得できます。I単項関数ではないため(これは関数ではありません)、これは未評価のままです。

ただしC、引数xを渡そうとしたときに実際には評価されないため、再度抽出する方法が必要になります。

これは、リストだけでなくf[[i]]、任意の式fに使用できる便利な場所です。それf自体がの形式head[val1,...,valn]であると仮定すると、f[[0]]ギブズheadf[[1]]ギブズval1f[[-1]]ギブズvalnなどが続きます。したがって、1またはのいずれかを評価するため-1、を取得する必要があります。CI[C][[1]]I[C][[-1]]C

私たちはすることができます取得1、任意の未定義のシンボルなどからx、それを行うには、我々は分裂のために別の文字を必要とするだろう(x/x与え1未定義のためx)。乗算は、(原則として)追加の文字なしで実行できる唯一の算術演算であるため、-1またはを得るために乗算できる値が必要1です。これがI、私たちの識別子に私が特に選んだ理由であることになります。そのためI、それ自体で虚数単位のためのMathematicaの組み込みシンボルです。

しかし、それは最後の問題を残します。実際Iにそれ自体でどのよう乗算するのでしょうか?II単一のシンボルとして解析されるため、単に書くことはできません。a)値を変更せずに、b)新しい文字を使用せずに、これらのトークンを分離する必要があります。

魔法の最後の部分は文書化されていない動作です:(f[[]]または同等のPart[f])有効な構文であり、fそれ自体を返します。したがって、乗算Iする代わりにI、乗算I[[]]Iます。括弧を挿入すると、Mathematicaは後で新しいトークンを探し、必要に応じてI[[]]I評価し-1ます。そして、それが私たちがどのようにして終わるかI[C][[I[[]]I]]です。

使用できないことに注意してくださいI[]。これはfunctionの引数なしの呼び出しですが、前述したように関数IIはないため、これは評価されないままです。


素晴らしい答え。
パトリックスティーブンス

23

Python 2、8文字

exc'%~-0

これらの文字を使用すると、フォーマット文字列とを使用して、Pythonプログラムを翻訳/実行できますexec。チューリングの完全性のためにプログラムを翻訳できることは必須ではありませんが、これは私が知っている中で、とにかくTCにする最も少数の文字です。それがとても強力であることは単なるボーナスです。

二重引用符とゼロ以外の任意の数字も使用できます。(今、私はそれについて考えることを、1間違いなくあなたが使う可能性があるので、短いプログラムで、その結果、良いだろう111111同様に、。)

プログラムはprint次のとおりです。

exec'%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c'%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0

オンラインで試す

基本プログラムが必要です

exec''

xプログラムに追加される各文字には(char-count)が必要です。

  • % - 2**(n-1)
  • c - 1
  • - - ord(x)*2
  • ~ - ord(x)*2
  • 0 - 1

これの例外は、48の代わりに%'0'文字0に使用するなど、エンコードされたプログラムを短くするために特定の最適化/ショートカットを使用できることです-~

実用的な使用(別名ゴルフ):この戦術を使用して、追加のハンディキャップキャラクターを使用せずにこの課題を解決しました。

キャラクターリストとエンコーダープログラムのクレジット:ここ

結果のプログラムサイズの下限(最適化なし)を見つける方法については、このコメントを参照してください。

必要なバイト数が増えるO(2**n)ため、この方法はゴルフにはお勧めできません。このソースの制限を使用するウマは、めちゃくちゃ長いでしょう。


演算子の優先順位のみが実行される+場合-、またはの前に%、文字を削除できます。
mbomb007

すべてのPythonプログラムを縮小文字セットに変換できることは、チューリング完全性のために必要ではないことに注意する価値があります。execとにかく使用せずに必要な量の制御フローを取得するのは難しいと思います。
マーティンエンダー

しかし、これは技術的には完全なターニングコンプリート言語ではありません。組み込みPythonインタープリターであるTurning Complete言語のインタープリターを呼び出す機能があります。これは、たとえば、別のインタープリターに対してシェルコマンドを呼び出すことができる限り、ターニングコンプリートかどうかに関係なく、どの言語でも機能します。
mmachenry

@mmachenry Pythonは、独自のコンパイラとインタープリターを使用しています。別の別の言語を使用していません。そして、PythonでBrainfuckインタープリターが作成されたため、Turing Completeです。その知識を使用して、あなたの議論は偽です。
mbomb007

@ mbomb007いいえ私の引数は偽ではありません。Pythonは明らかにターニングコンプリート言語です。計算は、内部呼び出しに必要な任意の文字を使用してPythonからPythonインタープリターを呼び出すことによって行われます。プログラムを指定する言語は、プログラミング言語ではなく、単なるエンコードです。これを使用すると、文字0と1を使用してソースファイルをバイナリとして表示することで、文字通りすべてのプログラミング言語をチューリング完了にするのは簡単です。しかし、質問の精神は、実際の言語の構文サブセットを見つけることです。
mmachenry

23

C(移植不可)、24 18 13文字

aimn[]={};,1+

これは、フォームのすべてのプログラムをカバーします

main[]={<sequence of constants>};

...ここで、一連の定数(1 + 1 + 1 ...形式)には、プログラムのマシンコード表現が含まれます。これは、環境ですべてのメモリセグメントの実行が許可されていることを前提としています(tcc [ありがとう@Dennis!]およびNXビットのない一部のマシンでは明らかです)。それ以外の場合、LinuxおよびOSXの場合はキーワードを先頭constに追加する必要があり、Windowsの場合は#pragmaセグメントを実行可能として明示的にマークすることを追加する必要があります。

例として、上記のスタイルで記述された次のプログラムは、Hello, World!Linuxおよびx86およびx86_64上のOSXで印刷されます。

main[]={111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+11111+11111+11111+11111+11111+11111+11111+11111+111+11+11+11+11+11+11+1+1,1111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+11111+1111+1111+1111+111+111+111+111+111+111,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+111111+111111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1+1+1,111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+111+11+11+11+11+11+11+11+1,1111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+1111+1111+1111+111+11+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+1+1+1+1+1+1+1,1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1,1111111111+111111111+111111111+111111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+1+1+1+1+1+1,111111+111111+11111+11111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+11+11+11+11+11+11+11+11+11+11,11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+11+11+11+11+11+11+11+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+11+11+11+1,111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+11+11+1+1+1+1+1,11111+11111+11111+11111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+1+1+1+1+1};

オンラインでお試しください!


2
@GB:少なくともx86マシンコードでのゼロの使用はかなり簡単です(それほど重要な命令ではありません)。特に、4バイトのゼロバイトが連続している場合にのみ問題が発生するためです。

2
32ビットのintを持つマシンで@GB0==1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+11+11+11+11+11+11+11+1
ceilingcat

3
tccを使用すると、consttio.run/nexus/...
デニス・

8
@GB私はちょうど0の短い表現が1==11
天井猫

3
@ wizzwizz4、それはどんな場合でも純粋なCではなく、チューリングを完全にするどんな意味でもありません。Cのセマンティクスは何もありません。とにかくコンパイラーと実行環境の詳細に依存して実行可能なものを取得しているため、任意の名前のエントリーポイントを許可することもできます。
ジョンボリンジャー

20

網膜、6文字

$%`{¶

改行(0x0A)も同様です。

一方で、私はそれをこれほど低くすることができたことに驚いています。一方、を含めることに非常に不満です。それぞれ、$`{2つのあるいは3の目的のために再利用されるが、 一緒に一つだけの目的を果たします。それは彼らをむしろ無駄に思わせ、アプローチの優雅さをわずかに破壊します。この構造に打ち勝つ方法があることを願っています。

証拠に。上記の文字を使用して、サイクリックタグシステムをRetina に変換する簡単な方法を説明します。

まず、andの代わりにandをバイナリアルファベットに使用`します。これらは正規表現でエスケープする必要がないため便利ですが、Retinaまたは置換構文で意味を持ちます。for とfor を使用していますが、この選択は任意です。さらに、最後の文字を操作するとandの代わりにandを使用して文字の再利用を最大化できるため、メモリ内の文字列(およびプロダクション)を逆にします。{01`0{1$$`^$'

最初の単語がで示されSith(逆)生成が呼び出される場合、結果のプログラムは次のようになります。pi


S
{`

{$
¶p1$%``
``$

{$
¶p2$%``
``$

{$
¶p3$%``
``$

...

この構造は、プロダクションが適用されるたびにメモリ内で必然的に成長し、終了することはありません。実際、循環タグシステムが終了する時点(作業文字列が空になるとき)で、結果のRetinaプログラムの動作は基本的に未定義。

プログラムの機能を見てみましょう。


S

作業文字列を最初の単語に初期化することから始めます。

{`

これは、結果の文字列の変更に失敗するまで実行されるプログラムの残りの部分をラップします(ナイーブな組み込みの無限ループ検出は無料です...)。そこにある2つのラインフィードは必ずしも必要ではありませんが、個々のプロダクションからループをより明確に分離します。プログラムの残りは各プロダクションを通過し、ループのために、それらを効果的に繰り返し繰り返し処理しています。

各プロダクションは2段階で処理されます。最初に、先頭(またはこの場合は末尾)シンボルが{であるケースを扱います。この場合、プロダクションを使用します。

{$
¶pi$%``

正規表現は、文字列がで終わる場合にのみ一致し{ます。その場合、次のように置き換えます。

  • 改行()。作業文字列の最後の行のみを操作するため、これまでの作業文字列は事実上破棄されます(これが、プログラムのメモリ使用量が増え続ける理由です)。
  • 現在のプロダクション()。これを作業文字列の先頭に追加します(サイクリックタグシステムが追加する場所)。pi
  • 前の残りの作業文字列($%`)。これが、:を挿入する必要がある理由$%`です。マッチの残りすべてを選択しますが、同じ行のみです。したがって、これは以前のプロダクションで残されたすべてのジャンクを見ることはできません。このトリックは、私たちはで何かを一致させることができます最後に何かを挿入する作業列の先頭にのようなものを使用することなく、作業列の(.+)$1大幅に私たちが必要とする文字の数を爆破ことになります。
  • 単一のバックティック(`)。これは、効果的に置き換えます{1私たちはと一致-symbol) `0次の段階は、我々はすでに現在の生産を処理したかどうかを知る必要がありませんように-symbolを)。

各プロダクションの2番目の部分は、プロダクションがスキップされる些細なケースです。

``$

末尾のを削除するだけ `です。`最初の行に2つが必要な理由は、Retinaが最初のバックティックを構成と正規表現の間の仕切りと見なすためです。これは単純に空の構成を提供するため、正規表現自体でバックティックを使用できます。


20

Javaの7、18の 17文字

\bcdefu0123456789

すべてのJavaソースコードをUnicodeコードポイントに減らすことができます。「a」はにのみ使用されるため、必要ありません*:jJzZ。アスタリスクは、乗算またはブロックコメントに使用されます。乗算は単に追加が繰り返されるため、代わりに1行のコメントを使用できます(または単にコメントを省略できます)。コロンは、代わりにif文を使用できる三項演算子と、通常のforループに置き換えることができるforeachループに使用されます。jとzは、javaのキーワードの一部ではありません。

他の文字を削除しようとすると、Javaボイラープレートに必要な文字を少なくとも1つ追加する必要がありますclass a{public static void main(String[]a){}}。下記参照:

1 -> a (which has already been removed)
2 -> r (required for "String")
3 -> S (required for "String")
4 -> t (required for "static")
5 -> S (required for "String")
6 -> v (required for "void")
7 -> g (required for "String")
8 -> ( (required for "main(String[]a)"
9 -> i (required for "static")
b -> { (required for "class a{")
c -> l (required for "class")
d -> } (required for "(String[]a){}}")
e -> n (required for "main")
f -> o (required for "void")

Hello Worldプログラムの例を次に示しますオンラインで試してみてください!

Java 8、16文字

\bdefu0123456789

これを指摘してくれたais523に感謝します。Java 8では、インターフェイスに静的メソッドを持たせることができます。つまり、「クラス」の「l」には「c」を必要としないため、「c」をドロップできます。「c」が使用されている,<lL\|ため、「a」を削除したときよりも少し多くのJava機能が失われますが、それでも十分にチューリングすることができます。オンラインでお試しください!


3
確かに、どの16進数を省略することができるかを理解することは、Javaでこれを解決する興味深い部分ですか?:)
マーティンエンダー

@MartinEnder絶対に。少し時間があれば、この作業をさらに進める予定です。
ポケ

6
そしてJava, 127 characters、何かを書く準備ができていた私...素敵な人、ポケ;)
オリビエグレゴワール

私の答えに必要な文字に基づいて、他の16進数を削除できるとは思わない。

3
Java 8に切り替えると、16で実行できます。Java 8では、インターフェイスで静的メソッドを使用できるため、ドロップできますc(16進リテラルを使用interfaceしないac、16進リテラル内のすべての文字にアクセスできます)。

19

ラビリンス、5文字

~{}

プラス改行(0x0A)およびスペース(0x20)。

Smallfuck(1ビットセルを使用する縮小されたBrainfuck-variant)からの縮小の形で証明をスケッチします。言語ではテープが有限である必要があると指定されているため、Smallfuck自体はチューリング完全ではありませんが、無限テープを使用したSmallfuckのバリアントを想定します。設計による制限)。

この削減を通じて重要な不変式は、すべてのプログラム(またはサブプログラム)が、同じ行で開始および終了し、偶数列にまたがるラビリンスプログラム(またはサブプログラム)になることです。

Labyrinthには2つのスタックがあり、最初は無限(暗黙)の0sで満たされています。これらのスタック間で最上位の値{}シフトします。メインスタックの最上部を現在の「セル」と見なすと、これら2つのスタックは、Smallfuckが使用する無限のテープの2つの半無限の半分と見なすことができます。ただし、上記の不変条件を確保するために、各テープ値の2つのコピーをスタックに置く方が便利です。したがって<、およびはそれぞれ>{{および}}に変換されます(必要に応じてこれらを交換できます)。

セルの値0and を許可する代わりに、and 1を使用0しています。 -1これらはwith ~(ビットごとの否定)を切り替えることができます。正確な値は、チューリング完全性の目的には関係ありません。スタック上の値の両方のコピーを変更する必要があります。これにより、再び偶数長の変換*が行われ~}~{ます。

それは制御フローコマンドを残します[]。Labyrinthには明示的な制御フローはありませんが、制御フローはコードのレイアウトによって決まります。そのレイアウトを行うには、スペースと改行が必要です。

まず、~~2つが~効果的にキャンセルされるため、これはノーオペレーションです。これを使用して、長さが偶数である限り、コードに任意の長いパスを含めることができます。次の構造を使用して、AA[BB]CCラビリンスに変換できます(不変式で保証されているように、ラビリンスの各スニペットのサイズが均等になるように2文字を使用しています)。

      ~~~~
      ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

ここで、はの幅に一致..する適切な数~ですBB

繰り返しますが、構造の幅は均一のままであることに注意してください。

これで、このループがどのように機能するかを確認できます。コードはを介して入力されAAます。最初のもの~~は何もせず、ジャンクションに到達します。これはおおよそ次のものに対応します[

  • 現在のセル値がゼロの場合、IPはそのまま続行され、最終的にスキップされBBます。..一部はまだ何もしません。次に~、別のジャンクションでシングルに到達します。現在、現在の値がゼロ以外であることがわかっているため、IPは北に向かっています。6後に別のジャンクションに達するまで、上部のベンドを回り~ます。そのため、その時点で現在の値はゼロ以外のままであり、IPは再びターンして東に移動しCCます。ループがスキップされたときのように、現在の値をに戻す~前の3つに注意してください。CC0
  • ループの開始時の現在のセル値がゼロ以外の場合、IPは南向きになります。~到達する前にさらに6つ実行されBB(何も実行されません)、~次の分岐点に到達する前にさらに6つ実行されます。これはにほぼ対応します]
    • 現在のセルがゼロの場合、IPは北へ移動し続けます。次に~、値がゼロ以外になるため、IPはこの2番目のジャンクションを取得し、ループが完全にスキップされた場合にパスをマージします。この場合も、3つ~は値をゼロに戻してからに達しCCます。
    • 現在のセルがゼロ以外の場合、IPは西に曲がります。~次のジャンクションの前にあります。つまり、この時点で現在の値はゼロであるため、IPは西に進み続けます。その後~、IPが最初のジャンクションに再び到達する前に奇数が存在するため、値が返さ-1れ、IPは次の反復に向かって南に移動します。

プログラムにループが含まれている場合、AAIPが開始する正しいセルを見つけるように、最初のループをプログラムの先頭まで拡張する必要があります。

~     ~~~~
~     ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

それだけです。この削減から生じるプログラムは決して終了しませんが、チューリング完全性の要件の一部ではないことに注意してください(ルール101またはフラクトランを考慮してください)。

最後に、これが最適かどうかという質問が残ります。ワークロードの特性に関しては、3つ以上のコマンドを実行できるとは思いません。私は2つのレジスタとミンスキー・マシンに基づいて別の構造を見ることができるが、それは必要であろう=()=-~、一つだけスタック操作コマンドを有するが、2つの算術命令。これについて間違っていることが証明されてうれしいです。:)

レイアウトコマンドについては、1行では有用な制御フローが不可能であるため、改行が必要であると考えています。ただし、スペースは技術的には必要ありません。理論的には、グリッド全体を~{}(または=()または=-~)で埋めるか、または行がすべて同じ長さではない不規則なレイアウトを使用する構造を考え出すことが可能かもしれません。ただし、ラビリンスはすべてのセルをジャンクションとして処理するため、そのようなコードを書くのは非常に困難です。また、コードを望まないときに分岐しないように細心の注意を払う必要があります。チューリング完全性のためにスペースを省略することが可能であるかどうかを誰かが証明または反証できる場合は、そのための相当な報奨金を喜んで提供します。:)


19

Haskell、5 7文字

()\->=;

関数型言語Haskellにはもちろんラムダがあるので、ラムダ計算のシミュレーションは簡単です。ラムダの構文なので、少なくとも文字が必要です。 さらに、任意のラムダ式を構築できるように、無制限の量の変数シンボルが必要です。幸いなことに、これには新しい文字は必要ありません。なぜなら、、、、...はすべて有効な変数名だからです。実際、ラムダ式用に予約されているjust と、および行コメントを開始するを除いて、内側括弧のすべての組み合わせは有効な変数名です。(\variable->body)argument()\->
(>)(>>)(>>>)\->\->--

例:

  • S = (\(>)(\\)(-)->(>)(-)((\\)(-)))タイプ(t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1
  • K = (\(>)(-)->(>))タイプt -> t1 -> t
  • I = (\(>)->(>))タイプt -> t

編集:ただし、ais523がコメントで指摘しているように、この構造は型付きラムダ計算を実装します。これは、無限ループに入ることができないため、それ自体はチューリング完全ではありません。これを修正するには、再帰を実行する関数が必要です。これまでのところ、名前のないラムダを使用しましたが、名前がないラムダは、それ自体を呼び出すことができません。だから我々は、文字を追加する必要があります=し、;実装するためfixの機能を:

(>)=(\(-)->(-)((>)(-)));   -- equivalent to: f =(\ x -> x ( f  x ));

この宣言により、ラムダ計算はチューリング完全になりますが、追加され=ているため;、を使用するnimi の答えでわかるように、ラムダはもう必要ありません()=;


コンパイル時に技術的に削除されませんmainか?
PyRulez

4
単純に型指定されたSKIコンビネーター計算はチューリング完全ではありません。そのためには型付けされていないラムダ計算が必要です。残念ながら、デモンストレーションで言及したように、Haskellはデフォルトでコードに型付き解釈を適用します。

@PyRulezデフォルトのルールに従って、私は関数が受け入れられると仮定しました。
ライコニ

@ ais523 SKIコンビネーターは単なる例であり、与えられた表記法を使用して、任意のラムダ用語を作成できます。たとえば、教会の数字や関数です。
ライコニ

@ ais523型付けされたLambda Calculusが完了する必要があるコンビネータの数 yコンビネータが必要だと思いますか?
PyRulez

18

CJam、3文字

)マーティン・エンダーの提案に従って削除

'(~

例として与えられたPythonに似ています。

を使用し'~~キャラクターを取得できます。次に、を使用して(、必要な文字(~最後の印刷可能なASCII文字)を取得するためにデクリメントできます。~任意の文字列を通常のCJamコードとして評価します。文字列を作成するには、文字を[(デクリメントによって)取得し~、評価し、他の文字のシーケンスを入れてから、文字を評価し]ます。これにより、これらの3文字のみを使用してCJamプログラムをビルドおよび実行できます。

のみを使用して2 + 2を計算する '(~


別の課題として、誰かが任意のcjamプログラムを取得してこのサブセットに自動的にコンパイルするプログラムを作成しました。私はそれを見つけることがしたい
ツヴァイ

1
私は非常に2 + 2プログラムダウンゴルフに管理'~((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~
ツヴァイ

@Zwei素晴らしい、あなたの名前に合う
Chromium

18

Brain-Flak、6文字

(){}[]

Brain-Flakは、8文字しか使用できないミニマリスト言語です。ただし、6文字のみを使用してチューリング完全なBrain-Flakのサブセットが存在することを証明できます。

最初に行うことは、Minsky MachineをBrain-Flakの1つのスタックのみで実装することです。Minsky Machineが1つのスタックだけで可能であることを証明できれば、Brain-Flakが<>and []nilads なしで完全なチューリングであることを示すことができます。これは、文字をすぐには保存しませんが、将来、それ<...>が不要であることを示すときに保存されます。

ミンスキーマシンは、有限数の無制限のレジスタと2つの命令を持つチューリング完全オートマトンの一種です。

  • レジスタをインクリメントする

  • ゼロ以外のデクリメントの場合、指定された命令に遷移します

Brain-Flakでgoto構造を設定するには、次のスニペットを使用できます。

(({}[()])[(())]()){(([({}{})]{}))}{}{(([({}{}(%s))]{}))}{}

これにより、カウンターが減分され、%sゼロの場合に実行されます。これらのチェーンをつなげることで、スタックに移動する行を示す数値をスタックに配置できます。これらはそれぞれスタックの最上部をデクリメントしますが、実際にコードを実行するのはそのうちの1つだけです。

これをすべてのMinsky Machine命令のラッパーとして使用します。

特定のレジスタをインクリメントすることは、スタックを切り替えることなく非常に簡単です。これは、次の文字列式で実現できます。

"({}<"*n+"({}())"+">)"*n

たとえば、3番目のレジスタをインクリメントするには、次のコードを記述します。

({}<({}<({}<({}())>)>)>)

次に、2番目の操作を実装する必要があります。Brain-Flakでは、数値がゼロかどうかを確認するのは非常に簡単です。

(({})){(<{}%s>)}{}

%sTOSがゼロの場合にのみ実行されます。したがって、2番目の操作を行うことができます。

Minsky Machinesはチューリング完全であるため、Brain-Flakは<>および[]オペレーションを使用せずにチューリング完全です。

ただし、まだ使用されているため<...>、文字数はまだ削減していません[...]。これは単純な置換で修正できます。以来<...>、実際に[(...)]{}はすべての場合と同等です。したがって、Brain-Flakは、<および>文字(およびすべてのノーオペレーション)を使用せずにチューリング完全です。


「なぜなら<...>[...]まだ使用中だからです。」ただし、を削除しませんでした[...]。修正してください。
電卓

質問:[...]本当に必要ですか?0をプッシュすると、開始時に行うことができます({})(ただし、0は慎重にシャッフルする必要がありますので、それは、空のスタックに依存します)主な問題はアクセスせずにスタックを下ることができることはありません<...>(もはやシミュレートすることができます)
電卓

16

> <>、3文字

> <>は3 1p-で実行可能です。

1          Push 1
p          Pop y, x, c and put the char c in cell (x, y) of the codebox
-          Subtraction: pop y, x and push x-y

pリフレクションを提供し、文字をコードボックスに配置して2Dソースコードを変更します。を使用すると1-1-1を減算して111-1--x-(1-1-1) = x+1)を加算するため、任意の数をスタックにプッシュできます。

すべての1p-コマンドが実行されると、命令ポインターが折り返され、「実際の」コードを実行できるようになります。

この回答から)フィボナッチ数を計算するサンプルプログラムは次のとおりです。

111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1-1--1p

オンラインでお試しください!すべての1p-コマンドが実行されると、コードボックスは次のようになります。

01aa+v1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1- ...
@+&1->:?!;&:nao:

v最初の行以降のすべてを除いて、これは標準のフィボナッチ> <>プログラムです。


13

bash、9文字

01456\$ '

Bashには、$'\nnn'8進数のASCII値で文字を入力するための構文があります。evalこの形式でコマンドを入力できます$'\145\166\141\154'。まず、目的の結果を8進数値に変換します。我々は、次に、0以外の数字、1、4、5を使用して、任意の8進数値を変換し、そしてする評価式に6 8進値が用い前記$(())減算、付加eval正面に。最後のステップでは、もう1つ追加しeval、括弧とマイナス記号を8進数値に変換します。このメソッドを使用すると、任意のbashコマンドを実行できるため、このサブセットは完全に調整されます。

例:

dc になる

$'\144\143' になる

$'\145\166\141\154' \$\'\\144\\$((144-1))\' になる

$'\145\166\141\154' $'\145\166\141\154' $'\$\\\'\\\\144\\\\$\050\050144\0551\051\051\\\''


12

インシデント、2文字

また、どちらの2つの文字を選択してもかまいません。2オクテットの任意の組み合わせは、インシデントではチューリング完全です。

実際にこれを証明することはあなたが予想するよりもはるかに困難であり、執筆時点では、エソランのインシデントに関する議論ページが問題に当てられています。ただし、以下で最も簡単な既知の証明の概要を説明します。

証明の前に、いくつかの背景。インシデントは、ソースを調べることでプログラムで使用されるトークンを推測します(トークンとは、ソースに正確に3回現れる文字列であり、別のトークンの部分文字列ではなく、別の潜在的なトークンと重複しません)。そのため、トークンを変更することで、ほとんどすべての文字セットを使用するようにプログラムを変換できます。言語はチューリング完全です(また、I / Oの完全性もあります!)、プログラミングが非常に難しいにもかかわらず、必要なのは、トークンをエンコードして、2文字だけで動作する方法です。

そして今、証拠の概要を以下に示します(エソランの居住数学者Ørjanによって発見されました)。アイデアは、ある文字(たとえば1)の2つのコピーを使用して、別の文字(たとえば0)の大きな海でトークンをエンコードすることです。1s 間の距離はトークンごとに異なりますが、常に4の倍数になります。その後、トークン間のパディングには、中央に0a 1を持つsの追加リストを使用しますが、その両側の0の数1ない 4の倍数ではなく、プログラムのどこかに表示されていないプログラムの特定の入射に固有の番号。つまり、それぞれ11パディング内では2回しか表示できないため、トークンの一部にはなりません。意図された各トークンには正確に2つの1が含まれ、偽トークンには複数の1を含めることはできません1。次に、サイドにパディングを追加して、1つ1または0 を含むすべてのトークンを削除します(1少なくとも4つのコピーを追加します)。


11

網膜、3文字

{`

および改行。

まず、置換を行うために改行が必要です(プログラム全体を1つの正規表現に適合させたい場合に必要です。これにより多くの文字が必要になります)。そして、`し、{ループを行うには、少なくとも文字を多用する方法です。他に何も必要ないことがわかりました。

実装するターゲット言語は、Thueの決定論的なバリアントです(チューリング完全性には非決定性は必要ありません。どの評価順序が使用されるかに関係なく、Thueプログラムを正しく動作させることができます)。基本的な考え方は、にコンパイルするpattern::=replacementことです

`pattern
replacement

(ThueのRetinaの直接翻訳です。あるいは、ThueではなくRetinaを知っている場合は、Thueの仕組みを学習する方法として使用できます)。例外として、最初のパターンの前に{`代わりに(プログラム全体をループに入れるために、Thueプログラムは、置換ができなくなるまで実行を継続します。これにより、Retinaも同じように動作します)。

もちろん、これは、Thue Turingが完全であることを証明する必要があることを意味します。 {`がパターンおよび置換で、それは十分に単純です。我々は、ASCIIコードの文字置き換えn個`nは 1 {、および別のものを`。パターンが文字の境界以外で一致することは明らかに不可能であるため、元のプログラムと同じことを行うことになります。


1
「プログラムは、置換が不可能になるまで実行を続けます。これにより、Retinaが同じように動作します」という例外があります。ただし、プログラム全体を1回パスしても文字列を変更できない場合、Retinaは早期に終了します。そのため、無料で簡単な無限ループ検出を行うこともできます。
マーティン・エンダー

1
そうだね。もちろん、チューリング完全性には影響しません(内部状態を変更しない無限ループはプログラムの計算クラスに寄与できないため)。

10

Brachylog、5文字

~×₁↰|

この文字のサブセットにより、Fractranのバージョンを実装できます。このバージョンでは、表示できる数字はレプユニットの積(つまり、数字1のみを使用して10進数で記述できる数の積)のみです。(整数を添え字として)現在の値をその整数で除算しますが、正確に除算した場合のみです(そうでない場合は「失敗」し、実行する別のケースを探します。|分離します)。×整数で乗算します。したがって~×₁|、Fractran実行の1ステップを実装できます。その後、再帰を実行して、新しい現在値でプログラム全体を再度実行します。ここだ非常に単純なFractranプログラム(例11111111111111111111111/111Brachylogに変換)が。

このチューリングは完全ですか?Fractranチューリングを完全にするために必要なのは、十分な量の素数だけです(Fractran自体でチューリング完全言語のインタープリターを作成するのに十分です)。実証済みの5つと疑わしい4つがありますrepunit素数は、おそらく、まだ発見されていないものに加えて。この場合、実際にはそれ以上です。プログラムは左から右への可能性をチェックするため、1つの素数を命令ポインターとして使用し、さらに2つをカウンターとして使用して、3つの素数のみでチューリングの完全性を示します(2、19でrepunits 、および23桁。これは、317桁または1031桁の実績のある迷惑なほど大きな繰り返し単位に頼る必要がないため、ソースコードの記述がかなり難しくなります。これにより、2つのカウンターを備えたMinskyマシンを実装できます(チューリング完全性に十分)。

コンパイルの具体的な仕組みを次に示します。Minskyマシンの実装には次の2つのコマンドを使用します(これはチューリング完了と呼ばれます)。各コマンドにはラベルとして整数があります。

  • ラベルL:カウンター{AまたはB}がゼロの場合、Xに進みます。そうでない場合は、デクリメントしてYに進みます。
  • ラベルL:カウンター{AまたはB}をインクリメントし、Zに進みます。

11の累乗を分母に配置することで、実行するコマンドを選択します。最高の累乗が最初になります。11の指数は、コマンドのラベルです。この方法では、一致する最初の小数部が現在実行中のコマンドになります(前の小数部はこれらすべての11で除算できないため)。デクリメントコマンドの場合、1111111111111111111または11111111111111111111111の係数をそれぞれカウンターAまたはBの分母に配置し、その係数のない別のコマンドでフォローアップします。「減少」の場合は最初のコマンドによって実装され、「ゼロ」の場合は2番目のコマンドによって実装されます。一方、「goto」は分子内の11の適切な累乗によって処理され、「111111111111111111111」または「111111111111111111111111」の係数を介して「増分」されます。


ペアワイズ相互素数レプユニットを使用できない特別な理由はありますか?
CalculatorFeline

@CalculatorFeline:いいえ、しかし、それらを必要としない構造をすでに見つけた後まで、それらについて考えませんでした。このキャラクターセットで書かれたゴルフプログラムで確かに役立ちます。

また、すべてのrepunits> 1は、ペアワイズ互いに素(それについて考える)です
CalculatorFeline

@CalculatorFeline:いいえ、そうではありません。111と111111はどちらも3で割り切れます。

*何レピュニットは別のレピュニットを分割しない
CalculatorFeline

10

Befunge-98、3文字

私の知る限り、Befunge-98は完全にチューリングされているはずなので、たった3文字でBefunge-98プログラムを生成する方法を示す必要があります。私の最初の解決策は、次の4つの文字に依存していました。

01+p

コマンドで複数の1値を追加することで、スタックに正の整数を取得でき+ます0。ゼロの場合は、単に使用します。必要な数をプッシュできるようになったら、次を使用できます。p(put)コマンドをして、ASCII値をBefungeプレイフィールドの任意の場所に書き込むことができます。

ただし、Sp3000が指摘したように、実際には次の3つの文字だけで対応できます。

1-p

負の数は、最初から1繰り返し減算することで計算できます1(たとえば、-3はになります11-1-1-1-)。次に、1から1-nを引くことで、任意の正の数を表すことができます。ここで、1-nは、処理方法が既にわかっている負の数です(たとえば、4 = 1-(-3)は111-1-1-1--)。

したがって、3文字を使用して、実行する実際のコードをゆっくり生成するブートローダーを作成できます。このローダーの実行が完了すると、プレイフィールドの最初の行の先頭に戻ります。この時点で、新しく生成されたコードの先頭が保持されます。

例として、2 + 2を合計して結果を出力するために必要なBefungeコードを生成するブートローダーを次に示します。 22+.@

少し複雑な例では、これは「Hello World」です。 "!dlroW olleH"bk,@


これはポリグロットであり、同じ文字を> <>とその派生に使用できます。よくやった!
ソク

2
Befunge-98も3で実行1p-可能
Sp3000

@ Sp3000もちろんそうです!私はそれを3文字まで下げる方法があったに違いないと確信していました。ありがとう。
ジェームズホルダーネス

9

ルビー、8文字

eval"<1+

Pythonの回答に触発された

使い方

  • evalを使用して、任意の文字列を実行できます。
  • 「<1+は、文字列を作成するために必要な最小限の文字セットです。

rubyの文字列は、空の文字列を開始点として使用し、それにASCII文字を追加して構築できます。たとえば、

eval ""<<111+1<<11+11+11+1<<111<<11+11+11+1

実際に同等です

eval ""<<112<<34<<111<<34

文字列を評価します

p"o"

8

OCaml、9文字

fun->()`X

これらの文字は、OCamlでSKI Combinator Calculusを実装するのに十分です。特に、十分な括弧でスペースの使用を回避できます。残念ながら、OCamlのラムダ式にはfunキーワードが必要なため、より簡潔なソリューションは不可能です。ただし、より複雑なラムダ式が必要な場合は、同じ文字を使用して任意の変数名を作成できます。

Sコンビネーター:

fun(f)(u)(n)->f(n)(u(n)) タイプ付き ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c

Kコンビネーター:

fun(f)(u)->u タイプ付き 'a -> 'b -> 'b

コンビネーター:

fun(f)->f タイプ付き 'a -> 'a

ais523で述べたように、単にSKIをエンコードするだけでは不十分です。型システムを操作するために多相バリアントを使用したZのエンコードを次に示します。これで私のサブセットは完全にチューリングするはずです。

Zコンビネーター:

fun(f)->(fun(`X(x))->(x)(`X(x)))(`X(fun(`X(x))y->f(x(`X(x)))y))

タイプ付き (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b


2
単純に型指定されたSKIコンビネーター計算はチューリング完全ではありません。そのためには型付けされていないラムダ計算が必要です。残念ながら、デモンストレーションで述べたように、OCamlはデフォルトでコードに型付き解釈を適用します。

1
次に、yコンビネータ(および同様にzコンビネータ)のエンコードを可能にする多相バリアントを使用できるようにするために、さらにいくつかの文字が必要です。
デビンリーマッハー

Zコンビネーターとは何ですか?
電卓

@CalculatorFeline yコンビネーターの厳密なバリアントです。OCamlはレイジーではないため、OCamlで必要です。ここではWikipediaのページへのリンクです:en.wikipedia.org/wiki/...は
デヴィンLehmacher

8

スタックベースの連結言語、4文字

負荷の下で

():^

GolfScript

{}.~

CJam

{}_~

GS2

  • バックスペース、タブ、@スペース

dc(@seshoumaraが推奨)

[]dx

アンダーロードは、():^(Esolangの居住数学者Ørjanのおかげで)使用のみでチューリング完全であることが証明されています。証明は長すぎてここで説明することはできませんが、興味があれば、ここでそれについて読むことができます

問題のコマンドは():(スタックにコードリテラルを配置する)、(一番上のスタック要素を複製する)、および^(スタックの一番上を評価する)です。これらのコマンドは、スタックベースの言語(特に連結言語)でかなり一般的であるため、上記のコマンドのコレクションをいくつか示しました。これらの言語はすべて、Underloadと同じ理由で4文字でチューリング完全です。


それらを使用してスタック操作を実行できることを理解していますが、数学的な計算を行うために、そのスタックにデータを取り込むために少なくとも数字が必要ではないですか?または、4つの文字のいずれかを使用して単項で行われますか?
seshoumara

1
@seshoumara:このメソッドを使用すると、数値(および他のほとんどすべてのデータストレージ)が非常に間接的に実装されます。算術として認識できるものに到達する前に、2つまたは3つ、場合によっては4つの抽象化レベルがあります。この種のことは、このような非常に限られたシステムのチューリング完全性証明では一般的です。

スタックベースの言語であるdcで自分で回答を送信することを考えていましたが、4よりも多くの文字を含む別の方法を使用しました。dcはリストに収まりますか?
セショウマラ

@seshoumara:はい、必要なすべての機能を備えているようです。私はそれを追加し、あなたに入金しました。

たぶん、あなたはFlogScriptを調べることができます
mbomb007

7

空白、3文字

STL

Sスペース、Tタブ、L改行です。


これは完全な言語ですか、それともサブセットですか?チューリングの完全性の証拠はどこにありますか?
ブライアンミントン

2
@BrianMinton完全な言語です。esolangwikiは非常に軽いです。esolangs.org/ wiki / Whitespaceですが、afaik、完全に調整中です。
Cruncher

7

ラケット(スキーム)、4文字

(λ)

λ、括弧、およびスペースのみを使用して、SchemeのLambda Calculusサブセットで直接プログラムできます。識別子を連結して任意の数の一意の識別子を提供することにより、すべての識別子にλ文字を再利用します。

例として、永遠にループする古典的なOmegaコンビネーターを次に示します。

((λ (λλ) (λλ λλ)) (λ (λλ) (λλ λλ)))

6

Python 3、9文字

exc('%1+)

基本的な説明については、Python 2の回答を参照してください。この答えはそれに基づいています。

を追加してPython 2と同じ文字を使用する代わりに()、括弧を使用できるようになったため、文字をドロップできます。プログラムは、基本的な形のままです。

exec('%c'%stuff)

ただし、の+代わりにを使用してプログラムの長さを短縮し、の代わりにを使用して-削除できます。次に、~10111および111必要なASCII値を取得します。

プログラムprint()は最短で次のようになります。

exec('%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c'%(111+1)%(111+1+1+1)%(11+11+11+11+11+11+11+11+11+1+1+1+1+1+1)%(11+11+11+11+11+11+11+11+11+11)%(111+1+1+1+1+1)%'('%')')

オンラインで試す

あなたは自分で考えているかもしれませんが、どのようにNULバイトを作成するの0ですか?怖くない、若いバッタ!%というのも、数学にも使用でき、でゼロを作成できるから1%1です。


プログラムにNULバイトが必要なのはなぜですか?
-NieDzejkob

@NieDzejkobこのサイトでは、「なぜ」に対する答えは常に「できるから」です。ただし、この場合、エラーが発生したとしても、できなかった場合はPythonの完全な実装にはなりません。
mbomb007

チューリング完全性のためにNULバイトは必要ありません。BFインタープリターは1
つなし

@ MilkyWay90本当ですが、できればそれを説明してみませんか?
mbomb007

6

PHP 7、6文字

'().;^

アイデアは、次の構成を使用して任意のコードを実行できるということです。

('create_function')('','<code>')();

eval ここでは機能しません。これは、言語構造であり、変数関数を使用して呼び出すことができないためです。

create_function そして、コードは利用可能な文字のビットごとのXORの連結として書くことができます:

(<char1_1>^<char1_2>^...).(<char2_1>^<char2_2>^...)...

().;^for を使用すると<charX_Y>

()./:;<=JKLMXY^_bcdepqvw

およびいくつかの印刷できない文字。十分ではありませんが、今では'eXp'()いくつかの数字を呼び出して取得することができます:

''.'eXp'('eXp'('')) -> 1
''.'eXp'('eXp'('eXp'(''))) -> 2.718281828459
''.'eXp'('eXp'('eXp'('eXp'('eXp'(''))))) -> 3814279.1047602

それは私たちを与え12そして3(他の文字列が1文字の長さであれば、他の文字は、XORによって無視されます)。ここから().;^123、すべてのASCII文字セットを生成できます。

オンラインで試す


5

パイク、5文字

0h.CE

これは無限に大きな数を生成し、それを文字列に変換してからPykeコードとして評価することができます。

コードの説明:

0-スタックに0を追加します。これは番号を開始するために必要です

h-前に数字を増やします。これを任意の回数繰り返すことで、無限に大きな数字を作成できます。Pykeは、Pythonで記述されたbignumをサポートします。これはデフォルトとして使用されます。

.C-次のアルゴリズムを使用して、数値を文字列に変換します:(Githubリンク

def to_string(num):
    string = ""
    while num > 256:
        num, new = divmod(num, 256)
        string = chr(new) + string
    string = chr(num) + string
    return string

この時点で、Pykeで任意の値を使用して任意の量の文字列と自然数を作成できます。数値は正規表現に対応する形式0(h)*で作成でき、文字列は次のように作成できます0(h)*.C。これらを互いに織り交ぜて、文字列と整数の任意の混合を作成できます。

E-文字列をPykeコードとして評価します。これは、すでに実行されているPykeコードと同じ環境を使用するため、入力などを共有します。

Pykeがチューリング完了であることの証明を試みました。

言語を完全に表示する最も簡単な方法の1つは、Brainf * ckを実装することです。これはおそらくPykeが他の多くの言語よりもはるかに難しいのは、Pykeが実行されるように設計されている領域ではリストおよび辞書操作が必要ないためにほとんど存在しないためです。です

まず、brainf * ckのインタープリターを作成し、上記のアルゴリズムを使用してエンコードして数値を作成し、その数値を0とで表現しhます。次に、まったく同じ方法で実行するコードを含む文字列を作成します。そのままにしておくと、スタックは次のようになります。

string containing brainf*ck code
string containing brainf*ck interpreter

つまり、Pykeスタックは先入れ先出しであるため、コードは逆の形式にする必要があります。

楽しい部分は、なんと216バイトのbrainf * ckインタープリターです!

Q~B"><ht.,".:=B;Z]1=L;W~Bo@D=c"ht"{I~c~LZ@EZ]1~LR3:=L)~c\,qIz.oZ]1~LR3:=L)~c\.qI~LZ@.CpK)~c"<>"{I~c"<>""th".:ZE=ZZ1_qI0=Z~L0"":0]10:=L)Z~LlqI~L~Ll"":1_]10:=L))~c\[qI~LZ@0qI\]~B~o>@~o+h=o))~c\]qI~o\[~B~o<_@-t=o)~o~BlN

ここで試してみてください!

半完成だが編集可能な形式でコードを試してみたい場合は、 ここ試してください!

文字列から数値に変換するには、次のPythonコードを使用できます。

def conv(string, t=0):
    t *= 256
    t += ord(string[0])
    if len(string) != 1:
        return conv(string[1:], t)
    return t

(ほぼ)最終的な解決策はここ試すことができます!

Brainf * ckインタープリターの説明

最初に、プログラムを部分に分割します。

  • 初期化:

Q~B"><ht.,".:=B;Z]1=L; - The initialisation part
Q~B"><ht.,".:          - input.replace("><+-.,[]", "><ht.,")
                       - replace the characters in brainf*ck with some modified ones. 
                       - this means we can `eval` the add and subtract bits easily.
             =B;       - set `B` to this.
                       - The `B` variable contains the instructions
                Z]1=L; - set `L` to [0]
                       - `L` contains the stack, initialised with 0
  • メインループ:

​​ ​ ​

W~Bo@D=c !code! ~o~BlN - The main loop
W                      - do
 ~Bo@D=c               -  c=B[o++]
                       -  the c variable is used to store the current character.
                ~o~BlN - while
                ~o     -   o 
                     N -  ^ != V 
                  ~Bl  -   len(B)
                       -  this stops the program running once it's finished.
  • 説明書
    • インクリメント/デクリメント:+-

​​ ​ ​

"ht"{I~c~LZ@EZ]1~LR3:=L) - The bit that does incrementing and decrementing
"ht"{I                 ) - if c in "ht"
        ~LZ@             -  L[Z]
                         -  `Z` contains the current stack pointer
      ~c    E            -  eval current character with ^ as an argument
                         -  returns the contents of `Z` either incremented or decremented
             Z]1~LR3:=L  - L[Z] = ^
  • 入力,::

​​ ​ ​

~c\,qIz.oZ]1~LR3:=L) - The code for output 
~c\,qI             ) -  if character == ",":
      z.o            -    ord(input)
         Z]1~LR3:=L  -   L[Z] = ^
  • 出力.::

​​ ​ ​

~c\.qI~LZ@.CpK) - The code for input 
~c\.qI        ) - if c == ".":
      ~LZ@      -    L[Z]
          .C    -   chr(^)
            pK  -  print(^)
  • 左/右にシフト<>::

​​ ​ ​

~c"<>"{I~c"<>""th".:ZE=Z - main part 
~c"<>"{I                 - if "<>" in c:
        ~c"<>""th".:     -  c.replace("<>", "th")
                    ZE=Z -  Z = eval(char, Z)

Z1_qI0=Z~L0"":0]10:=L) - lower bound check
Z1_qI                ) - if Z == -1:
     0=Z               -  Z = 0
        ~L0"":         -  L.insert("", 0)
              0]10:=L  -  L[0] = 0

Z~LlqI~L~Ll"":1_]10:=L) - upper bound check
Z~LlqI                ) - if Z == len(L):
        ~Ll"":          -  L.insert("", len(L))
      ~L      1_]10:=L  -  L[-1] = 0
  • 条件[::

​​ ​ ​

~c\[qI~LZ@0qI\]~B~o>@~o+h=o)) - Code for `[`
~c\[qI                      ) - if c == "[":
      ~LZ@0qI              )  -  if L[Z] == 0:
               ~B~o>          -     B[o:]
             \]     @         -    ^.find("]")
                     ~o+h=o   -   o = o + ^ + 1

-そして ]

​​ ​ ​

~c\]qI~o\[~B~o<_@-t=o) - Code for `]`
~c\]qI               ) - if c == "]":
          ~B~o<_       -    reversed(B[:o])
        \[      @      -   ^.find("[")
      ~o         -t=o  -  o = o - ^ -1

5

積み上げ、5文字

{!n:}

これは驚くほど短いです。Stackedが各SKIの組み合わせを実装できる場合、チューリング完了です。要約:

  • I コンビネーター-恒等関数。 x -> x
  • K コンビネーター-定数関数。 x -> y -> x
  • S コンビネーター-置換関数。 (x, y, z) -> x(z)(y(z))

私はコンビネーター: {!n}

さて、積み重ねられた詳細について。{! ... }n-lambdaです。これは、引数が暗黙的に指定されている単項関数ですn。次に、最後の式が関数から返されます。したがって、{!n}引数を取り、以下nを生成する関数です。n

Kコンビネーター: {!{:n}}

これ{:...}は、引数をとらない関数であり、を返します...。これをn-lambdaフォーメーションと組み合わせると、次のようになります(わかりやすくするために空白を追加します)。

{! { : n } }
{!         }   n-lambda. arguments: (n)
   { : n }     lambda.   arguments: ()
       n       yields n.

Sコンビネーター: {n!nn!nnn:nnn{!n}!nn!nnn{!n}!n!!}

わかりました、これはもう少し複雑に見えます。したがって、ラムダは、非識別子文字で区切られた引数を取ります。したがって、ヘッダーのラムダは次と同等です。

{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}

これは、3つの引数を取りラムダであるnnnnnn。わかりやすくするためxy、これらをz、、およびに置き換えましょう。

{x y z:z{!n}!y!z{!n}!x!!}

この2つ{!n}!は、!「実行」を意味する空白を再度回避するための単なるアイデンティティ関数です。だから、再び、削減:

{x y z:z y!z x!!}

説明付き:

{x y z:z y!z x!!}
{x y z:         }  three arguments
       z y!        apply `y` to `z` -- `y(z)`
           z x!    apply `x` to `z` -- `x(z)`
               !   apply `x(z)` to `y(z)` -- `x(z)(y(z))`

したがって、これはSコンビネーターです。


{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}スペースが含まれています。
電卓

@CalculatorFelineその前の文章を読みましたか?わかりました、これはもう少し複雑に見えます。そのため、ラムダは、非識別子文字で区切られた引数を取ります。このように、ヘッダ内のラムダは、と等価である:
コナー・オブライエン

ああ。(自己への注意:ばかであることを停止します。)
電卓
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.