Il minor numero di (distinti) personaggi per Turing Completezza


108

Sommario:

Per una determinata lingua, qual è la quantità minima di caratteri unici per la tua lingua da completare ?

Sfida:

Per qualsiasi lingua di tua scelta, trova il sottoinsieme più piccolo di caratteri che consente alla tua lingua di essere Turing-Complete. Puoi riutilizzare il tuo set di caratteri tutte le volte che vuoi.


Esempi:

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

  • Brainfuck: +<>[](assume una dimensione di cella avvolgente)

  • Python 2: ()+1cehrx(fatto da script come exec(chr(1+1+1)+chr(1)))

punteggio:

Questa sfida è segnata in caratteri , non in byte . Ad esempio, i punteggi per gli esempi sono 6, 5 e 9.


Appunti:

  • Questa sfida si differenzia dagli altri, nel senso che solo la tua lingua deve essere Turing-Complete (non necessariamente essere in grado di utilizzare tutte le funzionalità della lingua).

  • Sebbene sia possibile, non pubblicare le risposte senza ridurre i caratteri utilizzati. Esempio: Brainfuck con 8 caratteri (poiché ogni altro personaggio è un commento per impostazione predefinita).

  • DEVI fornire almeno una breve spiegazione del perché il tuo sottoinsieme è Turing-Complete.


90
Unario , 1 personaggio. sospira
Dennis il

4
@Dennis Non è così diverso da Jelly o 05AB1E con un built-in per un interessante problema di teoria dei numeri. Questa sfida sembra ancora un problema di ottimizzazione interessante e non banale in qualsiasi linguaggio che non sia stato progettato per essere un tarpit.
Martin Ender,

7
@MartinEnder Sarei particolarmente interessato a vedere le risposte in lingue come Java o C.
Julian Lachniet,

9
Si prega di non pubblicare soluzioni in esolangs in cui la soluzione è ogni carattere valido nella lingua. Non è interessante o intelligente.
Pavel,

20
@Pavel Non interessante o intelligente potrebbe significare che non dovrebbe essere votato, ma sicuramente non dovrebbe essere pubblicato.
Dennis,

Risposte:


77

Haskell, 4 caratteri

()=;

Con ()=siamo in grado di definire S, K e I. Le definizioni devono essere separate da una ;o da una NL.

Definiamo (==)S (la seconda riga mostra una versione più leggibile):

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

(===) Chiedi:

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

e (====)come io:

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

Per fortuna (==), (===), (====), ecc, sono i nomi delle funzioni / parametri validi.

Come sottolinea @ ais523, SKI non è abbastanza in un linguaggio fortemente tipizzato come Haskell, quindi è necessario aggiungere un combinatore di punti fissi (=====):

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

17
Questa costruzione non funziona direttamente; Gli SKI non sono Turing completi in un linguaggio fortemente tipizzato come Haskell. Tuttavia, credo che tu possa usare la stessa tecnica per definire fix, e SKI + fix è Turing completo, anche in un linguaggio fortemente tipizzato.

Oh, quindi hai prefisso quelle definizioni all'inizio di ogni programma?
PyRulez,

@PyRulez: si. Per impostazione predefinita presumo che sia sufficiente essere in grado di costruire funzioni con il set di caratteri specificato - non è necessario un programma completo.
nimi,

1
Probabilmente dovresti sostituirlo in (==)modo che non si scontrasse con l'operatore di uguaglianza predefinito
orgoglioso haskeller

@proudhaskeller: sì, se in realtà vuoi programmare è meglio rinominarlo (==), ma il codice sopra è solo una prova della completezza turing.
nimi,

61

JavaScript (ES6), 5 caratteri

Grazie a @ETHproductions e @ATaco per l'aiuto in questo; questo era un progetto di gruppo e sebbene l'idea originale fosse mia, molti dei dettagli sono loro. Si veda la discussione di chat dove questo sottoinsieme JavaScript è stato sviluppato qui .

[]+=`

È abbastanza noto che qualsiasi programma Javascript può essere scritto con i caratteri ( []()+!), ma 5 caratteri non sono sufficienti . Tuttavia, questa non è una sfida per la scrittura di JavaScript arbitrario. È una sfida scrivere una lingua completa di Turing e usare il fatto che le lingue complete di Turing non hanno bisogno dell'accesso al DOM, o persino dell'I / O interattivo, si scopre che possiamo scrivere un programma con tutte le funzionalità richieste , anche senza alcuna possibilità di eseguire un evalo un equivalente.

Bootstrap di base

JavaScript è molto flessibile con i tipi. Quindi, ad esempio, []è un array vuoto, ma +[]è 0 e[]+[] è la stringa null. In particolare, il fatto che possiamo produrre 0 con questo set di caratteri rende possibile simulare l'effetto delle parentesi per il raggruppamento; (a)può essere scritto come [a][+[]]. Possiamo usare questo tipo di trucco per produrre vari personaggi usando solo +[]:

  • [][+[]]è undefined(essendo il primo elemento di un array vuoto); così
  • []+[][+[]] è "undefined" (la stringa di undefined); così
  • [[]+[][+[]]]è ["undefined"](avvolgendolo in un array); così
  • [[]+[][+[]]][+[]] è "undefined" (il suo primo elemento); così
  • [[]+[][+[]]][+[]][+[]] è "u" (la sua prima lettera).

uè uno dei personaggi più facili da creare, ma tecniche simili ci consentono di creare una serie di altri personaggi. Lo stesso link di prima ci fornisce il seguente elenco di caratteri accessibili con +[](questo è lo stesso elenco di +[](), escluso, perché è l'unica costruzione che utilizza le parentesi per uno scopo diverso dal raggruppamento / precedenza):

0123456789acdefinotuvyIN (){}.

Non possiamo scrivere molte parole utili da questo set di caratteri (ricorda che questo è il set di caratteri che possiamo produrre come stringhe ; non possiamo eseguirli senza una sorta di eval). Come tale, abbiamo bisogno di un altro personaggio. Lo useremo =perché tornerà utile in seguito, ma per il momento lo useremo per scrivere l'operatore di confronto ==. Ciò ci consente di produrre falsee true, che può essere stretto e indicizzato, e di farci immediatamente aggiungere lrsai caratteri che possiamo includere nelle stringhe.

Di gran lunga la parola più importante che questo ci permette di scrivere, che non potevamo prima, è constructor. Ora JavaScript ha una sintassi di accesso alla proprietà simile alla seguente:

object.property

ma puoi anche scriverlo in questo modo:

object["property"]

e nulla ci impedisce di usare una proprietà calcolata, piuttosto che una stringa letterale. Possiamo così fare qualcosa sulla falsariga di

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

(con le lettere generate come descritto sopra; il codice diventa rapidamente molto lungo!); è equivalente aobject.constructor , che ci consente di accedere ai costruttori di oggetti arbitrari.

Ci sono molti trucchi che possiamo fare con questo. Dal banale al fantastico:

  • Il costruttore di un oggetto è una funzione. In particolare, ha un nome e quel nome fa parte della stringificazione della funzione. Quindi, ad esempio, possiamo fare [[]+[]][+[]]["constructor"]per arrivare al costruttore per una stringa, il cui nome è String, e quindi stringere per arrivare alla capitaleS carattere . Questo espande un po 'il nostro alfabeto e avremo bisogno di alcuni dei nuovi personaggi in seguito.
  • Tutti gli array hanno lo stesso costruttore; []["constructor"] == []["constructor"]è true(a differenza di [] == [], che è falso). Questo può sembrare minore, ma è molto importante, perché ci fornisce un metodo per memorizzare i valori in modo persistente; possiamo impostare una proprietà casuale sul costruttore e rileggerla più tardi. (Questo è uno dei motivi che stiamo usando =in particolare, piuttosto che uno degli altri modi per generare truee false.) Ad esempio, possiamo valutare[[]["constructor"]["a"]=[]] , e in seguito leggere []["constructor"]["a"]e recuperare lo stesso array che abbiamo archiviato lì.

    Ciò soddisfa uno dei requisiti di cui abbiamo bisogno per la completezza di Turing , la capacità di archiviare e recuperare quantità arbitrarie di dati. Possiamo creare una cella contro usando una matrice a due elementi, prendendo i valori dalla nostra memoria di proprietà del costruttore e quindi salvandola al posto di uno di quei valori, permettendoci di costruire strutture di dati arbitrariamente grandi in memoria; e possiamo accedervi da questo archivio facendo il contrario, abbattendolo pezzo per pezzo fino a quando i dati che vogliamo diventano accessibili. La lettura è distruttiva, ma è accettabile perché abbiamo più di un posto dove archiviare i dati, quindi possiamo copiarli mentre li leggiamo e quindi riposizionare la copia nella posizione originale.

  • Ci consente di accedere al costruttore per una funzione (ci sono molte funzioni a cui possiamo accedere con il nostro alfabeto limitato; []["find"]cioè Array.find, è la più facilmente accessibile, ma ce ne sono altre). Perché è utile? Bene, possiamo effettivamente usarlo per lo scopo previsto di un costruttore e costruire funzioni! Sfortunatamente, con il nostro set di caratteri, non possiamo trasmettere al costruttore della funzione una stringa calcolata. Tuttavia, l'uso di `ci fa passare una stringa letterale (es. []["find"]["constructor"]`function body goes here`); questo significa che possiamo definire valori personalizzati del tipo di funzione con qualsiasi comportamento quando eseguito, purché possiamo esprimere quel comportamento interamente usando []+=. Per esempio,[]["find"]["constructor"]`[]+[]` è una funzione abbastanza noiosa che calcola la stringa nulla, la scarta ed esce; quellola funzione non è utile, ma saranno più complessi. Si noti che sebbene le funzioni non possano accettare parametri o restituire valori, in pratica non si tratta di problemi in quanto è possibile utilizzare l'archivio proprietà-costruttore per comunicare da una funzione all'altra. Un'altra restrizione è che non possiamo usare` nel corpo di una funzione.

    Ora possiamo definire funzioni personalizzate, ma ciò che ci trattiene a questo punto è la difficoltà che abbiamo nel chiamarle . Al livello più alto del programma, possiamo chiamare una funzione con`` , ma essere in grado di chiamare funzioni solo dal livello più alto non ci permette di fare alcun tipo di loop. Piuttosto, abbiamo bisogno di funzioni per poterci chiamare.

    Lo realizziamo con un trucco piuttosto ingegnoso. Ricordi la capitale che Sabbiamo generato in precedenza? Questo ci permette di scrivere "toString". Non lo chiameremo; possiamo convertire le cose in stringhe aggiungendole []. Piuttosto, lo sostituiremo . Possiamo usare l'archiviazione del costruttore per definire array persistenti che restano intorno. Possiamo quindi assegnare le nostre funzioni create ai toStringmetodi delle matrici e anche quelle assegnazioni resteranno invariate. Ora, tutto ciò che dobbiamo fare è un semplice +[]array e all'improvviso verrà eseguita la nostra funzione personalizzata. Questo significa che possiamo usare i personaggi+=[]chiamare funzioni, e quindi le nostre funzioni possono chiamarsi a vicenda - o se stesse. Questo ci dà la ricorsione, che ci dà loop e improvvisamente abbiamo tutto ciò di cui abbiamo bisogno per la completezza di Turing.

Ecco una carrellata di una serie di funzionalità che danno completezza a Turing e come sono implementate:

  • Memoria illimitata : matrici nidificate nella memoria del costruttore
  • Flusso di controllo : implementato usando ife ricorsione:
    • if: converte un valore booleano in un numero e indicizza in un array di 2 elementi; un elemento esegue la funzione per il thencaso quando sottoposto a stringa, l'altro elemento esegue la funzione per il elsecaso quando sottoposto a stringa
    • Ricorsione : in stringa un elemento corrispondente del costruttore stoccaggio
  • Comando sequenziamento : [a]+[b]+[c]Esamina a, be cda sinistra a destra (almeno sul browser ho controllato)

Sfortunatamente, questo è abbastanza poco pratico; non solo è enormemente grande dato che le stringhe devono essere costruite carattere per carattere partendo dai primi principi, ma non ha nemmeno modo di fare I / O (che non è necessario per essere completo di Turing). Tuttavia, se termina, è almeno possibile cercare manualmente nella memoria del costruttore in seguito, quindi non è impossibile eseguire il debug dei programmi e non sono completamente non comunicativi.


16
Se questo non ha un nome, suggerisco J5h * t.
Calcolatrice

1
Quale sarebbe un buon programma di esempio? Test Prime? Ciao mondo?
Calcolatrice

3
Il mio, questo è così wat ... risposta delizioso, come un buon film horror.
cessò di girare in senso antiorario il

4
Ho pensato che l'uso di Angular1 toString()per l'iniezione delle dipendenze fosse il modo più creativo di usare la funzione. Ora ho cambiato idea.
Sunny Pun,


55

Unario , 1 personaggio

0

La scelta del personaggio non ha molta importanza; la lunghezza del programma definisce il programma di brainfuck in cui si traspone. Mentre le specifiche 0obbligano i personaggi, la maggior parte dei transpiler non sembra verificarlo.


44
Probabilmente dovremmo aprire problemi con i transpilers che convalidano le specifiche, questo è un problema molto serio.
Captain Man,

5
Sono sbalordito. Ho avuto bisogno di 20 minuti per dire se è uno scherzo.
Peter A. Schneider,

3
@ PeterA.Schneider Alcuni googling scopriranno che qualcuno ha effettivamente implementato un quine in questo modo in teoria, anche se la stringa risultante di 0 è probabilmente il numero più grande che abbia mai visto in qualsiasi contesto pratico e non potrebbe mai essere implementato su una macchina reale.
Darren Ringer,

12
Quella stringa di zero è in realtà il numero più piccolo che abbia mai visto in qualsiasi contesto.
Matteo Leggi il

1
LOL, beh, se fai qualcosa di stupido come definire il tuo unico simbolo come identità additiva ...: p
Darren Ringer

37

vim, 9 8 7 6 caratteri

<C-v><esc>1@ad

Possiamo costruire ed eseguire un programma di vimscript arbitrario come segue:

  1. Utilizzare la sequenza aa<C-v><C-v>1<esc>dd@1<esc>ddddper ottenere un <C-a>registro 1.

  2. Inserire la modalità di inserimento con a, quindi inserire un a, che verrà utilizzato per accedere nuovamente alla modalità di inserimento in una macro in un secondo momento.

  3. Per ogni personaggio nel programma vimscript desiderato,

    1. usare <C-v><C-v>1<esc>per inserire la sequenza letterale <C-v>1,

    2. use @1(ovvero <C-a><cr>, in cui la finale <cr>è una no-op a causa dell'ultima riga) tutte le volte necessarie per incrementare il 1valore fino al raggiungimento del valore ASCII del carattere desiderato,

    3. e accedere nuovamente alla modalità di inserimento con a.

  4. Elimina la linea (insieme a una nuova riga finale) nel 1registro con <esc>dd.

  5. Esegui il risultato come sequenze di tasti vim utilizzando @1, quindi <esc>ddper eliminare la riga immessa dalla nuova riga finale dal passaggio precedente.

  6. Eseguire la sequenza arbitraria di byte risultante con dd@1. Se inizia con a :, verrà interpretato come codice vimscript e verrà eseguito a causa della nuova riga finale da dd.

Non sono convinto che si tratti di un set di caratteri minimo, ma è abbastanza facile dimostrare di essere Turing completo.


2
Non puoi fare i<C-v>1<ESC>per scrivere <C-a>e quindi in ddmodo da poter utilizzare @1per incrementare qualsiasi numero e comportare di non doverlo usare <C-a>?
Kritixi Lithos,

4
Caspita, questa risposta è incredibile! +1!
DJMcMayhem

@KritixiLithos Questo finisce per funzionare dopo un po 'di ristrutturazione, grazie!
Maniglia della porta

2
@ mbomb007 In realtà ... a causa di un dettaglio di implementazione interessante, <C-v>10inserisce un NUL anziché \ n (non chiedere). In ogni caso, sì, non importa per quanto riguarda la completezza di Turing.
Maniglia della porta


33

Perl, 5 caratteri

<>^es

Come con altri linguaggi di scripting, l'idea è quella di evalstringhe arbitrarie. Tuttavia, il nostro set di caratteri non include virgolette o operatori di concatenazione, quindi costruire stringhe arbitrarie sarà molto più complesso. Nota che eval^"sarebbe molto più semplice da gestire, ma ha un personaggio in più.

Il nostro strumento principale è s<^><CODE>ee, che valuta CODE, quindi elimina la sua produzione. Più epuò essere aggiunto, con l'effetto previsto.

Otteniamo le stringhe usando <>, che è l'operatore glob tranne quando non lo è. Il primo carattere non può essere <(altrimenti sembra l' <<operatore), le parentesi angolari devono essere bilanciate e deve esserci almeno un carattere non lettera (altrimenti viene interpretato come l'operatore readline).

Analizzando insieme quelle stringhe, possiamo ottenere qualsiasi combinazione di caratteri ^B^V^S(*-/9;<>HJMOY[`\^begqstv, purché accettiamo di avere un po 'di spazzatura in giro (i primi tre di questi sono caratteri di controllo).

Ad esempio, supponiamo di voler ottenere "v99". Un modo per ottenere v99è "><<" ^ "e>>" ^ "see" ^ "^^^", ma non possiamo rappresentare quelle stringhe a causa dei vincoli <>. Quindi, invece, utilizziamo:

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

Quanto sopra produce Y9;v99;, che, se valutato, produce lo stesso risultato di una semplice v99(vale a dire, il carattere con codice ASCII 99).

Quindi possiamo usare l'intero ^B^V^S(*-/9;<>HJMOY[`\^begqstvset di caratteri per generare la nostra stringa arbitraria, quindi convertirla come sopra e incollarla in a s<><CODE>eeeeper eseguirla. Sfortunatamente, questo set di caratteri è ancora molto limitato, senza alcun modo ovvio per eseguire la concatenazione.

Ma per fortuna contiene la stella. Questo ci permette di scrivere *b, che valuta la stringa "*main::b". Poi, *b^<^B[MMH^V^SY>(^ B, ^ ^ V e S sono i caratteri di controllo letterali) ci dà (6, $&);, che, quando eval-ed ancora una volta, restituisce il valore della variabile partita di Perl, $&. Questo ci consente di utilizzare una forma limitata di concatenazione: possiamo anteporre ripetutamente le cose $_all'utilizzo s<^><THINGS>ee quindi utilizzare s<\H*><*b^<^B[MMH^V^SY>>eeeper valutare $_( \Hcorrisponde a tutto tranne che agli spazi bianchi orizzontali; lo usiamo al posto del punto, che non è nel nostro set di caratteri).

Utilizzando 9-/, possiamo facilmente generare tutte le cifre. Usando cifre, ve concatenazione, possiamo generare caratteri arbitrari (vXXX restituisce il carattere con il codice ASCII XXX). E possiamo concatenarli, così possiamo generare stringhe arbitrarie. Quindi sembra che possiamo fare qualsiasi cosa.

Scriviamo un esempio completo. Supponiamo di voler un programma che stampi il proprio PID. Iniziamo con il programma naturale:

say$$

Lo convertiamo in v-notation:

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

Lo riscriviamo usando solo ^B^V^S(*-/9;<>HJMOY[`\^begqstv(gli spazi sono solo per leggibilità e non influiscono sull'output):

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;

Infine, convertiamo il programma sopra in solo <>^es: pastebin . Purtroppo, questo si blocca con Perl Excessively long <> operator, ma è solo una limitazione tecnica e non dovrebbe essere preso in considerazione.

Accidenti, è stato un bel viaggio. Sarebbe davvero interessante vedere qualcuno inventare un set di 5 personaggi che semplifica le cose.

EDIT: utilizzando un approccio leggermente diverso, possiamo evitare di colpire il limite di lunghezza <>. Interprete brainfuck completamente funzionale usando solo <>^es: provalo online! . Perl automatizzato al <>^estranspiler: pastebin .


1
Vedo ... la tua codifica ottiene un ingrandimento quadratico perché i tuoi personaggi si dividono in due gruppi, uno che può essere prodotto solo xorando un numero pari di caratteri base e un altro che può essere prodotto solo da un numero dispari, costringendoti a aggiungi un altro glob ogni volta che cambi tra di loro. Hai qualche possibilità di dividere il programma in pezzi valutabili più brevi legati insieme ^o con altri personaggi di base?
Ørjan Johansen,

@ ØrjanJohansen Sì, buon lavoro. Sto lavorando a una soluzione in questo momento.
Grimy,

Puoi trasformare quell'esempio ridotto in un link TIO Provalo online!
Ørjan Johansen,

7
Richiesta: Spiega questo "approccio leggermente diverso"
CalculatorFeline

32

Python 2, 7 caratteri

exc="%\n

Qualsiasi programma Python 2 può essere codificato usando questi 7 caratteri ( \nè newline).

Costruire stringhe arbitrarie

È possibile eseguire la concatenazione applicando ripetutamente l'operatore di sostituzione %su una singola stringa. Ad esempio, se a=1, b=2, c=3, "%d%%d%%%%d" % a % b % cci darà la stringa "123". Fortunatamente, le lettere execci danno accesso %xe %cche sono fondamentalmente hex()e chr(). Con %c, possiamo costruire qualsiasi stringa fintanto che abbiamo i numeri necessari che rappresentano i caratteri. Possiamo quindi eseguire questa stringa come codice Python usando la execparola chiave.

Crea numeri

Siamo in grado di accedere a 0e 1subito con i confronti ( ==). Attraverso una combinazione di cifre concatenanti e modulo, è possibile costruire il numero 43che rappresenta +in ASCII. Questo ci consente di costruire i numeri di cui abbiamo bisogno per il nostro codice.

Mettendolo insieme

Ho omesso diversi dettagli in questa spiegazione poiché non sono essenziali per capire come i programmi con questi vincoli possono essere scritti. Di seguito è riportato un programma Python 2 che ho scritto che converte qualsiasi programma Python in una versione funzionalmente equivalente che utilizza solo questi 7 caratteri. Le tecniche utilizzate sono ispirate da questa presentazione sul golf dell'anarchia di k. Alcuni semplici trucchi vengono anche utilizzati per mantenere le dimensioni dei programmi generati entro limiti ragionevoli.

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

Provalo online


È possibile aggiungere alcuni controlli per vedere se il programma di input è già limitato al set di caratteri necessario e, in tal caso, solo cat.
mbomb007

26

Mathematica, 5 4 personaggi

I[]

è un carattere Unicode di uso privato , che funge da operatore per Functionconsentire di scrivere letterali per funzioni senza nome con argomenti denominati. Il personaggio assomiglia molto a Mathematica, quindi lo userò per il resto di questa risposta per chiarezza.

L'utilizzo di questi, siamo in grado di implementare il S, Ke Icombinatori della logica combinatoria:

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

Un problema sintattico con questi è che ha una precedenza molto bassa che sarà un problema se proviamo a passare argomenti a questi combinatori. Normalmente lo aggiusteresti avvolgendo un combinatore Ctra parentesi come (C), ma non abbiamo parentesi. Tuttavia, possiamo usare Ie []avvolgere Cqualche altra magia che abbia una precedenza sufficientemente elevata da poterla utilizzare in seguito:

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

Infine, per scrivere un'applicazione A x y z(dove Aè un combinatore "parentesi," come mostrato sopra, e x, y, zpuò o non può essere, tra parentesi, o può essere espressioni più grandi), si può scrivere:

A[x][y][z]

Ciò lascia la questione di come funzioni effettivamente l'equivalente tra parentesi. Proverò a spiegarlo all'incirca nell'ordine in cui me ne sono inventato.

Quindi la cosa che abbiamo sintatticamente per raggruppare qualcosa sono le parentesi []. Le parentesi appaiono in due modi in Mathematica. O come invocazioni di funzioni f[x]o come operatore di indicizzazione f[[i]](che in realtà è solo una scorciatoia per Part[f, i]). In particolare, ciò significa che né [C][[C]]è valida la sintassi. Abbiamo bisogno di qualcosa di fronte. In teoria può essere qualsiasi cosa. Se usiamo il Igià presente, possiamo ottenere I[C]ad esempio. Ciò non viene valutato, perché Inon è una funzione unaria (non è affatto una funzione).

Ma ora abbiamo bisogno di un modo per estrarre di Cnuovo, perché altrimenti non verrà effettivamente valutato quando proviamo a passargli un argomento x.

Qui è utile che f[[i]]può essere utilizzato per espressioni arbitrarie f, non solo per elenchi. Supponendo che fessa stessa sia della forma head[val1,...,valn], quindi f[[0]]head, f[[1]]val1, f[[-1]]valne così via. Quindi abbiamo bisogno di ottenere uno 1o -1di estrarre di Cnuovo, perché uno I[C][[1]]o I[C][[-1]]valuta C.

Siamo in grado di ottenere 1da un simbolo arbitrario definito come x, ma per fare questo, avremmo bisogno di un altro personaggio per la divisione ( x/x1per non definito x). La moltiplicazione è l'unica operazione aritmetica che possiamo eseguire senza caratteri aggiuntivi (in linea di principio), quindi abbiamo bisogno di un valore che può essere moltiplicato per dare -1o 1. Questo finisce per essere il motivo per cui ho scelto appositamente Iper i nostri identificatori. Perché di Iper sé è il simbolo incorporato di Mathematica per l'unità immaginaria.

Ma che lascia un ultimo problema: come possiamo effettivamente moltiplichiamo Iper sé? Non possiamo semplicemente scrivere IIperché viene analizzato come un singolo simbolo. Dobbiamo separare questi token senza a) cambiando il loro valore eb) usando nuovi caratteri.

Il bit finale di una magia è un pezzo di comportamento non documentato: f[[]](o equivalentemente Part[f]) è una sintassi valida e restituisce fse stessa. Quindi, invece di moltiplicare Iper I, moltiplichiamo I[[]]per I. Inserendo le parentesi, Mathematica cerca in seguito un nuovo token e I[[]]Ivaluta -1come richiesto. Ed è così che finiamo I[C][[I[[]]I]].

Si noti che non avremmo potuto usare I[]. Questa è un'invocazione senza argomenti della funzione I, ma come ho detto prima Inon è una funzione, quindi rimarrà sottovalutata.


Risposta meravigliosa
Patrick Stevens,

23

Python 2, 8 caratteri

exc'%~-0

Questi caratteri consentono la traduzione / esecuzione di qualsiasi programma Python usando stringhe di formato e exec. Anche se non è necessario tradurre alcun programma per completezza di Turing, questo è il minor numero di personaggi che conosco che lo rendono comunque TC. Che sia così potente è solo un bonus.

È possibile utilizzare anche una virgoletta doppia e una singola cifra oltre a zero. (Ora che ci penso, 1sarebbe sicuramente meglio, con conseguente programmi più brevi, dal momento che è possibile utilizzare 1, 11e 111, pure.)

Ecco il programma print:

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

Provalo online

Il programma di base richiede

exec''

Ogni personaggio xaggiunto al programma richiede (conteggio):

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

L'eccezione a questo è che alcune ottimizzazioni / scorciatoie potrebbero essere prese per rendere più breve il programma codificato, come usare %'0'per il carattere 0invece di 48 -~, ecc.

Usi pratici (golf AKA): ho usato questa tattica per risolvere questa sfida senza usare un personaggio con handicap aggiuntivo.

Riconoscimento dell'elenco dei caratteri e di un programma di codifica: qui

Per informazioni su come trovare un limite inferiore sulla dimensione del programma risultante (senza ottimizzazioni), vedere questo commento .

Il numero di byte richiesti aumenta O(2**n), quindi questo metodo non è raccomandato per giocare a golf. Un quine che utilizza questa restrizione della fonte sarebbe follemente lungo.


Se solo la precedenza dell'operatore fosse eseguita +o -prima di %, potremmo rimuovere un carattere.
mbomb007,

Vale la pena notare che poter tradurre ogni programma Python nel set di caratteri ridotto non è necessario per la completezza di Turing. Anche se immagino che sarà difficile ottenere la quantità richiesta di flusso di controllo senza usare execcomunque.
Martin Ender,

Questo non è nemmeno tecnicamente un linguaggio Turning Complete, vero? Ha la capacità di chiamare l'interprete per un linguaggio Turning Complete, che è l'interprete Python incorporato. Funzionerebbe in qualsiasi lingua, indipendentemente dal fatto che sia Turning Complete, purché abbia la capacità, ad esempio, di invocare un comando shell a un altro interprete.
mmachenry,

@mmachenry Python utilizza il proprio compilatore e interprete. Non sta usando un'altra lingua separata. E un interprete brainfuck è stato creato in Python, quindi è Turing Complete. Usando questa conoscenza, il tuo argomento è falso.
mbomb007,

@ mbomb007 No, il mio argomento non è falso. Python è un linguaggio Turning Complete, ovviamente. Il calcolo viene eseguito chiamando un interprete Python da Python utilizzando qualsiasi carattere desiderato per la chiamata interna. Il linguaggio in cui stai specificando il programma è semplicemente una codifica, non un linguaggio di programmazione. Usando questo, è banale rendere letteralmente ogni linguaggio di programmazione Turing completo usando i caratteri 0 e 1 e visualizzando i file sorgente come binari. Lo spirito della domanda è di trovare un sottoinsieme sintattico della lingua attuale.
mmachenry

23

C (non portabile), 24 18 13 caratteri

aimn[]={};,1+

Questo copre tutti i programmi del modulo

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

... dove la sequenza di costanti (nella forma 1 + 1 + 1 ...) contiene la rappresentazione del codice macchina del programma. Questo presuppone che il tuo ambiente consenta l'esecuzione di tutti i segmenti di memoria (apparentemente vero per tcc [grazie @Dennis!] E alcune macchine senza bit NX). Altrimenti, per Linux e OSX potrebbe essere necessario anteporre la parola chiave conste per Windows potrebbe essere necessario aggiungere un #pragmacontrassegno esplicito il segmento come eseguibile.

Ad esempio, il seguente programma scritto nello stile sopra stampa Hello, World!su Linux e OSX su x86 e x86_64.

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};

Provalo online!


2
@GB: Zero è abbastanza facile evitare di usare almeno il codice macchina x86 (non è un'istruzione terribilmente importante), soprattutto perché il problema si verifica solo se si hanno quattro zero byte di fila.

2
@GB Su una macchina con ints a 32 bit0==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 ti lascia andare via senza const. tio.run/nexus/…
Dennis il

8
@GB Ho appena realizzato una rappresentazione più breve di 0 is1==11
ceilingcat,

3
@ wizzwizz4, non è C pura in ogni caso, non in alcun senso che lo rende Turing completo. Non ha alcuna semantica in C. Dato che stai comunque facendo affidamento sui dettagli del compilatore e dell'ambiente di esecuzione per ottenere qualsiasi cosa eseguibile, potresti anche consentire un punto di ingresso nominato arbitrariamente.
John Bollinger,

20

Retina , 6 caratteri

$%`{¶

Oltre ai feed di linea (0x0A).

Da un lato sono sorpreso di essere riuscito a farlo così in basso. D'altra parte, sono molto scontento dell'inclusione di . Ognuno di essi $`{viene riutilizzato per due o anche tre scopi, ma insieme servono solo uno scopo. Ciò li rende piuttosto dispendiosi e distrugge leggermente l'eleganza dell'approccio. Spero che ci sia un modo per battere questa costruzione.

Alla prova. Descriverò un modo semplice per tradurre i sistemi di tag ciclici in Retina usando i caratteri sopra.

Prima di tutto, useremo `e {per l'alfabeto binario invece di 0e 1. Questi sono convenienti, perché non hanno bisogno di essere salvati in una regex, ma hanno significato per Retina o nella sintassi di sostituzione. Sto usando `per 0e {per 1, ma questa scelta è arbitraria. Inoltre, invertiremo la stringa (e le produzioni) in memoria, perché lavorare con l'ultimo carattere ci consente di usare $e $`invece di ^e $', massimizzando il riutilizzo dei caratteri.

Se la parola iniziale è indicata da Se iviene chiamata la produzione th (invertita) , il programma risultante sarà simile al seguente:pi


S
{`

{$
¶p1$%``
``$

{$
¶p2$%``
``$

{$
¶p3$%``
``$

...

Questa costruzione inevitabilmente cresce in memoria ogni volta che viene applicata una produzione ed è improbabile che termini - in effetti, nel punto in cui il sistema di tag ciclico terminerebbe (quando la stringa di lavoro si svuota), il comportamento del risultante programma Retina diventa sostanzialmente indefinito.

Diamo un'occhiata a cosa fa il programma:


S

Iniziamo inizializzando la stringa di lavoro sulla parola iniziale.

{`

Questo avvolge il resto del programma in un programma che viene eseguito fino a quando non riesce a modificare la stringa risultante (ehi, ingenuo rilevamento a ciclo infinito incorporato gratuitamente ...). I due avanzamenti di riga non sono realmente necessari, ma separano il ciclo più chiaramente dalle singole produzioni. Il resto del programma passa attraverso ciascuna delle produzioni e, a causa del ciclo, le stiamo effettivamente elaborando ciclicamente più e più volte.

Ogni produzione viene elaborata in due fasi. Innanzitutto trattiamo il caso in cui il simbolo principale (o nel nostro caso finale) sia {, nel qual caso utilizziamo la produzione:

{$
¶pi$%``

La regex corrisponde solo se la stringa finisce {. In tal caso, lo sostituiamo con:

  • Un linefeed ( ). Lavoreremo sempre e solo con l'ultima riga della stringa di lavoro, quindi questo effettivamente elimina la stringa di lavoro finora (motivo per cui l'utilizzo della memoria del programma crescerà e crescerà).
  • La produzione corrente ( ), che con la presente stiamo anteponendo alla stringa di lavoro (dove il sistema di tag ciclico lo aggiunge).pi
  • La stringa di lavoro rimanente precedente ( $%`). Questo è il motivo per cui dobbiamo inserire : $%`raccoglie tutto ciò che resta della partita, ma solo sulla stessa riga. Quindi, questo non vede tutta la spazzatura che abbiamo lasciato dalle produzioni precedenti. Questo trucco ci consente di abbinare qualcosa alla fine della stringa di lavoro per inserire qualcosa all'inizio della stringa di lavoro, senza dover usare qualcosa di simile (.+)e $1che farebbe saltare in modo significativo il numero di caratteri di cui abbiamo bisogno.
  • Un singolo backtick ( `). Questo sostituisce efficacemente il {( 1-simbolo) che abbiamo abbinato con un `( 0-simbolo) in modo che la fase successiva non abbia bisogno di sapere se abbiamo già elaborato la produzione attuale o meno.

La seconda parte di ogni produzione è quindi il banale caso in cui la produzione viene saltata:

``$

Eliminiamo semplicemente un finale `. La ragione per cui abbiamo bisogno di due `sulla prima riga è che Retina considera il primo backtick come il divisore tra configurazione e regex. Questo semplicemente gli dà una configurazione vuota in modo che possiamo usare i backtick nella regex stessa.


20

Java 7, 18 17 caratteri

\bcdefu0123456789

Tutto il codice sorgente Java può essere ridotto a punti di codice Unicode. "a" non è necessario poiché è utilizzato solo per *:jJzZ. L'asterisco viene utilizzato per moltiplicare o bloccare i commenti. La moltiplicazione è solo un'aggiunta ripetuta e puoi invece utilizzare i commenti a riga singola (o semplicemente ometterli). I due punti vengono utilizzati per gli operatori ternari, per i quali è possibile utilizzare un'istruzione if per invece i cicli foreach, che possono essere sostituiti con normali per i loop. j e z non fanno parte di alcuna parola chiave in Java.

Il tentativo di rimuovere qualsiasi altro carattere richiede di aggiungere almeno uno dei caratteri richiesti nella piastra della caldaia Java class a{public static void main(String[]a){}}. Vedi sotto:

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")

Ecco un esempio con un programma Hello World Provalo online!

Java 8, 16 caratteri

\bdefu0123456789

Grazie a ais523 per averlo segnalato. Java 8 consente alle interfacce di avere metodi statici, il che significa che possiamo eliminare "c" perché non ne abbiamo bisogno per la "l" nella "classe". "c" è usato per ,<lL\|così finiamo per perdere un po 'più funzionalità java rispetto a quando abbiamo rimosso "a" ma abbiamo ancora abbastanza per essere completati. Provalo online!


3
Sicuramente, capire quale delle cifre esadecimali può essere omessa è la parte interessante della risoluzione di questo in Java? :)
Martin Ender,

@MartinEnder assolutamente. Ho intenzione di lavorarci di più quando avrò del tempo
Poke

6
E io che ero pronto a scrivere qualcosa Java, 127 characters... Bello, Poke;)
Olivier Grégoire,

Sulla base dei caratteri richiesti nella mia risposta , non credo che sia possibile rimuovere altre cifre esadecimali.

3
Se passi a Java 8, puoi farlo in 16; Java 8 consente alle interfacce di avere metodi statici, permettendoti di rilasciare c(tutte le lettere interfacesono ancora accessibili senza ao cnei tuoi letterali esadecimali).

19

Labirinto , 5 personaggi

~{}

Plus linefeed (0x0A) e spazi (0x20).

Ho intenzione di delineare una prova sotto forma di una riduzione da Smallfuck (una variante Brainfuck ridotta che utilizza celle a 1 bit). Si noti che Smallfuck stesso non è completo di Turing perché il linguaggio specifica che il suo nastro deve essere finito, ma assumeremo una variante di Smallfuck con un nastro infinito, che sarebbe quindi completo di Turing (poiché Labyrinth non ha memoria restrizioni in base alla progettazione).

Un importante invariante in tutta questa riduzione sarà che ogni programma (o sottoprogramma) si tradurrà in un programma Labyrinth (o sottoprogramma) che inizia e termina sulla stessa riga e si estende su un numero pari di colonne.

Labyrinth ha due pile che inizialmente sono riempite con una quantità infinita (implicita) di 0s. {e }sposta il valore più alto tra queste pile. Se consideriamo la parte superiore dello stack principale come la "cella" corrente, allora queste due pile possono essere viste come le due metà semi-infinite del nastro infinito usato da Smallfuck. Tuttavia, sarà più conveniente avere due copie di ciascun valore di nastro sugli stack, per garantire l'invariante sopra menzionato. Pertanto <e >saranno tradotti in {{e }}, rispettivamente (puoi scambiarli se vuoi).

Invece di consentire i valori di cella 0e 1, stiamo usando 0e -1, che possiamo alternare con ~(negazione bit a bit). I valori esatti non contano ai fini della completezza di Turing. Dobbiamo cambiare entrambe le copie del valore nello stack, il che ci dà di nuovo una traduzione di lunghezza pari: *diventa ~}~{.

Ciò lascia i comandi del flusso di controllo []. Labyrinth non ha un flusso di controllo esplicito, ma invece il flusso di controllo è determinato dal layout del codice. Richiediamo gli spazi e gli avanzamenti di riga per eseguire tale layout.

Innanzitutto, nota che ~~è una no-op, poiché i due si ~annullano effettivamente. Possiamo usarlo per avere percorsi arbitrariamente lunghi nel codice, purché la loro lunghezza sia pari. Ora possiamo usare la seguente costruzione per tradurre AA[BB]CCin Labyrinth (sto usando doppie lettere in modo che la dimensione di ogni frammento in Labyrinth sia pari, come garantito dall'invariante):

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

Qui, ..c'è un numero adatto di ~cui corrisponde la larghezza di BB.

Ancora una volta, nota che la larghezza della costruzione rimane uniforme.

Ora possiamo esaminare come funziona questo ciclo. Il codice viene inserito tramite AA. Il primo ~~non fa nulla e ci permette di raggiungere l'incrocio. Ciò corrisponde approssimativamente a [:

  • Se il valore della cella corrente è zero, l'IP continua dritto, il che salterà alla fine BB. La ..parte è ancora vietata. Quindi raggiungiamo un singolo ~in un altro incrocio. Ora sappiamo che il valore corrente è diverso da zero, quindi l'IP prende la svolta a nord. Gira intorno alla curva in alto, fino a raggiungere un altro incrocio dopo le sei ~. Quindi a quel punto il valore corrente è ancora diverso da zero e l'IP fa di nuovo il giro per spostarsi verso est verso il CC. Si noti che i tre ~precedenti alla CCrestituzione restituiscono il valore corrente 0, come dovrebbe essere quando il ciclo è stato ignorato.
  • Se il valore della cella corrente all'inizio del loop è diverso da zero, l'IP prende la svolta a sud. Corre altri sei ~prima di raggiungere BB(che non fanno nulla), e poi altri sei ~prima di raggiungere l'incrocio successivo. Questo corrisponde approssimativamente al ].
    • Se la cella corrente è zero, l'IP continua a spostarsi verso nord. Il successivo ~rende il valore diverso da zero, in modo che l'IP prenda questo secondo nodo, che unisce il percorso con il caso in cui il ciclo è stato saltato completamente. Ancora una volta, i tre ~riportano il valore a zero prima di raggiungere CC.
    • Se la cella corrente è diversa da zero, l'IP prende la svolta a ovest. Ci sono ~prima del prossimo incrocio, il che significa che a questo punto il valore corrente è zero in modo che l'IP continui ad andare verso ovest. Quindi ci sarà un numero dispari ~prima che l'IP raggiunga nuovamente la giunzione iniziale, in modo che il valore venga restituito -1e l'IP si sposta a sud nella successiva iterazione.

Se il programma contiene dei loop, il primo AAdeve essere esteso all'inizio del programma in modo che l'IP trovi la cella corretta su cui iniziare:

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

Questo è quanto. Si noti che i programmi derivanti da questa riduzione non verranno mai chiusi, ma ciò non fa parte dei requisiti di completezza di Turing (si consideri la Regola 101 o Fractran).

Alla fine, ci resta la domanda se sia ottimale. In termini di caratteri del carico di lavoro, dubito che sia possibile fare meglio di tre comandi. Ho potuto vedere una costruzione alternativa basata su macchine Minsky con due registri, ma ciò richiederebbe =()o =-~, avendo solo un comando di manipolazione dello stack ma poi due comandi aritmetici. Sarei felice di essere smentito su questo. :)

Per quanto riguarda i comandi di layout, credo che siano necessari gli avanzamenti di riga, poiché un flusso di controllo utile è impossibile su una sola riga. Tuttavia, gli spazi non sono tecnicamente necessari. In teoria potrebbe essere possibile escogitare una costruzione che riempia l'intera griglia con ~{}(o =()o =-~) o che faccia uso di un layout irregolare in cui le linee non sono tutte della stessa lunghezza. Tuttavia, scrivere codice in questo modo è incredibilmente difficile, perché Labyrinth tratterà quindi ogni singola cella come una giunzione e devi stare molto attento a evitare che il codice si ramifichi quando non lo desideri. Se qualcuno può dimostrare o smentire se l'omissione dello spazio è possibile per completezza di Turing, sarei felice di dare una generosa taglia per questo. :)


19

Haskell, 5 7 caratteri

()\->=;

Come linguaggio funzionale, Haskell ovviamente ha lambda, quindi simulare il calcolo lambda è facile. La sintassi per lambdas è quindi abbiamo bisogno almeno dei personaggi . Inoltre, abbiamo bisogno di un numero illimitato di simboli variabili per poter costruire espressioni lambda arbitrarie. Per fortuna non abbiamo bisogno di nessun nuovi personaggi per questo, perché , , , ..., sono tutti nomi di variabili validi. In effetti ogni combinazione di parentesi interne è un nome di variabile valido, ad eccezione di just e , che sono riservati per le espressioni lambda e , che inizia un commento di riga.(\variable->body)argument()\->
(>)(>>)(>>>)\->\->--

Esempi:

  • S = (\(>)(\\)(-)->(>)(-)((\\)(-)))tipi a(t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1
  • K = (\(>)(-)->(>))tipi at -> t1 -> t
  • I = (\(>)->(>))tipi at -> t

Modifica: Tuttavia, come ha sottolineato ais523 nei commenti, questa costruzione implementa il calcolo lambda tipizzato , che di per sé non è completo di Turing perché manca della possibilità di inserire loop infiniti. Per risolvere questo problema, abbiamo bisogno di alcune funzioni che eseguono la ricorsione. Finora abbiamo usato lambda senza nome, che non possono chiamarsi, perché, beh, non hanno un nome. Quindi dobbiamo aggiungere i caratteri =e ;implementare una fixfunzione:

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

Con questa dichiarazione il nostro calcolo lambda diventa Turing completo, tuttavia dopo aver aggiunto =e ;, non abbiamo più bisogno di lambda, come puoi vedere nella risposta di Nimi che usa solo ()=;.


Non verrà tecnicamente rimosso al momento della compilazione senza main ?
PyRulez,

4
Il calcolo del combinatore SKI tipizzato in modo semplice non è completo di Turing; hai bisogno di un calcolo lambda non tipizzato per quello. Sfortunatamente, come menzionano le tue dimostrazioni, Haskell inserisce un'interpretazione tipizzata nel codice per impostazione predefinita.

@PyRulez Secondo le regole predefinite ho assunto che le funzioni fossero accettabili.
Laikoni

@ ais523 I combinatori SKI sono solo un esempio, usando la notazione data si possono costruire termini lambda arbitrari, ad esempio numeri di chiesa e funzioni su di essi.
Laikoni,

@ ais523 di quanti combinatori deve essere completato Lambda Calculus? Penso che tu abbia solo bisogno del combinatore y, giusto?
PyRulez,

18

CJam, 3 personaggi

Rimosso )secondo il suggerimento di Martin Ender

'(~

Simile a quello di Python fornito come esempio.

utilizzando '~ puoi ottenere il ~personaggio. Quindi utilizzando (, è possibile diminuirlo per ottenere qualsiasi carattere desiderato ( ~è l'ultimo carattere ASCII stampabile). ~elimina qualsiasi stringa come normale codice CJam. Le stringhe possono essere costruite ottenendo il personaggio [(attraverso il decremento ~), valutandolo, mettendo una sequenza di altri personaggi, quindi valutando il personaggio ]. Attraverso questo, puoi costruire ed eseguire qualsiasi programma CJam usando solo questi tre caratteri.

Calcolo di 2 + 2 usando solo '(~


per un'altra sfida, qualcuno ha creato un programma che prende qualsiasi programma cjam e lo compila automaticamente in questo sottoinsieme. Vorrei poterlo trovare
Zwei

1
Sono riuscito a giocare a golf sul programma 2 + 2 in modo significativo'~((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~
Zwei

@Zwei fantastico, che si adatta al tuo nome
Chromium

18

Brain-Flak , 6 personaggi

(){}[]

Brain-Flak è un linguaggio minimalista con solo 8 caratteri disponibili. Tuttavia, si può dimostrare che esiste un sottoinsieme di Brain-Flak che è anche Turing completo usando solo 6 caratteri.

La prima cosa che faremo è implementare una macchina Minsky con una sola pila di Brain-Flak. Se possiamo dimostrare che una macchina Minsky è possibile con un solo stack, possiamo dimostrare che Brain-Flak è Turing completo senza il <>e[] nilad. Questo non salverà immediatamente alcun personaggio ma lo farà in futuro quando mostreremo che <...>non è necessario.

Una macchina Minsky è un tipo di automa completo di Turing che ha un numero finito di registri illimitati e due istruzioni:

  • Incrementa il registro a

  • Se decrementa diverso da zero, altrimenti passa a un'istruzione specifica

Per impostare una struttura goto in Brain-Flak possiamo usare il seguente frammento:

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

Questo diminuirà il contatore ed eseguirà %s se zero. Un gruppo di questi concatenati ci permetterà di mettere un numero in pila che indicherà quale linea vogliamo andare. Ognuno di questi ridurrà la parte superiore dello stack ma solo uno di essi eseguirà effettivamente il codice.

Lo usiamo come involucro per tutte le nostre istruzioni Minsky Machine.

Incrementare un registro particolare è abbastanza facile senza cambiare lo stack. Può essere ottenuto con questa formula di stringa:

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

Ad esempio per incrementare il 3 ° registro dovremmo scrivere il seguente codice:

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

Ora non ci resta che attuare la seconda operazione. Controllare se un numero è zero è abbastanza semplice in Brain-Flak:

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

verrà eseguito solo %sse il TOS è zero. Quindi possiamo fare la nostra seconda operazione.

Poiché le macchine Minsky sono Turing complete, Brain-Flak è anche Turing completa senza l'uso di <>e[] operazioni .

Tuttavia non abbiamo ancora ridotto il numero di caratteri perché <...>e [...]sono ancora in uso. Questo può essere risolto con una semplice sostituzione. Dato che in <...>realtà è equivalente a [(...)]{}in tutti i casi. Quindi Brain-Flak è Turing completo senza l'uso dei caratteri <e >(più tutti i no-op).


"perché <...>e [...]sono ancora in uso." Tuttavia, non è stato rimosso [...]. Per favore, aggiusta.
Calcolatrice

Domanda: è [...]davvero necessario? Il push di 0 può essere fatto all'inizio con ({})(ma si basa su uno stack vuoto, quindi gli 0 dovranno essere mescolati con cura) Il problema principale è riuscire a scendere lo stack senza accesso a <...>(che non può più essere simulato)
Calcolatrice

16

> <> , 3 caratteri

> <> è fattibile in 3 con 1p-, che fanno:

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

pfornisce riflessione, modificando il codice sorgente 2D inserendo i caratteri nella casella del codice. Con 1-, puoi spingere qualsiasi numero nello stack poiché 1-sottrae uno e 111-1--( x-(1-1-1) = x+1) ne aggiunge uno.

Una volta 1p-eseguiti tutti i comandi, il puntatore dell'istruzione si avvolge, consentendogli di eseguire il codice "reale".

Un programma di esempio che calcola i numeri di Fibonacci (da questa risposta ) è:

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

Provalo online! Una volta 1p-eseguiti tutti i comandi, la codebox appare così:

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

Escludendo tutto dopo la vprima riga, questo è un programma standard di Fibonacci> <>.


13

bash, 9 caratteri

01456\$ '

Bash ha una sintassi $'\nnn'per inserire caratteri con i loro valori ascii ottali. Possiamo inserire il evalcomando in questo formato come $'\145\166\141\154'. Innanzitutto trasformiamo il risultato desiderato nei suoi valori ottali. Quindi convertiamo tutti i valori ottali usando cifre diverse da 0, 1, 4, 5 e 6 in espressioni che valutano i suddetti valori ottali usando $(())e sottrazione, aggiungendo una evalin primo piano. Nel nostro passaggio finale, ne aggiungiamo un altro evale convertiamo le parentesi e il segno meno nei loro valori ottali. Usando questo metodo possiamo eseguire qualsiasi comando bash, quindi questo sottoinsieme è in fase di completamento.

Esempio:

dc diventa

$'\144\143' che diventa

$'\145\166\141\154' \$\'\\144\\$((144-1))\' che diventa

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


12

Incidente , 2 caratteri

Non importa nemmeno quali due personaggi scegli; qualsiasi combinazione di due ottetti è Turing-completa in Incidente.

Provare effettivamente questo è molto più difficile di quanto ci si possa aspettare, e al momento in cui scrivo, la pagina di discussione su Esolang sull'incidente è dedicata al problema. Cercherò comunque di fornire un riepilogo della dimostrazione più semplice conosciuta di seguito.

Prima della prova, alcuni retroscena. L'incidente infligge i token utilizzati nel programma osservando l'origine (un token è una stringa che appare esattamente tre volte nell'origine, non è una sottostringa di un altro token e non si sovrappone a un altro potenziale token). In quanto tale, qualsiasi programma può essere convertito per usare praticamente qualsiasi set di caratteri modificando i token; la lingua è Turing-complete (e ha completezza anche per l'I / O!), nonostante sia incredibilmente difficile da programmare, quindi "tutto" è un metodo per codificare i token in modo che funzionino con solo due caratteri.

E ora, ecco un riassunto della prova (che è stata trovata da Ørjan, matematico residente a Esolang). L'idea è che codifichiamo un token usando due copie di un personaggio (diciamo 1) in un grande mare dell'altro personaggio (diciamo 0). La distanza tra le 1s differisce per ogni token, ma è sempre un multiplo di 4. Quindi per il riempimento tra i token, usiamo un ulteriore elenco di 0s con a 1nel mezzo, ma il numero di 0 su ciascun lato di 1è non un multiplo di 4, ma piuttosto un numero unico per quella particolare incidenza del programma che non appare altrove nel programma. Ciò significa che ciascuno1 ...1all'interno dell'imbottitura può apparire solo due volte, quindi non farà parte di un token; ogni token previsto contiene esattamente due 1 e nessun token fasullo può contenere più di uno 1. Quindi aggiungiamo solo un po 'di imbottitura sul lato per rimuovere tutti i possibili token contenenti uno aggiungendone almeno quattro copie.1 o zero1


11

Retina , 3 personaggi

{`

e newline.

Prima di tutto, abbiamo bisogno di Newline per poter fare delle sostituzioni (necessario a meno che non vogliamo adattare l'intero programma in una regex, che avrebbe bisogno di più caratteri); e `e {sono il modo meno intensivo per eseguire i loop. Si scopre che non abbiamo bisogno di nient'altro.

Il nostro linguaggio di destinazione da implementare è una variante deterministica di Thue (il non determinismo non è necessario per la completezza di Turing; è possibile scrivere un programma Thue per funzionare correttamente indipendentemente dall'ordine di valutazione utilizzato). L'idea di base è compilarepattern::=replacement in

`pattern
replacement

(che è una traduzione diretta della Retina della Gio; in alternativa, se conosci la Retina ma non la Tu, puoi usarla come metodo per apprendere come funziona la Gioia); come eccezione, il primo modello è preceduto da{` invece, (al fine di posizionare l'intero programma in un ciclo; I programmi continuano a essere eseguiti fino a quando non sono più possibili sostituzioni e questo fa sì che Retina funzioni allo stesso modo).

Naturalmente, questo significa che abbiamo bisogno di dimostrare Thue Turing-complete con un solo {e `nei modelli e la sostituzione, ma questo è abbastanza semplice; sostituiamo un carattere con il codice ASCII n con `, n +1 {e un altro `. È chiaramente impossibile che uno schema corrisponda ovunque ma ai confini del personaggio, quindi questo finirà per fare la stessa cosa del programma originale.


1
"Quindi i programmi continuano a funzionare fino a quando non sono più possibili sostituzioni e questo fa sì che Retina funzioni allo stesso modo" con la sola eccezione che Retina terminerà in anticipo se un passaggio attraverso l'intero programma non riesce a cambiare la stringa. Quindi ottieni persino un semplice rilevamento a ciclo infinito gratuitamente.
Martin Ender,

1
Ah giusto. Ciò non influisce sulla completezza di Turing, ovviamente (perché un ciclo infinito che non cambia lo stato interno non può contribuire alla classe computazionale di un programma).

10

Brachylog , 5 personaggi

~×₁↰|

Questo sottoinsieme di caratteri ci consente di implementare una versione di Fractran in cui gli unici numeri che possono apparire sono prodotti di ricompense (ovvero prodotti di numeri che possono essere scritti in decimali usando solo la cifra 1). (con un numero intero come indice) divide il valore corrente per quel numero intero, ma solo se si divide esattamente (altrimenti "non riesce" e cerca un altro caso da eseguire; |separa i casi). ×ci moltiplica per un numero intero. Quindi utilizzando ~×₁|possiamo implementare un passaggio di un'esecuzione di Fractran. Quindi, possiamo ricorrere, eseguendo di nuovo l'intero programma sul nuovo valore corrente. Ecco un esempio di un programma Fractran molto semplice (11111111111111111111111/111 ) tradotto in Brachylog.

Quindi questo Turing è completo? Tutto ciò di cui abbiamo bisogno per completare Fractran Turing è una quantità sufficientemente grande di numeri primi (abbastanza per scrivere un interprete per una lingua completa di Turing nello stesso Fractran). Ci sono cinque provati e quattro sospettatirepunit primes, oltre a, molto probabilmente, quelli che non sono stati ancora scoperti. Questo è in realtà più di quanto abbiamo bisogno in questo caso. Il programma controlla le possibilità da sinistra a destra, quindi possiamo usare un numero primo come puntatore di istruzione e altri due come contatori, dimostrando la completezza di Turing con solo tre numeri primi (una cosa buona anche perché ci consente di usare le ricompense con 2, 19 e 23 cifre, senza dover ricorrere a rimontaggi comprovati ma fastidiosamente grandi con 317 o 1031 cifre, il che renderebbe il codice sorgente abbastanza difficile da scrivere). Ciò consente di implementare una macchina Minsky con due contatori (sufficiente per completezza di Turing).

Ecco come funziona la compilation in modo specifico. Utilizzeremo i seguenti due comandi per l'implementazione della nostra macchina Minsky (questo è noto come Turing completo) e ogni comando avrà un numero intero come etichetta:

  • Etichetta L: se il contatore {A o B} è zero, vai su X. Altrimenti diminuiscilo e vai su Y.
  • Etichetta L: incrementa il contatore {A o B}, quindi vai a Z.

Scegliamo quale comando eseguire posizionando i poteri di 11 nel denominatore, i poteri più alti per primi; l'esponente di 11 è l'etichetta del comando. In questo modo, la prima frazione che corrisponde sarà il comando attualmente in esecuzione (perché i precedenti non possono essere divisi per tutti quegli 11). Nel caso di un comando di decremento, inseriamo anche un fattore di 1111111111111111111 o 11111111111111111111111 nel denominatore, rispettivamente per il contatore A o B, e lo seguiamo con un altro comando senza tale fattore; il caso "decremento" sarà implementato dal primo comando, il caso "zero" dal secondo. Nel frattempo, il "goto" verrà gestito da una potenza appropriata di 11 nel numeratore e "incrementato" tramite un fattore di 1111111111111111111 o 1111111111111111111111111 nel numeratore.


Qualche motivo particolare per cui non puoi usare le coprime coprime a coppie?
CalculatorFeline

@CalculatorFeline: No, ma non ci ho pensato fino a quando non ho già trovato la costruzione che non ne aveva bisogno. Sarebbe sicuramente utile nei programmi di golf scritti con questo set di caratteri.

Inoltre, tutti i repunits> 1 sono coprimi a coppie (pensaci)
CalculatorFeline

@CalculatorFeline: No, non lo sono. 111 e 111111 sono entrambi divisibili per 3, abbastanza ovviamente.

* nessuna repunit divide un'altra repunit
CalculatorFeline

10

Befunge-98, 3 personaggi

Per quanto ne so, Befunge-98 dovrebbe essere completamente completo, quindi dobbiamo solo mostrare come qualsiasi programma Befunge-98 può essere generato usando solo tre caratteri. La mia soluzione iniziale si basava sui seguenti quattro caratteri:

01+p

Possiamo ottenere qualsiasi numero intero positivo nello stack aggiungendo più 1valori insieme al +comando e per zero semplicemente usiamo 0. Una volta che abbiamo la possibilità di spingere qualsiasi numero che vogliamo, possiamo quindi usare ilp comando (put) per scrivere qualsiasi valore ASCII in qualsiasi posizione nel campo di gioco di Befunge.

Tuttavia, come ha sottolineato Sp3000 , puoi effettivamente cavartela con solo i tre caratteri:

1-p

Qualsiasi numero negativo può essere calcolato iniziando con 1e quindi sottraendo ripetutamente 1(per esempio, sarebbe -3 11-1-1-1-). Quindi qualsiasi numero positivo può essere rappresentato sottraendo 1-n da 1, dove 1-n è un numero negativo che già sappiamo gestire (ad esempio, 4 = 1 - (- 3), che sarebbe111-1-1-1-- ).

Possiamo quindi usare i nostri tre caratteri per scrivere una sorta di bootloader che genera lentamente il codice effettivo che vogliamo eseguire. Al termine dell'esecuzione, questo caricatore si sposta all'inizio della prima riga del campo di gioco, che a quel punto dovrebbe contenere l'inizio del nostro nuovo codice generato.

Ad esempio, ecco un bootloader che genera il codice Befunge necessario per sommare 2 + 2 e produrre il risultato: 22+.@

E per un esempio leggermente più complicato, questo è "Hello World": "!dlroW olleH"bk,@


Questo è un poliglotta, gli stessi caratteri possono essere usati per> <> e i suoi derivati. Bel lavoro!
Ho

2
Befunge-98 è fattibile in 3 con 1p-pure
SP3000

@ Sp3000 Certo che sì! Ero sicuro che ci doveva essere un modo per ridurlo a 3 caratteri. Grazie.
James Holderness,

9

Rubino, 8 caratteri

eval"<1+

Ispirato dalle risposte di Python

Come funziona

  • eval può essere usato per eseguire una stringa arbitraria.
  • "<1+ è il set minimo di caratteri richiesto per creare qualsiasi stringa

Una stringa in ruby ​​può essere costruita usando la stringa vuota come punto di partenza e aggiungendo caratteri ASCII ad essa, quindi ad esempio:

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

è in realtà equivalente a

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

che valuta la stringa

p"o"

8

OCaml, 9 caratteri

fun->()`X

Questi caratteri sono sufficienti per implementare il calcolo del combinatore SKI in OCaml. In particolare, siamo in grado di evitare l'uso dello spazio con parentesi sufficiente. Sfortunatamente le espressioni lambda in OCaml richiedono ilfun parola chiave, quindi non è possibile una soluzione più concisa. Le stesse lettere possono essere utilizzate per costruire nomi di variabili arbitrarie se si desiderano espressioni lambda più complesse.

Combinatore S:

fun(f)(u)(n)->f(n)(u(n)) con il tipo ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c

Combinatore K:

fun(f)(u)->u con il tipo 'a -> 'b -> 'b

I Combinatore:

fun(f)->f con il tipo 'a -> 'a

Come notato da ais523, non è sufficiente codificare semplicemente SKI. Ecco una codifica per Z che utilizza varianti polimorfiche per manipolare il sistema di tipi. Con questo il mio sottoinsieme dovrebbe essere completo.

Combinatore Z:

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

con il tipo (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b


2
Il calcolo del combinatore SKI tipizzato in modo semplice non è completo di Turing; hai bisogno di un calcolo lambda non tipizzato per quello. Sfortunatamente, come menzionato nelle tue dimostrazioni, OCaml inserisce un'interpretazione tipizzata nel codice per impostazione predefinita.

1
Quindi ho semplicemente bisogno di qualche altro carattere per consentire l'uso di varianti polimorfiche che consentiranno di codificare il combinatore y (e allo stesso modo il combinatore z).
Devin Lehmacher,

Cos'è il combinatore Z?
Calcolatrice

@CalculatorFeline È una variante rigorosa del combinatore y. È necessario in OCaml perché OCaml non è pigro. Ecco un link alla pagina di Wikipedia: en.wikipedia.org/wiki/…
Devin Lehmacher,

8

Linguaggi concatenativi basati su stack, 4 caratteri

Sotto carico

():^

GolfScript

{}.~

CJam

{}_~

GS2

  • backspace, tab,, @space (sapevo che GS2 usava molto gli stampabili, ma questo è ridicolo ...)

dc (suggerito da @seshoumara)

[]dx

Underload ha dimostrato di essere Turing completo solo con l'uso di ():^(grazie al matematico residente di Esolang Ørjan). La prova è troppo lunga per essere spiegata qui, ma se sei interessato, puoi leggere qui .

I comandi in questione sono ()(posiziona il codice letterale nello stack), :(elemento stack superiore duplicato) e ^(valuta la parte superiore dello stack). Questi comandi sono abbastanza comuni nei linguaggi basati su stack (in particolare i linguaggi concatenativi), e quindi ho dato una sorta di raccolta sopra; queste lingue sono tutte complete di Turing in 4 caratteri per lo stesso motivo di Underload.


Capisco che puoi eseguire operazioni di stack con quelle, ma non hai bisogno di almeno numeri per popolare quella pila per fare calcoli matematici? O quelli fatti in unario usano uno dei 4 caratteri?
seshoumara,

1
@seshoumara: I numeri (e praticamente tutti gli altri archivi di dati) sono implementati in modo indiretto quando si utilizza questo metodo. C'è qualcosa come due o tre, forse anche quattro, livelli di astrazione prima di arrivare a qualcosa di riconoscibile come aritmetico. Questo genere di cose è comune nelle prove di completezza di Turing di sistemi molto limitati come questo.

Stavo pensando di inviare una risposta in dc me stesso, anche un linguaggio basato su stack, ma usando un altro metodo che coinvolge più caratteri di 4. dc non ha un operatore di concatenazione, ma ha quelli equivalenti che menzioni: [] d x. Può dc inserirsi nella tua lista?
seshoumara,

@seshoumara: Sì, sembra che abbia tutte le funzionalità richieste. L'ho aggiunto e accreditato.

Forse potresti cercare FlogScript
mbomb007,


7

Racchetta (schema), 4 caratteri

(λ)

Usando solo λ, parentesi e spazio, possiamo programmare direttamente nel sottoinsieme Lambda Calculus di Scheme. Riutilizziamo il carattere λ per tutti gli identificatori concatenandoli insieme per fornire un numero arbitrariamente elevato di identificatori univoci.

Ad esempio, ecco il classico combinatore Omega, che gira per sempre.

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

6

Python 3, 9 caratteri

exc('%1+)

Vedi la mia risposta Python 2 per una spiegazione di base. Questa risposta si basa su quella.

Invece di usare semplicemente gli stessi personaggi di Python due con l'aggiunta di (), siamo in grado di rilasciare un personaggio poiché ora abbiamo l'uso delle parentesi. I programmi avranno ancora la forma base di

exec('%c'%stuff)

ma abbreviamo la durata del programma usando +invece di -, e quindi possiamo rimuovere ~usando 1invece di 0. Possiamo quindi aggiungere 1, 11e 111per ottenere i valori ASCII richiesti.

Il programma print()diventa quanto segue al più breve:

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)%'('%')')

Provalo online

Potresti pensare a te stesso, come si fa a creare un byte NUL senza 0? Non temere, giovane cavalletta! perché abbiamo la possibilità di usare anche %per la matematica, creando zero con 1%1.


Perché mai vorresti un byte NUL nel tuo programma?
NieDzejkob,

@NieDzejkob Su questo sito, la risposta al "perché" è sempre "perché possiamo". In questo caso, tuttavia, non sarebbe l'implementazione completa di Python se non si potesse farlo, anche se dà solo un errore.
mbomb007,

Non è necessario un byte NUL per Turing Completezza; un interprete BF può essere scritto senza uno
MilkyWay90

@ MilkyWay90 Vero, ma perché non spiegarlo se puoi?
mbomb007,

6

PHP 7, 6 caratteri

'().;^

L'idea è che è possibile eseguire codice arbitrario usando la seguente costruzione:

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

eval non funzionerebbe qui, perché è un costrutto di linguaggio e non può essere chiamato usando funzioni variabili.

create_function e il codice potrebbe essere scritto come una concatenazione di XOR bit a bit di caratteri disponibili:

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

Usando ().;^per <charX_Y>, possiamo ottenere

()./:;<=JKLMXY^_bcdepqvw

e alcuni personaggi non stampabili. Non è abbastanza, ma ora possiamo chiamare 'eXp'()e ottenere anche alcuni caratteri numerici:

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

Ci dà 1, 2e 3(altri caratteri saranno ignorati da XOR, se l'altra stringa è lunga un carattere). Da ().;^123ora possiamo generare tutto il set di caratteri ASCII.

Provalo online


5

Pyke, 5 personaggi

0h.CE

Questo è in grado di produrre un numero infinitamente grande, trasformandolo in una stringa e quindi valutandolo come codice Pyke.

Spiegazione del codice:

0- Aggiungi 0 allo stack. Questo è necessario per iniziare un numero

h- Incrementa il numero prima. Ripetendolo per un numero arbitrario di volte, puoi creare numeri infinitamente grandi. Pyke supporta i bignum come è scritto in Python, che li usa come predefinito.

.C- Trasforma un numero in una stringa usando il seguente algoritmo: ( collegamento Github )

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

A questo punto, possiamo creare una quantità arbitraria di stringhe e numeri naturali in Pyke con valori arbitrari. I numeri possono essere creati nella forma corrispondente alla regex 0(h)*e le stringhe possono essere create con 0(h)*.C. Possono essere intrecciati tra loro per creare una miscela arbitraria di stringhe e numeri interi.

E- valuta una stringa come codice Pyke. Questo utilizza lo stesso ambiente del codice Pyke già in esecuzione, quindi condividerà cose come l'input.

Tentativo di prova che Pyke è Turing completo.

Uno dei modi più semplici per mostrare una lingua è il completamento completo implementando Brainf * ck in essa. Questo è probabilmente molto più difficile in Pyke rispetto a molte altre lingue perché le sue operazioni di elenco e dizionario sono praticamente inesistenti a causa della mancanza del loro bisogno nell'area in cui Pyke è progettato per funzionare: .

Innanzitutto creiamo un interprete per brainf * ck e lo codifichiamo usando il nostro algoritmo sopra per creare un numero e quindi esprimere quel numero con 0e h. Quindi creiamo la stringa contenente il codice da eseguire esattamente allo stesso modo. Se dovessimo lasciarlo a quello, avremmo lo stack come

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

Ciò significa che il codice deve essere nella forma opposta poiché lo stack di Pyke è il primo ad uscire.

Ora per la parte divertente: l'interprete brainf * ck con un enorme 216 byte!

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

Provalo qui!

Se vuoi provare il codice in forma semi-completata ma modificabile, provalo qui!

Per convertire da una stringa in un numero, puoi usare il seguente codice Python:

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

La (quasi) soluzione finale può essere provata qui!

Spiegazione dell'interprete Brainf * ck

Innanzitutto, separiamo il programma in parti:

  • L'inizializzazione:

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
  • Il ciclo principale:

Diario di viaggio

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.
  • Le istruzioni
    • Incremento / Decremento:+-

Diario di viaggio

"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] = ^
  • Ingresso ,::

Diario di viaggio

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

Diario di viaggio

~c\.qI~LZ@.CpK) - The code for input 
~c\.qI        ) - if c == ".":
      ~LZ@      -    L[Z]
          .C    -   chr(^)
            pK  -  print(^)
  • Maiusc sinistra / destra <>::

Diario di viaggio

~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
  • I condizionali [::

Diario di viaggio

~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

- E ]:

Diario di viaggio

~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

In pila, 5 caratteri

{!n:}

Questo è sorprendentemente breve. Se Stacked può implementare ciascuna delle combinazioni SKI, allora è Turing Complete. Ricapitolare:

  • I combinatore: la funzione identità. x -> x
  • K combinatore: la funzione costante. x -> y -> x
  • S combinatore: la funzione di sostituzione. (x, y, z) -> x(z)(y(z))

I combinatore: {!n}

Ora, per le specifiche in pila. {! ... }è un n-lambda. È una funzione unaria il cui argomento è implicitamente n. Quindi, l'ultima espressione viene restituita dalla funzione. Pertanto, {!n}è una funzione che accetta un argomento ne producen .

Combinatore K: {!{:n}}

Ora, {:...}è una funzione che non accetta argomenti e restituisce .... Combinando questo con la nostra formazione n-lambda, otteniamo (aggiungendo spazi bianchi per chiarezza):

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

Combinatore S: {n!nn!nnn:nnn{!n}!nn!nnn{!n}!n!!}

Ok, sembra un po 'più complicato. Quindi, una lambda accetta argomenti, separati da caratteri non identificativi. Pertanto, la lambda nell'intestazione è equivalente a:

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

Si tratta di una lambda che prende tre argomenti, n, nn, e nnn. Diamo sostituire questi con x, ye zper chiarezza:

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

I due {!n}!sono solo la funzione di identità per evitare ancora spazi bianchi, dove !significa "eseguire". Quindi, ancora una volta, riducendo:

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

Con una spiegazione:

{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))`

E quindi, questo è il combinatore S.


{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}contiene spazi.
Calcolatrice

@CalculatorFeline Hai già letto la frase? Ok, sembra un po 'più complicato. Quindi, una lambda accetta argomenti, separati da caratteri non identificativi. Pertanto, la lambda nell'intestazione equivale a:
Conor O'Brien il

Oh. (Nota a se stesso: smetti di essere un idiota.)
CalculatorFeline
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.