Scrivi un interprete per il calcolo lambda non tipizzato


45

La sfida è scrivere un interprete per il calcolo lambda non tipizzato nel minor numero di caratteri possibile. Definiamo il calcolo lambda non tipizzato come segue:

Sintassi

Esistono tre tipi di espressioni seguenti:

  • Un'espressione lambda ha la forma in (λ x. e)cui xpotrebbe essere qualsiasi nome di variabile legale e equalsiasi espressione legale. Qui xsi chiama il parametro e esi chiama il corpo della funzione.

    Per semplicità aggiungiamo l'ulteriore limitazione che non ci deve essere una variabile con lo stesso nome xattualmente nell'ambito. Una variabile inizia ad essere nell'ambito quando appare il suo nome tra e .e si ferma per essere nell'ambito nell'ambito del corrispondente ).

  • L'applicazione della funzione ha la forma in (f a)cui fe asono espressioni legali. Qui fsi chiama la funzione e asi chiama argomento.
  • Una variabile ha la forma in xcui xè un nome di variabile legale.

Semantica

Una funzione viene applicata sostituendo ogni occorrenza del parametro nel corpo delle funzioni con il suo argomento. Più formalmente un'espressione del modulo ((λ x. e) a), dove xè un nome variabile e ee asono espressioni, valuta (o riduce) l'espressione in e'cui e'è il risultato della sostituzione di ogni occorrenza di xin econ a.

Una forma normale è un'espressione che non può essere ulteriormente valutata.

La sfida

La tua missione, se scegli di accettarlo, è quella di scrivere un interprete che prenda come input un'espressione del calcolo lambda non tipizzato che non contenga variabili libere e produca come output la forma normale dell'espressione (o un'espressione alfa congruente con essa) . Se l'espressione non ha una forma normale o non è un'espressione valida, il comportamento non è definito.

Vince la soluzione con il minor numero di personaggi.

Un paio di note:

  • L'input può essere letto da stdin o da un nome file indicato come argomento della riga di comando (è necessario solo implementare l'uno o l'altro, non entrambi). L'output va allo stdout.
  • In alternativa è possibile definire una funzione che accetta l'input come stringa e restituisce l'output come stringa.
  • Se i caratteri non ASCII sono problematici per te, puoi usare il carattere barra rovesciata ( \) anziché λ.
  • Contiamo il numero di caratteri, non i byte, quindi anche se il tuo file sorgente è codificato come unicode λ conta come un carattere.
  • I nomi delle variabili legali sono costituiti da una o più lettere minuscole, ovvero caratteri tra a e z (non è necessario supportare nomi alfanumerici, lettere maiuscole o lettere non latine, sebbene ciò non invalidi la soluzione, ovviamente).
  • Per quanto riguarda questa sfida, nessuna parentesi è facoltativa. Ogni espressione lambda e ogni applicazione di funzione saranno circondate esattamente da una coppia di parentesi. Nessun nome di variabile sarà racchiuso tra parentesi.
  • Lo zucchero sintattico come la scrittura (λ x y. e)per (λ x. (λ y. e))non ha bisogno di essere supportato.
  • Se per valutare una funzione è necessaria una profondità di ricorsione superiore a 100, il comportamento non è definito. Dovrebbe essere abbastanza basso da essere implementato senza ottimizzazione in tutte le lingue e comunque abbastanza grande da essere in grado di eseguire la maggior parte delle espressioni.
  • Si può anche supporre che la spaziatura sia come negli esempi, cioè senza spazi all'inizio e alla fine dell'input o prima di uno λo .esattamente uno spazio dopo una .e tra una funzione e il suo argomento e dopo una λ.

Ingresso e uscita campione

  • Ingresso: ((λ x. x) (λ y. (λ z. z)))

    Produzione: (λ y. (λ z. z))

  • Ingresso: (λ x. ((λ y. y) x))

    Produzione: (λ x. x)

  • Ingresso: ((λ x. (λ y. x)) (λ a. a))

    Produzione: (λ y. (λ a. a))

  • Ingresso: (((λ x. (λ y. x)) (λ a. a)) (λ b. b))

    Produzione: (λ a. a)

  • Ingresso: ((λ x. (λ y. y)) (λ a. a))

    Produzione: (λ y. y)

  • Ingresso: (((λ x. (λ y. y)) (λ a. a)) (λ b. b))

    Produzione: (λ b. b)

  • Ingresso: ((λx. (x x)) (λx. (x x)))

    Output: nulla (Questo è un esempio di un'espressione che non ha forma normale)

  • Ingresso: (((λ x. (λ y. x)) (λ a. a)) ((λx. (x x)) (λx. (x x))))

    Output: (λ a. a)(Questo è un esempio di un'espressione che non si normalizza se si valutano gli argomenti prima della chiamata della funzione, e purtroppo un esempio per il quale la mia tentata soluzione fallisce)

  • Ingresso: ((λ a. (λ b. (a (a (a b))))) (λ c. (λ d. (c (c d)))))

    Output: `(λ a. (λ b. (a (a (a (a (a (a (a (a b)))))))))) calcola 2 ^ 3 in cifre della Chiesa.


1
Possiamo supporre che non ci sarà spazio bianco anteposto o aggiunto alla stringa e che lo spazio bianco sia altrimenti specificato nell'input di esempio? Cioè, nessuno spazio tra parentesi, tra il punto e il nome del parametro e altre istanze di spazio bianco è esattamente 1 spazio.
JPvdMerwe,

@JPvdMerwe: Sì, buon punto, puoi supporre che.
sepp2k,

Ci sono variabili libere? Intendo variabili non legate da una lambda come nell'espressione (\y. a).
FUZxxl

3
Molte o tutte le soluzioni qui non riescono ad implementare la sostituzione per evitare l'acquisizione! Dovresti aggiungere un test case come ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))), che dovrebbe valutare in (λ x. (Λ z. X)), non (λ x. (λ x. x)).
Anders Kaseorg,

1
@ sepp2k Hai considerato di aggiungere ((λ f. (λ x. (fx))) (λ y. (λ x. y))) come caso di test e di non accettare la risposta corrente che produce erroneamente (λ x. (λ x. x))?
Anders Kaseorg,

Risposte:


36

Novità:

L'ho ridotto a 644 caratteri , ho scomposto parti di cEll in cOpy e Par; chiamate memorizzate nella cache su cell e cdr in variabili locali temporanee e spostate tali variabili locali su globali in funzioni "terminali" (cioè non ricorsive). Inoltre, le costanti decimali sono più brevi dei letterali dei personaggi e questo brutto affare ...

atom(x){
    return m[x]>>5==3;
}

... identifica correttamente le lettere minuscole (presupponendo ASCII), ma accetta anche uno qualsiasi di `{|} ~. (Questa stessa osservazione su ASCII è fatta in questo eccellente video su UTF-8 .)

Et viola: |

#include<stdio.h>
#include<string.h>
#define X m[x]
#define R return
char*n,*m;int u,w,d;C(x,y){w=n-m;n+=sprintf(n,y?"(%s %s)":"(%s)",&X,m+y)+1;R w;}T(x){R X>>5==3;}
L(x){R X==92;}O(x,j){w=n-m;memcpy(n,&X,j);n+=j;*n++=0;R w;}E(x){X==' '?++x:0;R
X==41?0:L(x)?O(x,4):P(x);}P(x){d=0,w=x;do{X==40?d++:X==41?d--:0;++x;}while(d>0);R
O(w,x-w);}D(x){u=E(x+1);R u?E(x+1+strlen(m+u)):0;}V(x){int a=E(x+1),b=D(x);R
T(x)|T(a)?x:L(a)?C(a,V(b)):L(E(a+1))?V(S(V(b),E(a+3),D(a))):V(C(V(a),b?V(b):0));}S(w,y,x){R
T(x)?(X==m[y]?w:x):C(L(w+1)?E(x+1):S(w,y,E(x+1)),D(x)?S(w,y,D(x)):0);}
Y(char*s){n+=strlen(s=strcpy(n,s))+1;printf("%s\n%s\n\n",s,m+V(s-m));n=m+1;}

char*s[]={
"((\\ a. a) (b))",
"((\\ x. x) (\\ y. (\\ z. z)))",
"(\\ x. ((\\ y. y) x))",
"(((\\ x. (\\ y. x)) (\\ a. a)) (\\ b. b))",
"((\\ x. (\\ y. y)) (\\ a. a))",
"(((\\ x. (\\ y. y)) (\\ a. a)) (\\ b. b))",
"((\\x. (x x)) (\\x. (x x)))",0};
#include<unistd.h>
main(){char**k;n=m=sbrk(4096);*n++=0;for(k=s;*k;k++)Y(*k);R 0;}

In precedenza:

Posso ottenere qualche voto per sforzo? Ci lavoro giorno e notte da una settimana. Ho estratto il documento originale McCarthy e sono stato afflitto da un bug nel documento stesso fino a quando ho letto l'appendice di Le radici di Lisp di Paul Graham . Ero così distratto che mi sono chiuso fuori da casa mia, poi mi sono completamente dimenticato di tornare a casa quella sera alle 12:30 (un po 'tardi per chiamare il direttore dell'edificio che vive nella contea), e ho dovuto passare il notte da mia nonna (tagliando via fino a quando la batteria del mio laptop era asciutta).

E dopo tutto ciò, non è nemmeno vicino alla voce vincente!

Non sono sicuro di come accorciarlo; e ho usato tutti i trucchi sporchi che mi vengono in mente! Forse non può essere fatto in C.

Con una certa generosità nel conteggio (il primo pezzo prende una stringa e stampa il risultato), sono 778 770 709 694 caratteri. Ma per renderlo autonomo, deve avere quella sbrkchiamata. E per gestire espressioni più complicate, ha bisogno anche del signalgestore. E ovviamente non può essere trasformato in un modulo con alcun codice che tenta di utilizzare malloc.

Quindi, ahimè, eccolo qui:

#include<stdio.h>
#include<string.h>
#define K(j) strncpy(n,m+x,j);n+=j;goto N;
#define R return
#define X m[x]
#define L =='\\'
char*m,*n;T(x){R islower(X);}V(x){int a=E(x+1);R
T(x)?x:T(a)?x:m[a]L?C(a,V(D(x))):m[E(a+1)]L?V(S(V(D(x)),E(a+3),D(a))):V(C(V(a),D(x)?V(D(x)):0));}
C(x,y){char*t=n;sprintf(n,y?"(%s %s)":"(%s)",m+x,m+y);n+=strlen(n)+1;R
t-m;}Y(char*s){char*t=strcpy(n,s);n+=strlen(n)+1;printf("%s=>%s\n",s,m+V(t-m));n=m+1;}S(x,y,z){R
T(z)?(m[z]==m[y]?x:z):C(m[z+1]L?E(z+1):S(x,y,E(z+1)),D(z)?S(x,y,D(z)):0);}D(x){R
E(x+1)?E(x+strlen(m+E(x+1))+1):0;}E(x){char*t=n,d=0;if(X==' ')++x;if(T(x)){K(1)}if(X
L){K(4)}do{d=X?(X=='('?d+1:(X==')'?d-1:d)):0;*n++=m[x++];}while(d);N:*n++=0;R t-m;}

char*samp[]={
    "a","a","b","b",
    "((\\ a. a) (b))", "(b)",
    "((\\ x. x) (\\ y. (\\ z. z)))", "(\\ y. (\\ z. z))",
    "(\\ x. ((\\ y. y) x))", "(\\ x. x)",
    "(((\\ x. (\\ y. x)) (\\ a. a)) (\\ b. b))", "(\\ a. a)",
    "((\\ x. (\\ y. y)) (\\ a. a))", "(\\ y. y)",
    "(((\\ x. (\\ y. y)) (\\ a. a)) (\\ b. b))", "(\\ b. b)",
    "((\\x. (x x)) (\\x. (x x)))", "undef",
    NULL};
#include<unistd.h>

unsigned sz;
#include<signal.h>
void fix(x){signal(SIGSEGV,fix);brk(m+(sz*=2));}
main(){
    char**t;
    signal(SIGSEGV,fix);
    m=n=sbrk(sz=10*getpagesize());
    *n++=0;
    for(t=samp;*t;t+=2){
        Y(*t);
        printf("s.b. => %s\n\n", t[1]);
    }
    return 0;
}

Ecco il blocco appena prima delle riduzioni finali. I trucchi qui sono cursori interi anziché puntatori (che sfruttano il comportamento "implicito int") e l'uso di "memoria graffiata": char*nè il puntatore "nuovo" o "successivo" nello spazio libero. Ma a volte scrivo una stringa in memoria, quindi chiamo strlen e incrementa n; utilizzare efficacemente la memoria e quindi allocarla, dopo che la dimensione è più facile da calcolare. Puoi vedere che è praticamente direttamente dal documento di McCarthy, ad eccezione delle cell()interfacce tra le funzioni e la rappresentazione in formato stringa dei dati.

#include<stdio.h>
#include<string.h>
char*m,*n;  //memory_base, memory_next
atom(x){  // x is an atom if it is a cursor to a lowercase alpha char.
    return x?(islower(m[x])?m[x]:0):0;
}
eq(x,y){  // x and y are equal if they are both atoms, the same atom.
    return x&&y&&atom(x)==atom(y);
}
cell(x){  // return a copy of the list-string by cursor, by parsing
    char*t=n,d=0;
    if(!x||!m[x])
        return 0;
    if(m[x]==' ')
        ++x;
    if(atom(x)){
        *n++=m[x];
        *n++=0;
        return(n-m)-2;
    }
    if(m[x]=='\\'){  // our lambda symbol
        memcpy(n,m+x,4);
        n+=4;
        *n++=0;
        return(n-m)-5;
    }
    do{  // um ...
        d=m[x]?(m[x]=='('?d+1:(m[x]==')'?d-1:d)):0;
        *n++=m[x++];
    }while(d);
    *n++=0;
    return t-m;
}
car(x){  // return (copy of) first element
    return x?cell(x+1):0;
}
cdr(x){  // return (copy of) rest of list
    return car(x)?cell(x+strlen(m+car(x))+1):0;
}
cons(x,y){  // return new list containing first x and rest y
    char*t=n;
    return x?(sprintf(n,y?"(%s %s)":"(%s)",m+x,m+y),n+=strlen(n)+1,t-m):0;
}
subst(x,y,z){  // substitute x for z in y
    if(!x||!y||!z)
        return 0;
    return atom(z)? (eq(z,y)?x:z):
        cons(m[z+1]=='\\'?car(z):
        subst(x,y,car(z)),cdr(z)?subst(x,y,cdr(z)):0);
}
eval(x){  // evaluate a lambda expression
    int a;
    return atom(x)?x:
        atom(a=car(x))?x:
        m[a]=='\\'?cons(a,eval(cdr(x))):
        m[car(a)]=='\\'?eval(subst(eval(cdr(x)),cell(a+3),cdr(a))):
        eval( cons(eval(a),cdr(x)?eval(cdr(x)):0));
}
try(char*s){  // handler
    char*t=strcpy(n,s);
    n+=strlen(n)+1;
    printf("input: %s\n", s);
    printf("eval => %s\n", m+eval(t-m));
    n=m+1;
}

1
Ho trovato qualche altro trucco per salvare un personaggio o due, ma niente di radicale. sprintf(n,...);n+=strlen(n)+1;è meglio n+=sprintf(n,...)+1;invertire la sintassi dell'array x[m]invece di m[x]permettermi di sostituire tutte le indirette con una macro 'postfix' #define M [m]... x Mche salva 1 carattere e dà un'interruzione di linea "libera" poiché lo spazio bianco è necessario per separare i token.
Luser droog

Sembra che ci siano alcune somiglianze con questo e jar.2 xlisp 4.0 di IOCCC 1989 .
Luser droog,

Ho cercato di espandere questo in un interprete Lisp più completo .
luser Droog

Il codice commentato // um ...scorre ciclicamente la stringa e conta le parentesi fino a quando non trova il paren vicino corrispondente al livello di annidamento corretto.
Luser droog,

1
Questo valuta erroneamente ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) a (\ x. (Fx)).
Anders Kaseorg,

22

Calcolo lambda binario 186

Il programma mostrato nella discarica esadecimale di seguito

00000000  18 18 18 18 18 18 44 45  1a 10 18 18 45 7f fb cf  |......DE....E...|
00000010  f0 b9 fe 00 78 7f 0b 6f  cf f8 7f c0 0b 9f de 7e  |....x..o.......~|
00000020  f2 cf e1 b0 bf e1 ff 0e  6f 79 ff d3 40 f3 a4 46  |........oy..@..F|
00000030  87 34 0a a8 d0 80 2b 0b  ff 78 16 ff fe 16 fc 2d  |.4....+..x.....-|
00000040  ff ff fc ab ff 06 55 1a  00 58 57 ef 81 15 bf bf  |......U..XW.....|
00000050  0b 6f 02 fd 60 7e 16 f7  3d 11 7f 3f 00 df fb c0  |.o..`~..=..?....|
00000060  bf f9 7e f8 85 5f e0 60  df 70 b7 ff ff e5 5f f0  |..~.._.`.p...._.|
00000070  30 30 6f dd 80 5b b3 41  be 85 bf ff ca a3 42 0a  |00o..[.A......B.|
00000080  c2 bc c0 37 83 00 c0 3c  2b ff 9f f5 10 22 bc 03  |...7...<+...."..|
00000090  3d f0 71 95 f6 57 d0 60  18 05 df ef c0 30 0b bf  |=.q..W.`.....0..|
000000a0  7f 01 9a c1 70 2e 80 5b  ff e7 c2 df fe e1 15 55  |....p..[.......U|
000000b0  75 55 41 82 0a 20 28 29  5c 61                    |uUA.. ()\a|
000000ba

non accetta esattamente il formato che proponi. Si aspetta piuttosto un termine lambda in formato binario di calcolo lambda (blc). Tuttavia, mostra ogni singolo passaggio nella riduzione della forma normale, utilizzando parentesi minime.

Esempio: calcolo di 2 ^ 3 in cifre della Chiesa

Salvare il dump esadecimale sopra con xxd -r> symbolic.Blc

Prendi un interprete blc da http://tromp.github.io/cl/uni.c

cc -O2 -DM=0x100000 -m32 -std=c99 uni.c -o uni
echo -n "010000011100111001110100000011100111010" > threetwo.blc
cat symbolic.Blc threetwo.blc | ./uni
(\a \b a (a (a b))) (\a \b a (a b))
\a (\b \c b (b c)) ((\b \c b (b c)) ((\b \c b (b c)) a))
\a \b (\c \d c (c d)) ((\c \d c (c d)) a) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
\a \b (\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
\a \b (\c \d c (c d)) a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
\a \b (\c a (a c)) ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
\a \b a (a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
\a \b a (a ((\c a (a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
\a \b a (a (a (a ((\c \d c (c d)) ((\c \d c (c d)) a) b))))
\a \b a (a (a (a ((\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) b))))
\a \b a (a (a (a ((\c \d c (c d)) a ((\c \d c (c d)) a b)))))
\a \b a (a (a (a ((\c a (a c)) ((\c \d c (c d)) a b)))))
\a \b a (a (a (a (a (a ((\c \d c (c d)) a b))))))
\a \b a (a (a (a (a (a ((\c a (a c)) b))))))
\a \b a (a (a (a (a (a (a (a b)))))))

Poiché hexdump è piuttosto illeggibile, ecco una versione "disassemblata"

@10\\@10\\@10\\@10\\@10\\@10\@\@\@\@@\@1010\@\\\@10\\@10\@\@@@1111111111101
1110@11111110\@@110@11111110\\\\@1110\@1111110\@@101101111110@111111110\@111
111110\\\\@@110@111111011110@11111011110@@10@1111110\@10110\@@111111110\@111
111110\@110@101111011110@1111111111010@1010\\@1110@11010@\@\@1010\@110@1010\
\@@@@@\@1010\@\\\\@@@10\@@111111111011110\\@@101111111111111110\@@101111110\
@@10111111111111111111111110@@@@1111111110\\110@@@@\@1010\\\\@@10\@@@1111101
11110\\@\@@@10111111101111110\@@1011011110\\@@11111010110\\@111110\@@1011110
1110@111010\10\1011111110@111110\\\@101111111111011110\\@@11111111110@@11111
0111110\10\@@@@11111110\\@10\\1101111101110\@@1011111111111111111111110@@@@1
11111110\\@10\\@10\\11011111101110110\\\@@101110110@1010\\11011111010\@@1011
111111111111110@@@@\@1010\@\\@@@10\@@@1110@10\\\@1011110\\110\\\@10\\\@1110\
@@@11111111110@1111111101010\10\\@\@@@1110\\\@10@1110111110\\1110\110@@@1111
0110@@@1111010\\110\\\@10\\\@@1101111111101111110\\\@10\\\@@1101111110111111
10\\\110@1010110\\101110\\@@11010\\\@@1011111111111110@11110\@@1011111111111
101110\@\@@@@@@@@11010101010101010\\110\\10\\1010\10\\\1010\\1010@@@110\110\
@

sostituendo 00 (lambda) con \ e 01 (applicazione) con @ Ora è quasi leggibile come brainfuck :-)

Vedi anche http://www.ioccc.org/2012/tromp/hint.html


7
BLC usa semplicemente un alfabeto binario. 00 è lambda, 01 è applicazione e 1 ^ {n} 0 è una variabile in unario. Non è prevista la compilazione.
John Tromp,

3
Dove ottieni un fattore x3? In realtà sollevi un buon punto in cui le lingue con alfabeti di origine più piccoli come BF sono penalizzate. Per un confronto equo, tutte le dimensioni devono essere espresse in bit e i caratteri BF devono prendere solo 3 bit ciascuno. La maggior parte delle altre lingue ha bisogno di 7 bit per ASCII, alcune usano tutte 8.
John Tromp

1
A proposito +1 Questo è dannatamente bello!
Luser droog

1
Se fractran in fractran è accettabile, non vedo perché questo dovrebbe essere un problema. Non riesci a leggerlo? Tu vuoi? Imparare!
Luser droog,

1
Cosa ci vorrebbe per farlo leggere l'attuale formato di input? Penso che sia lì che stai perdendo potenziali voti.
Luser droog,

14

Haskell, 342 323 317 305 caratteri

Al momento della stesura di questo documento, questa è l'unica soluzione che valuta ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))) al risultato corretto (λ x. (Λ z. x)) anziché (λ x. (λ x. x)). La corretta implementazione del calcolo lambda richiede la sostituzione che evita l'acquisizione , anche con la garanzia semplificativa di questo problema che nessuna variabile ombreggia un'altra variabile nel suo ambito. (Il mio programma sembra funzionare anche senza questa garanzia.)

data T=T{a::T->T,(%)::ShowS}
i d=T(i. \x v->'(':d v++' ':x%v++")")d
l f=f`T`\v->"(λ "++v++". "++f(i(\_->v))%('x':v)++")"
(?)=q.lex
q[(v,s)]k|v/="("=k(maybe T{}id.lookup v)s|'λ':u<-s,[(w,_:t)]<-lex u=t? \b->k(\e->l$b.(:e).(,)w).tail|0<1=s? \f->(?(.tail).k. \x z->f z`a`x z)
main=interact(? \f->(f[]%"x"++))

Appunti:

  • Funziona con GHC 7.0, come richiesto perché questa sfida è stata lanciata nel gennaio 2011. Sarebbe più corta di 13 caratteri se mi fosse permesso di assumere GHC 7.10.

Versione non golfata con documentazione.


il tuo prog nel compilatore haskell di ideone all'input ((\ x. x) (\ y. (\ z. z))) restituisce "errore di runtime" anche in ((\\ x. x) (\\ y. ( \\ z. z))) ... cosa significa "lex" in Haskell?
RosLuP,

2
@RosLuP Il mio programma accetta λ, non \.
Anders Kaseorg,

digita questo imput ((λ x. x) (λ y. (λ z. z))) in ideone.com return: tempo di errore di runtime: 0 memoria: 4876 segnale: -1
RosLuP

1
@RosLuP Ideone sembra aver rotto il supporto Unicode. Prova la riga di comando o un altro interprete online (funziona su Rextester , ad esempio).
Anders Kaseorg,

2
@codeshot L'autore della domanda ha già commentato che ((λ f. (λ x. (fx))) (λ y. (λ x. y)))) ↦ (λ x. (λ z. x)) è corretto per questo problema (proprio come il vero calcolo lambda).
Anders Kaseorg,

13

Python - 321 320

Ecco il mio tentativo (risolto):

l="("
def S(s):
 if s[0]!=l:return s
 if s[1]=="\\":g=s.find('.');return"(\\ %s. %s)"%(s[3:g],S(s[g+2:-1]))
 i=2;c=s[1]==l
 while c:c+=(s[i]==l)-(s[i]==')');i+=1
 t=S(s[1:i])
 z=s[i+1:-1]
 if l!=t[0]:return"(%s %s)"%(t,S(z))
 g=t.find('.')
 t=S(t[g+2:-1]).replace(t[3:g],z)
 if t!=s:t=S(t)
 return t
print S(raw_input())

Sembra carino, ma non sembra funzionare. Ho aggiunto alcuni input e output di esempio, per i quali il tuo codice produce risultati errati.
sepp2k,

1
Questo non riesce a fare la cattura per evitare la sostituzione. Ad esempio, ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) viene valutato erroneamente su (\ x. (\ X. X)).
Anders Kaseorg,

1
Perché questo è contrassegnato come una risposta quando funziona a malapena? Hai provato gli input e gli output forniti dall'autore?
rbaleksandar,

1
I casi di test forniti dall'autore non sono sufficienti per dimostrare i bug in questa risposta.
Anders Kaseorg,

1
Questa risposta non è né corretta né la più breve. Non riesce a evitare l'acquisizione e presenta bug di sostituzione delle stringhe.
Richard Padley,

6

Rubino 254 caratteri

f=->u,r{r.chars.take_while{|c|u+=c==?(?1:c==?)?-1:0;u>0}*''}
l=->x{x=~/^(\(*)\(\\ (\w+)\. (.*)/&&(b,v,r=$1,$2,$3;e=f[1,r];(e==s=l[e])?b==''?x:(s=f[2,r];(x==y=b.chop+e.gsub(v,s[2+e.size..-1])+r[1+s.size..-1])?x:l[y]):(b+'(\\ '+v+'. '+s+r[e.size..-1]))||x}

Può essere usato come

puts l["((\\ x. (\\ y. x)) (\\ a. a))"]    # <= (\ y. (\ a. a))

La soluzione non è ancora completamente giocata a golf ma già quasi illeggibile.


ciao invidia, mio ​​vecchio amico :)
luser droog

Questo non riesce a fare la cattura per evitare la sostituzione. Ad esempio, ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) viene valutato erroneamente su (\ x. (\ X. X)).
Anders Kaseorg,

Oltre al precedente bug di acquisizione, anche questo valuta erroneamente (\ y. (\ Xx. ((\ X. Xx) y))) a (\ y. (\ Xx. Yy)), dove è stata prodotta una sostituzione di stringa troppo zelante la variabile inesistente yy.
Anders Kaseorg,

3

Modifica: controlla la mia risposta qui sotto per 250 in puro JavaScript.

2852 243 caratteri usando LiveScript (No Regex! Non completamente giocato a golf - potrebbe essere migliorato)

L=(.0==\\)
A=->it.forEach?&&it.0!=\\
V=(.toFixed?)
S=(a,b,t=-1,l=0)->|L a=>[\\,S(a.1,b,t,l+1)];|A a=>(map (->S(a[it],b,t,l)),[0 1]);|a==l+-1=>S(b,0,l+-1,0)||a|l-1<a=>a+t;|_=>a
R=(a)->|L a=>[\\,R a.1]|(A a)&&(L a.0)=>R(S(R(a.0),R(a.1)).1)|_=>a

Test:

a = [\\,[\\,[1 [1 0]]]]
b = [\\,[\\,[1 [1 [1 0]]]]]
console.log R [a, b]
# outputs ["\\",["\\",[1,[1,[1,[1,[1,[1,[1,[1,[1,0]]]]]]]]]]]

Cioè 3^2=9, come indicato nel PO.

Se qualcuno è curioso, ecco una versione estesa con alcuni commenti:

# Just type checking
λ = 100
isλ = (.0==λ)
isA = -> it.forEach? && it.0!=λ
isV = (.toFixed?)

# Performs substitutions in trees
# a: trees to perform substitution in
# b: substitute bound variables by this, if != void
# f: add this value to all unbound variables
# l: internal (depth)
S = (a,b,t=-1,l=0) ->
    switch
    | isλ a             => [λ, (S a.1, b, t, l+1)]
    | isA a             => [(S a.0, b, t, l), (S a.1, b, t, l)]
    | a == l - 1        => (S b, 0, (l - 1), 0) || a
    | l - 1 < a < 100   => a + t
    | _                 => a

# Performs the beta-reduction
R = (a) ->
    switch
    | (isλ a)               => [λ,R a.1]
    | (isA a) && (isλ a.0)  => R(S(R(a.0),R(a.1)).1)
    | _                     => a

# Test
a = [λ,[λ,[1 [1 0]]]]
b = [λ,[λ,[1 [1 [1 0]]]]]
console.log show R [a, b]

Ciò non è conforme alle specifiche di input e output del problema.
Anders Kaseorg,

3

Waterhouse Arc - 140 caratteri

(=
f[is cons?&car._'λ]n[if
atom._ _
f._ `(λ,_.1,n:_.2)(=
c n:_.0
e _)(if
f.c(n:deep-map[if(is
c.1 _)e.1
_]c.2)(map n
_))]λ[n:read:rem #\._])

Dove posso trovare Waterhouse Arc?
Anders Kaseorg,

1
Non è possibile trovare un interprete non valido da nessuna parte
cat

@AndersKaseorg qui
solo ASCII il

@ ASCII-so che cos'è Arc, ma la parte "Waterhouse" mi ha suggerito che era necessario un dialetto particolare. L'hai fatto funzionare?
Anders Kaseorg il

@AndersKaseorg Non importa. Trovato
solo ASCII il

2

C 1039 byte

#define F for
#define R return
#define E if(i>=M||j>=M)R-1;
enum{O='(',C,M=3999};signed char Q[M],D[M],t[M],Z,v,*o=Q,*d=D,*T;int m,n,s,c,w,x,y;K(i,j,k){!Z&&(Z=t[O]=1)+(t[C]=-1);E;if(!o[i]){d[j]=0;R 0;}if((c=t[o[i]]+t[o[i+1]])!=2||o[i+2]!='\\'){d[j++]=o[i++];R K(i,j,i);}F(i+=2,y=w=0;i<M&&o[i]&&c;++i)c+=t[o[i]],!w&&c==1?w=i:0,!y&&o[i]=='.'?y=i+2:0;E;if(c){F(;d[j++]=o[i++];)E;R 0;}F(c=y;c<w;++c)if(o[c]=='\\')F(n=0,m=w+2;m<i;++m){if(o[m]==o[c+2]){F(x=0;o[m+x]&&isalpha(o[m+x])&&o[m+x]==o[c+2+x];++x);if(o[c+2+x]!='.'||isalpha(o[m+x]))continue;if(v>'Z')R-1;F(n=c+2;n<w;++n)if(o[n]==o[m]){F(x=0; o[m+x]&&isalpha(o[m+x])&&o[m+x]==o[n+x];++x);if(o[m+x]=='.'&&!isalpha(o[n+x]))F(;--x>=0;) o[n+x]=v;}++v;}}F(c=y;c<w&&j<M;++c){F(x=0;o[c+x]&&o[c+x]==o[k+4+x]&&isalpha(o[c+x]); ++x);if(o[k+4+x]=='.'&&!isalpha(o[c+x])){F(m=w+2;m<i-1&&j<M;++m)d[j++]=o[m];c+=x-1;}else d[j++]=o[c];}E;Z=2;R K(i,j,i);}char*L(char*a){F(s=n=0;n<M&&(o[n]=a[n]);++n);if(n==M)R 0;v='A';F(;++s<M;){Z=0;n=K(0,0,0);if(Z==2&&n!=-1)T=d,d=o,o=T;else break;}R n==-1||s>=M?0:d;}

Le variabili consentono come input usando lettere minuscole [da a..z] il sistema può generare variabili usando lettere maiuscole [da A..Z] se necessario nell'output ... Assumi la configurazione del carattere ASCII.

#define P printf
main()
{char  *r[]={ "((\\ abc. (\\ b. (abc (abc (abc b))))) (\\ cc. (\\ dd. (cc (cc dd)))))",
              "((\\ fa. (\\ abc. (fa abc))) (\\ yy. (\\ abc. yy)))",
              "((\\ x. x) z)", 
              "((\\ x. x) (\\ y. (\\ z. z)))", 
              "(\\ x. ((\\ y. y) x))", 
              "((\\ x. (\\ y. x)) (\\ a. a))", 
              "(((\\ x. (\\ y. x)) (\\ a. a)) (\\ b. b))",
              "((\\ x. (\\ y. y)) (\\ a. a))",
              "(((\\ x. (\\ y. y)) (\\ a. a)) (\\ b. b))",             
              "((\\ x. (x x)) (\\ x. (x x)))",
              "(((\\ x. (\\ y. x)) (\\ a. a)) ((\\ x. (x x)) (\\ x. (x x))))",
             0}, *p;
 int    w;

 for(w=0; r[w] ;++w)
   {p=L(r[w]);
    P("o=%s d=%s\n", r[w], p==0?"Error ":p);
   }
 R  0;
}

/*1.039*/

La specifica richiede \ o λ, non /. Richiede anche il supporto per nomi di variabili a più lettere.
Anders Kaseorg,

Il simbolo '\ n' etc '\' ha altri usi, è meglio usare '/' invece
RosLuP

1
Tuttavia, la sfida è soddisfare le specifiche, non migliorarle.
Anders Kaseorg,

ho scritto qualcosa per essere un po 'più conforme ... ma le dimensioni esplodono ...
RosLuP,


1

Haskell 456 C

Può essere molto più breve se la funzionalità di valutazione pigra di Haskell è pienamente utilizzata. Purtroppo, non so come farlo.

Inoltre, molti personaggi vengono sprecati nella fase di analisi.

data T=A[Char]|B[Char]T|C T T
(!)=(++)
s(A a)=a
s(B a b)="(λ "!a!". "!s b!")"
s(C a b)='(':s a!" "!s b!")"
e d(A a)=maybe(A a)id(lookup a d)
e d(B a b)=B a.e d$b
e d(C a b)=f d(e d a)(e d b)
f d(B x s)q=e((x,q):d)s
f d p q=C p q
d=tail
p('(':'λ':s)=let(A c,t)=p(d s);(b,u)=p(d.d$t);in(B c b,d u)
p('(':s)=let(a,t)=p s;(b,u)=p(d t)in(C a b,d u)
p(c:s)|elem c" .)"=(A "",c:s)|1<2=let((A w),t)=p s in(A(c:w),t)
r=s.e[].fst.p
main=do l<-getLine;putStrLn$r l

Versione Ungolfed

data Expression = Literal String 
                | Lambda String Expression
                | Apply Expression Expression
                deriving Show

type Context = [(String, Expression)]

show' :: Expression -> String
show' (Literal a) = a
show' (Lambda x e) = "(λ " ++ x ++ ". " ++ show' e ++ ")"
show' (Apply e1 e2) = "(" ++ show' e1 ++ " " ++ show' e2 ++ ")"

eval :: Context -> Expression -> Expression
eval context e@(Literal a) = maybe e id (lookup a context)
eval context (Lambda x e) = Lambda x (eval context e)
eval context (Apply e1 e2) = apply context (eval context e1) (eval context e2)

apply :: Context -> Expression -> Expression -> Expression
apply context (Lambda x e) e2 = eval ((x, e2):context) e
apply context e1 e2 = Apply e1 e2

parse :: String -> (Expression, String)
parse ('(':'λ':s) = let
    (Literal a, s') = parse (tail s)
    (e, s'') = parse (drop 2 s')
    in (Lambda a e, tail s'')

parse ('(':s) = let
    (e1, s') = parse s
    (e2, s'') = parse (tail s')
    in (Apply e1 e2, tail s'')

parse (c:s) | elem c " .)" = (Literal "", c:s)
            | otherwise    = let ((Literal a), s') = parse s 
                             in (Literal (c:a), s')

run :: String -> String
run = show' . eval [] . fst . parse
main = do
  line <- getLine
  putStrLn$ run line

3
Questo non riesce a fare la cattura per evitare la sostituzione. Ad esempio, ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))) valuta erroneamente su (λ x. (Λ x. X)).
Anders Kaseorg,

1

Ottenuto 231 con JavaScript / nessun Regex

(function f(a){return a[0]?(a=a.map(f),1===a[0][0]?f(function d(b,a,e,c){return b[0]?1===b[0]?[1,d(b[1],a,e,c+1)]:2===b[0]?b[1]===c-1?d(a,0,c-1,0)||b:c-1<b[1]?[2,b[1]+e]:b:[d(b[0],a,e,c),d(b[1],a,e,c)]:b}(a[0],a[1],-1,0)[1]):a):a})

Riceve matrici a 2 elementi. 1sta per λe 2 sta per una variabile di indice bruijn.

Test:

zero = [1,[1,[2,0]]]; // λλ0
succ = [1,[1,[1,[[2,1],[[[2,2],[2,1]],[2,0]]]]]]; // λλλ(1 ((2 1) 0))
console.log(JSON.stringify(reduce([succ,[succ,[succ,zero]]]))); // 0+1+1+1
// Output: [1,[1,[[2,1],[[2,1],[[2,1],[2,0]]]]]] = λλ(1(1(1 0))) = number 3

Ciò non è conforme alle specifiche di input e output del problema.
Anders Kaseorg,

1

Python: 1266 caratteri (misurato usando il wc)

from collections import *;import re
A,B,y,c=namedtuple('A',['l','r']),namedtuple('B',['i','b']),type,list.pop
def ab(t):c(t,0);p=c(t,0);c(t,0);return B(p,tm(t))
def tm(t):return ab(t)if t[0]=='\\'else ap(t)
def at(t):
    if t[0]=='(':c(t,0);r=tm(t);c(t,0);return r
    if 96<ord(t[0][0])<123:return c(t,0)
    if t[0]=='\\':return ab(t)
def ap(t):
    l = at(t)
    while 1:
        r = at(t)
        if not r:return l
        l = A(l,r)
def P(s):return tm(re.findall(r'(\(|\)|\\|[a-z]\w*|\.)',s)+['='])
def V(e):o=y(e);return V(e.b)-{e.i} if o==B else V(e.l)|V(e.r)if o==A else{e}
def R(e,f,t):return B(e.i,R(e.b,f,t)) if y(e)==B else A(R(e.l,f,t),R(e.r,f,t))if y(e)==A else t if e==f else e
def N(i,e):return N(chr(97+(ord(i[0])-96)%26),e) if i in V(e)else i
def S(i,e,a): return A(S(i,e.l,a),S(i,e.r,a)) if y(e)==A else(e if e.i==i else B(N(e.i,a),S(i,R(e.b,e.i,N(e.i,a)),a)))if y(e)==B else a if e==i else e
def T(e):
    if y(e)==A:l,r=e;return S(l.i,l.b,r)if y(l)==B else A(T(l),r)if y(l)==A else A(l,T(r))
    if y(e)==B:return B(e.i,T(e.b))
    q
def F(e):o=y(e);return r'(\%s. %s)'%(e.i,F(e.b))if o==B else'(%s %s)'%(F(e.l),F(e.r)) if o==A else e
def E(a):
    try: return E(T(a))
    except NameError:print(F(a))
E(P(input()))

Non il più breve di un colpo lungo, ma gestisce correttamente la ridenominazione alfa e tutti gli esempi elencati nel post OP.


È possibile abbreviare alcuni di questi nomi di funzioni e trasformarne alcuni in lambda. Hai anche degli spazi bianchi in eccesso qua e là
Jo King,

(1) La sostituzione del rientro di 4 spazi con un singolo spazio farà risparmiare parecchi byte. (2) è possibile sostituire except NameErrorcon solo except? (3) I nomi delle funzioni a due caratteri possono essere rinominati in nomi a un carattere. (4) Ci sono alcuni posti in cui hai incarichi che hanno spazi attorno al =. (5) if t[0]=='c'può essere sostituito con if'c'==t[0].
Esolanging Fruit il

1045 byte attraverso la maggior parte delle modifiche di formattazione come rientro e lambda
Jo King,

0

C ++ (gcc) ,782 766 758 731 byte

#include <string>
#include <map>
#define A return
#define N new E
using S=std::string;using C=char;using I=int;S V(I i){A(i>8?V(i/9):"")+C(97+i%9);}S W(C*&s){C*b=s;while(*++s>96);A{b,s};}struct E{I t,i;E*l,*r;E(E&o,I d,I e){t=o.t;i=o.i+(o.i>=d)*e;t?l=N{*o.l,d,e},t-1?r=N{*o.r,d,e}:0:0;}E(I d,std::map<S,I>m,C*&s){t=*s-40?i=m[W(s)],0:*++s-92?l=N{d,m,s},r=N{d,m,++s},++s,2:(m[W(s+=2)]=d,l=N{d+1,m,s+=2},++s,1);}I R(I d){A t?t-1?l->t==1?l->l->s(d,0,*r),*this=*l->l,1:l->R(d)||r->R(d):l->R(d+1):0;}I s(I d,I e,E&v){t?t-1?l->s(d,e,v),r->s(d,e,v):l->s(d,e+1,v):i==d?*this={v,d,e},0:i-=i>d;}S u(I d){A t?t-1?S{"("}+l->u(d)+' '+r->u(d)+')':S{"(\\ "}+V(d)+". "+l->u(d+1)+')':V(i);}};S f(C*s){E a{0,{},s};for(I c=999;a.R(0)&&c--;);A a.u(0);}

Provalo online!

L'idea di base qui è che il codice utilizza una rappresentazione interna basata sull'idea degli indici de Bruijn - tranne per il fatto che invertisco gli indici per indicare la profondità lambda del legame della variabile indicata. Nel codice:

  • E::trappresenta il tipo di nodo - 0 per un nodo foglia variabile, 1 per un nodo lambda e 2 per un nodo applicazione funzione. (Scelto in modo che coincida con l'arità del nodo, che sembra essere possibile.) Quindi E::le E::rsono i bambini appropriati (solo E::lper un nodo lambda), ed E::iè l'indice di profondità lambda per un nodo foglia variabile.
  • Il costruttore E::E(E&o,int d,int e)clona una sottoespressione che inizialmente era alla profondità di lambda dper incollare in una nuova posizione alla profondità di lambda d+e. Ciò implica preservare le variabili a lambda in profondità meno che ddurante l'incremento delle variabili a lambda in profondità almeno ddi e.
  • E::sfa una sostituzione della sottoespressione vin numero variabile din *thismentre decrementando numero variabile superiore d(ed eè un dettaglio interno inseguimento l'incremento lambda approfondita per quando è necessario chiamata E::c).
  • E::Rcerca una singola riduzione beta da eseguire, preferendo le istanze più alte o più a sinistra in base a una ricerca pre-ordine tramite l'AST. Restituisce diverso da zero se trova una riduzione da eseguire o zero se non ne trova nessuno.
  • E::uè un'operazione di to_stringtipo che ricostituisce una stringa "leggibile dall'uomo" usando nomi sintetici per le variabili. (Si noti che a causa di un po 'di golf della Vfunzione helper genererà solo nomi che contengono aattraverso i.)
  • Il costruttore E::E(int d, std::map<std::string, int> m, char*&s)analizza una stringa di input sin un'espressione AST basata su una mappatura mdi nomi di variabili attualmente associati in indici di profondità lambda.
  • f è la funzione principale che risponde alla domanda.

(Come puoi vedere dal link TIO, il codice gestisce i nomi delle variabili con più caratteri e ottiene anche una risposta corretta (\ a. (\ b. a))per ((\ f. (\ x. (f x))) (\ y. (\ x. y))). Accade anche che il codice di analisi sia in grado di gestire l'ombreggiatura variabile senza costi aggiuntivi.)


-16 byte parzialmente dovuto idea da ceilingcat (che avevo anche venire con indipendentemente), ed in parte a causa del cambiamento E*a=new E;di E&a=*new E;e modificando a->dia.

-8 più byte a causa di un altro commento di ceilingcat (fattore di assegnazione a.tda ternario)

-27 byte dalla conversione del parser e clone in costruttori di E


-1

C 637 byte

#define R return
#define E if(i>=M||j>=M)R-1;
#define H d[j++]
enum{O=40,C,M=3999};signed char Q[M],D[M],t[M],Z,*o=Q,*d=D,*T;int m,n,s,c,w;K(i,j,k){!Z&&(Z=t[O]=1)+(t[C]=-1);E;if(!o[i]){H=0;R 0;}if((c=t[o[i]]+t[o[i+1]])!=2||o[i+2]!=92){H=o[i++];R K(i,j,i);}for(i+=2,w=0;i<M&&o[i]&&c;++i)c+=t[o[i]],!w&&c==1?w=i:0;E;if(c){for(;H=o[i++];)E;R 0;}for(c=k+7,n=j;c<w&&j<M;++c)if(o[c]==o[k+4]){if(o[c+1]==46){d[n++]=o[k++];R K(k,n,k);}for(m=w+2;m<i-1&&j<M;)H=o[m++];}else H=o[c];E;Z=2;R K(i,j,i);}char*L(char*a){for(s=n=0;n<M&&(o[n]=a[n]);++n);if(n==M)R 0;for(;++s<M;){Z=0;if((n=K(0,0,0))!=-1&&Z==2)T=d,d=o,o=T;else break;}R n==-1||s>=M?0:d;}

Questa versione non utilizza variabili ausiliarie (quindi non segue al 100% ciò che dice il calcolo lambda ... come molti altri qui ...). Ogni variabile deve essere lunga 1 carattere (come altre qui). Codice di prova:

#define P printf

main()
{char  *r[]={ "((\\ x. x) z)", 
              "((\\ x. x) (\\ y. (\\ z. z)))", 
              "(\\ x. ((\\ y. y) x))", 
              "((\\ x. (\\ y. x)) (\\ a. a))", 
              "(((\\ x. (\\ y. x)) (\\ a. a)) (\\ b. b))",
              "((\\ x. (\\ y. y)) (\\ a. a))",
              "(((\\ x. (\\ y. y)) (\\ a. a)) (\\ b. b))",
              "((\\ x. (x x)) (\\ x. (x x)))",
              "(((\\ x. (\\ y. x)) (\\ a. a)) ((\\ x. (x x)) (\\ x. (x x))))",
              "((\\ a. (\\ b. (a (a (a b))))) (\\ c. (\\ d. (c (c d)))))",
              "((\\ f. (\\ x. (f x))) (\\ y. (\\ x. y)))",
             0}, *y;
 int    w;

 for(w=0; r[w] ;++w)
   {y=L(r[w]);
    P("o=%s d=%s\n", r[w], y==0?"Error ":y);
   }
 R  0;
}

i risultati:

/*
637
o=((\ x. x) z) d=z
o=((\ x. x) (\ y. (\ z. z))) d=(\ y. (\ z. z))
o=(\ x. ((\ y. y) x)) d=(\ x. x)
o=((\ x. (\ y. x)) (\ a. a)) d=(\ y. (\ a. a))
o=(((\ x. (\ y. x)) (\ a. a)) (\ b. b)) d=(\ a. a)
o=((\ x. (\ y. y)) (\ a. a)) d=(\ y. y)
o=(((\ x. (\ y. y)) (\ a. a)) (\ b. b)) d=(\ b. b)
o=((\ x. (x x)) (\ x. (x x))) d=Error
o=(((\ x. (\ y. x)) (\ a. a)) ((\ x. (x x)) (\ x. (x x)))) d=(\ a. a)
o=((\ a. (\ b. (a (a (a b))))) (\ c. (\ d. (c (c d))))) d=(\ b. (\ d. (b (b (b (b (b (b (b (b d))))))))))
o=((\ f. (\ x. (f x))) (\ y. (\ x. y))) d=(\ x. (\ x. x))
*/

questo è il semi ungolf:

#define R return
#define E if(i>=M||j>=M)R-1;
#define H d[j++]
enum{O=40,C,M=3999}; // assume ascii
signed char Q[M],D[M],t[M],Z,*o=Q,*d=D,*T;
int m,n,s,c,w;

K(i,j,k)
{!Z&&(Z=t[O]=1)+(t[C]=-1); //inizializza tabelle

 E;if(!o[i]){H=0;R 0;}
 if((c=t[o[i]]+t[o[i+1]])!=2||o[i+2]!=92)
      {H=o[i++]; R K(i,j,i);}
 for(i+=2,w=0;i<M&&o[i]&&c;++i)
         c+=t[o[i]],!w&&c==1?w=i:0;
 E;
 if(c){for(;H=o[i++];)E;R 0;} 
//  01234567w12 i
//  ((/ x. x) z)
//   x                 w              z
// o[k+4]..o[k+5];  o[k+7]..o[w];  o[w+2]..o[i-1]

// sostituzione
// sostituisce a x z in w e lo scrive in d
for(c=k+7,n=j;c<w&&j<M;++c)
      if(o[c]==o[k+4])
         {if(o[c+1]==46) // non puo' sostituire una variabile dove c'e' lambda
             {d[n++]=o[k++]; R K(k,n,k);}
          for(m=w+2;m<i-1&&j<M;++m)
                H=o[m];
         }
      else H=o[c];
 E;
 Z=2;
 R K(i,j,i);
}

char*L(char*a)
{for(s=n=0;n<M&&(o[n]=a[n]);++n);
 if(n==M)R 0;
 for(;++s<M;)
   {Z=0;
    n=K(0,0,0);
//    if(Z==2)printf("n=%d>%s\n", n, d);
    if(Z==2&&n!=-1)T=d,d=o,o=T;
    else break;
   }
 R n==-1||s>=M?0:d; 
}

La specifica richiede \ o λ, non /. Richiede anche il supporto per nomi di variabili a più lettere. Inoltre (so che ne sei a conoscenza, ma sì, è ancora sbagliato), questo valuta erroneamente ((/ f. (/ X. (Fx))) (/ y. (/ X. Y))) a ( / x. (/ x. x)).
Anders Kaseorg,

Cambio / a \ c'è il problema non consentire la variabile multi caratteri. se ne provi un altro, questo vale anche per un'altra soluzione
RosLuP
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.