Tulis penerjemah untuk kalkulus lambda yang tidak diketik

45

Tantangannya adalah menulis penerjemah untuk kalkulus lambda yang tidak diketik dalam karakter sesedikit mungkin. Kami mendefinisikan kalkulus lambda yang tidak diketik sebagai berikut:

Sintaksis

Ada tiga jenis ekspresi berikut:

  • Ekspresi lambda memiliki bentuk di (λ x. e)mana xbisa berupa nama variabel hukum dan eekspresi hukum apa pun. Di sini xdisebut parameter dan edisebut fungsi tubuh.

    Demi kesederhanaan, kami menambahkan batasan lebih lanjut bahwa tidak boleh ada variabel dengan nama yang sama seperti xsaat ini dalam ruang lingkup. Suatu variabel mulai berada dalam cakupan ketika namanya muncul di antara dan .dan berhenti berada dalam lingkup pada yang bersangkutan ).

  • Aplikasi fungsi memiliki bentuk di (f a)mana fdan amerupakan ekspresi hukum. Di sini fdisebut fungsi dan adisebut argumen.
  • Variabel memiliki bentuk di xmana xnama variabel hukum.

Semantik

Suatu fungsi diterapkan dengan mengganti setiap kemunculan parameter di badan fungsi dengan argumennya. Lebih formal ekspresi dari bentuk ((λ x. e) a), di mana xadalah nama variabel dan edan aadalah ekspresi, mengevaluasi (atau mengurangi) untuk ekspresi e'di mana e'merupakan hasil dari penggantian setiap kemunculan xdi edengan a.

Bentuk normal adalah ungkapan yang tidak dapat dievaluasi lebih lanjut.

Tantangan

Misi Anda, jika Anda memilih untuk menerimanya, adalah untuk menulis seorang juru bahasa yang mengambil sebagai input ekspresi dari kalkulus lambda yang tidak diketik yang tidak mengandung variabel bebas dan menghasilkan sebagai output bentuk normal ekspresi (atau ekspresi alpha-kongruen dengan itu) . Jika ekspresi tidak memiliki bentuk normal atau itu bukan ekspresi yang valid, perilaku tidak terdefinisi.

Solusi dengan jumlah karakter terkecil menang.

Beberapa catatan:

  • Input dapat dibaca dari stdin atau dari nama file yang diberikan sebagai argumen baris perintah (Anda hanya perlu mengimplementasikan satu atau yang lain - tidak keduanya). Output menuju ke stdout.
  • Atau Anda dapat mendefinisikan fungsi yang mengambil input sebagai string dan mengembalikan output sebagai string.
  • Jika karakter non-ASCII bermasalah untuk Anda, Anda dapat menggunakan karakter backslash ( \) alih-alih λ.
  • Kami menghitung jumlah karakter, bukan byte, jadi meskipun file sumber Anda dikodekan sebagai unicode, λ dihitung sebagai satu karakter.
  • Nama variabel legal terdiri dari satu atau lebih huruf kecil, yaitu karakter antara a dan z (tidak perlu mendukung nama alfanumerik, huruf besar atau huruf non-latin - meskipun hal itu tidak akan membatalkan solusi Anda, tentu saja).
  • Sejauh menyangkut tantangan ini, tidak ada tanda kurung opsional. Setiap ekspresi lambda dan setiap aplikasi fungsi akan dikelilingi oleh tepat sepasang kurung. Tidak ada nama variabel yang akan dikelilingi oleh tanda kurung.
  • Gula sintaksis seperti menulis (λ x y. e)untuk (λ x. (λ y. e))tidak perlu didukung.
  • Jika kedalaman rekursi lebih dari 100 diperlukan untuk mengevaluasi suatu fungsi, perilaku tidak terdefinisi. Itu harus lebih dari cukup rendah untuk diimplementasikan tanpa optimasi dalam semua bahasa dan masih cukup besar untuk dapat mengeksekusi sebagian besar ekspresi.
  • Anda juga dapat mengasumsikan bahwa spasi akan seperti dalam contoh, yaitu tidak ada spasi di awal dan akhir input atau sebelum λatau .dan tepat satu spasi setelah a .dan antara fungsi dan argumennya dan setelah a λ.

Input dan Output Sampel

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

    Keluaran: (λ y. (λ z. z))

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

    Keluaran: (λ x. x)

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

    Keluaran: (λ y. (λ a. a))

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

    Keluaran: (λ a. a)

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

    Keluaran: (λ y. y)

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

    Keluaran: (λ b. b)

  • Memasukkan: ((λx. (x x)) (λx. (x x)))

    Keluaran: apa saja (Ini adalah contoh ekspresi yang tidak memiliki bentuk normal)

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

    Output: (λ a. a)(Ini adalah contoh ekspresi yang tidak menormalkan jika Anda mengevaluasi argumen sebelum pemanggilan fungsi, dan sayangnya contoh yang gagal diupayakan solusi saya)

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

    Keluaran: `(λ a. (λ b. (a (a (a (a (a (a (a (a b)))))))))) Ini menghitung 2 ^ 3 dalam angka Gereja.

sepp2k
sumber
1
Bisakah kita mengasumsikan bahwa tidak akan ada spasi putih yang ditambahkan atau ditambahkan ke string dan spasi putih itu sebagaimana ditentukan dalam input sampel? Artinya, tidak ada spasi kosong antara tanda kurung, antara titik dan nama parameter dan contoh spasi putih lainnya adalah 1 spasi.
JPvdMerwe
@JPvdMerwe: Ya, bagus, Anda mungkin menganggap itu.
sepp2k
Apakah ada variabel gratis? Maksud saya variabel tidak terikat oleh lambda seperti dalam ekspresi (\y. a).
FUZxxl
3
Banyak atau semua solusi di sini gagal menerapkan subtitusi penghindaran penangkapan! Anda harus menambahkan kasus uji seperti ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))), yang harus dievaluasi menjadi (λ x. (Λ z. X)), tidak (λ x. (λ x. x)).
Anders Kaseorg
1
@ sepp2k Sudahkah Anda mempertimbangkan untuk menambahkan ((λ f. (λ x. (fx))) (λ y. (λ x. y)))) sebagai kasus uji dan tidak menerima jawaban saat ini yang salah menghasilkan (λ x. (λ x. x))?
Anders Kaseorg

Jawaban:

36

Terbaru:

Saya telah memerasnya menjadi 644 karakter , saya memasukkan beberapa bagian cOll ke dalam cOpy dan Par; cache panggilan ke sel dan cdr ke variabel lokal sementara, dan memindahkan variabel-variabel lokal ke global dalam fungsi "terminal" (mis. non-rekursif). Juga, konstanta desimal lebih pendek dari karakter literal dan bisnis yang buruk ini ...

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

... mengidentifikasi huruf kecil dengan benar (dengan asumsi ASCII), tetapi juga menerima salah satu dari `{|} ~. (Pengamatan yang sama tentang ASCII ini dibuat dalam video yang luar biasa ini tentang 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;}

Sebelumnya:

Bisakah saya mendapatkan beberapa suara untuk usaha? Saya telah bekerja pada siang dan malam ini selama seminggu. Saya menggali kertas McCarthy asli dan diganggu oleh bug di kertas itu sendiri sampai saya membaca lampiran untuk The Roots of Lisp karya Paul Graham . Saya sangat terganggu sehingga saya mengunci diri dari rumah saya, kemudian benar-benar lupa sampai tiba di rumah lagi malam itu pukul 12:30 (sedikit terlambat untuk memanggil manajer bangunan yang tinggal jauh di county), dan harus menghabiskan malam di rumah nenek saya (meretas hingga baterai laptop saya kering).

Dan setelah semua itu, bahkan tidak dekat dengan entri pemenang!

Saya tidak yakin bagaimana membuat ini lebih pendek; dan saya telah menggunakan semua trik kotor yang dapat saya pikirkan! Mungkin tidak bisa dilakukan dalam C.

Dengan kedermawanan dalam penghitungan (chunk pertama mengambil string dan mencetak hasilnya), itu 778 770 709 694 karakter. Tetapi untuk membuatnya berdiri sendiri, ia harus memiliki sbrkpanggilan itu. Dan untuk menangani ekspresi yang lebih rumit, perlu signalhandler juga. Dan tentu saja itu tidak dapat dibuat menjadi modul dengan kode apa pun yang mencoba untuk digunakan malloc.

Jadi, sayang, ini dia:

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

Inilah blok tepat sebelum reduksi akhir. Trik di sini adalah kursor integer alih-alih pointer (mengambil keuntungan dari perilaku 'implisit int'), dan penggunaan 'memori awal': char*nadalah pointer 'baru' atau 'berikutnya' ke ruang kosong. Tetapi kadang-kadang saya menulis string ke dalam memori, kemudian memanggil strlen dan increment n; menggunakan memori secara efektif dan kemudian mengalokasikannya, setelah ukuran lebih mudah untuk dihitung. Anda dapat melihat itu hampir langsung dari makalah McCarthy, dengan pengecualian cell()antarmuka antara fungsi dan representasi string data.

#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;
}
luser droog
sumber
1
Saya menemukan beberapa trik untuk menyelamatkan satu atau dua karakter, tetapi tidak ada yang radikal. sprintf(n,...);n+=strlen(n)+1;lebih baik sebagai n+=sprintf(n,...)+1;pembalikan sintaks array x[m]daripada m[x]memungkinkan saya untuk mengganti semua tipuan dengan makro 'postfix' #define M [m]... x Myang menyimpan 1 char dan memberikan garis "bebas" baris karena spasi diperlukan untuk memisahkan token.
luser droog
Tampaknya ada beberapa kesamaan dengan ini dan jar.2 xlisp 4.0 dari IOCCC 1989 .
luser droog
Saya mencoba mengembangkan ini menjadi interpreter Lisp yang lebih lengkap .
luser droog
Kode yang dikomentari // um ...adalah perulangan melalui string dan menghitung tanda kurung sampai menemukan paren dekat yang sesuai pada tingkat bersarang yang benar.
luser droog
1
Ini salah mengevaluasi ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) ke (\ x. (Fx)).
Anders Kaseorg
22

Binary Lambda Calculus 186

Program ditunjukkan dalam hex dump di bawah ini

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  |[email protected]|
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

tidak cukup menerima format yang Anda usulkan. Sebaliknya, ia mengharapkan istilah lambda dalam format kalkulus binda lambda (blc). Namun, itu menunjukkan setiap langkah dalam pengurangan bentuk normal, menggunakan tanda kurung minimal.

Contoh: menghitung 2 ^ 3 dalam angka Gereja

Simpan hex dump di atas dengan xxd -r> symbolic.Blc

Dapatkan juru bahasa blc dari 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)))))))

Karena hexdump agak tidak dapat dibaca, ini adalah versi "dibongkar"

@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\
@

mengganti 00 (lambda) dengan \ dan 01 (aplikasi) dengan @ Sekarang hampir bisa dibaca seperti brainfuck :-)

Juga lihat http://www.ioccc.org/2012/tromp/hint.html

John Tromp
sumber
7
BLC kebetulan menggunakan alfabet biner. 00 adalah lambda, 01 adalah aplikasi, dan 1 ^ {n} 0 adalah variabel dalam unary. Tidak ada kompilasi yang terlibat.
John Tromp
3
Di mana Anda mendapatkan faktor x3? Anda benar-benar mendapatkan poin bagus dalam bahasa-bahasa dengan abjad sumber yang lebih kecil seperti BF akan dihukum. Untuk perbandingan yang adil, semua ukuran harus dinyatakan dalam bit, dan karakter BF hanya mengambil masing-masing 3 bit. Kebanyakan bahasa lain membutuhkan 7 bit untuk ASCII, beberapa menggunakan semua 8.
John Tromp
1
BTW +1 Ini sangat keren!
luser droog
1
Jika fractran dalam fractran dapat diterima, saya tidak melihat mengapa ini harus menjadi masalah sama sekali. Anda tidak bisa membacanya? Yang kamu ingin? Belajar!
luser droog
1
Apa yang diperlukan untuk membuatnya membaca format input yang sebenarnya? Saya pikir di situlah Anda kehilangan potensi upvotes.
luser droog
14

Haskell, 342 323 317 305 karakter

Pada tulisan ini, ini adalah satu-satunya solusi yang mengevaluasi ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))) dengan hasil yang benar (λ x. (Λ z. x)) daripada (λ x. (λ x. x)). Implementasi yang benar dari kalkulus lambda membutuhkan penggantian yang menghindari penangkapan , bahkan di bawah jaminan penyederhanaan masalah ini bahwa tidak ada variabel yang menaungi variabel lain dalam cakupannya. (Program saya kebetulan bekerja bahkan tanpa jaminan ini.)

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

Catatan:

  • Ini berjalan di GHC 7.0, seperti yang dipersyaratkan karena tantangan ini ditetapkan pada Januari 2011. Ini akan menjadi 13 karakter lebih pendek jika saya diizinkan untuk mengasumsikan GHC 7.10.

Versi tidak dikoleksi dengan dokumentasi.

Anders Kaseorg
sumber
prog Anda di ideone haskell compiler ke input ((\ x. x) (\ y. (\ z. z)))) mengembalikan "run time error" bahkan dalam ((\\ x. x) (\\ y. ( \\ z. z))) ... apa artinya "lex" di Haskell?
RosLuP
2
@RosLuP Program saya menerima λ, bukan \.
Anders Kaseorg
ketik imput ini ((λ x. x) (λ y. (λ z. z))) di ideone.com kembali: Waktu kesalahan runtime: 0 memori: 4876 sinyal: -1
RosLuP
1
@RosLuP Ideone tampaknya telah merusak dukungan Unicode. Coba baris perintah atau juru bahasa online lainnya (misalnya, bekerja pada Rextester ).
Anders Kaseorg
2
@codeshot Penulis pertanyaan telah berkomentar bahwa ((λ f. (λ x. (fx))) (λ y. (λ x. y))) ↦ (λ x. (λ z. x)) sudah benar untuk masalah ini (seperti kalkulus lambda nyata).
Anders Kaseorg
13

Python - 321 320

Inilah upaya saya (diperbaiki):

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())
JPvdMerwe
sumber
Ini terlihat bagus, tetapi sepertinya tidak berhasil. Saya telah menambahkan beberapa contoh input dan output, di mana kode Anda menghasilkan hasil yang salah.
sepp2k
1
Ini gagal melakukan substitusi menghindari penangkapan. Misalnya, ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) salah mengevaluasi ke (\ x. (\ X. X)).
Anders Kaseorg
1
Mengapa ini ditandai sebagai jawaban ketika hampir tidak berfungsi? Sudahkah Anda mencoba input dan output yang diberikan oleh penulis?
rbaleksandar
1
Kasing yang disediakan penulis tidak cukup untuk menunjukkan bug dalam jawaban ini.
Anders Kaseorg
1
Jawaban ini tidak benar atau terpendek. Gagal menghindari penangkapan dan memiliki bug pengganti string.
Richard Padley
6

Ruby 254 karakter

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}

Dapat digunakan seperti

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

Solusinya belum sepenuhnya golf tetapi sudah hampir tidak dapat dibaca.

Howard
sumber
halo iri, teman lamaku :)
luser droog
Ini gagal melakukan substitusi menghindari penangkapan. Misalnya, ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) salah mengevaluasi ke (\ x. (\ X. X)).
Anders Kaseorg
Selain bug penangkapan di atas, ini juga salah mengevaluasi (\ y. (\ Xx. ((\ X. Xx) y))) ke (\ y. (\ Xx. Yy)), di mana substitusi string yang terlalu bersemangat telah diproduksi variabel yy tidak ada.
Anders Kaseorg
3

Sunting: periksa jawaban saya di bawah untuk 250 di bawah JavaScript murni.

2852 243 karakter menggunakan LiveScript (Tidak Ada Regex! Tidak sepenuhnya golf - bisa ditingkatkan)

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

Uji:

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]]]]]]]]]]]

Yaitu 3^2=9, sebagaimana dinyatakan pada OP.

Jika ada yang ingin tahu, ini adalah versi yang diperluas dengan beberapa komentar:

# 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]
Viktor Maia
sumber
Ini tidak sesuai dengan spesifikasi input dan output dari masalah.
Anders Kaseorg
3

Waterhouse Arc - 140 karakter

(=
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 #\._])
dipanaskan
sumber
Di mana saya bisa mendapatkan Waterhouse Arc?
Anders Kaseorg
1
Tidak valid sebagai juru bahasa tidak ditemukan
cat
@AndersKaseorg di sini
ASCII
@ ASCII-saja saya tahu apa itu Arc, tetapi bagian “Waterhouse” menyarankan kepada saya bahwa beberapa dialek tertentu diperlukan. Sudahkah Anda menjalankannya?
Anders Kaseorg
@AndersKaseorg Sudahlah. Ditemukan
ASCII
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;}

Variabel memungkinkan sebagai input menggunakan huruf kecil [dari a..z] sistem dapat menghasilkan variabel menggunakan huruf besar [dari A..Z] jika perlu dalam output ... Asumsikan konfigurasi karakter 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*/
RosLuP
sumber
Spesifikasi memerlukan \ atau λ, bukan /. Ini juga memerlukan dukungan untuk nama variabel multi-huruf.
Anders Kaseorg
'\ n' simbol dll '\' memiliki kegunaan lain, lebih baik menggunakan '/' sebagai gantinya
RosLuP
1
Namun, tantangannya adalah untuk memenuhi spesifikasi, bukan untuk membuatnya lebih baik.
Anders Kaseorg
saya menulis sesuatu untuk itu sedikit lebih sesuai ... tetapi ukuran meledak ...
RosLuP
1
932 bytes
ceilingcat
1

Haskell 456 C

Ini bisa menjadi jauh lebih pendek jika fitur evaluasi malas dari Haskell sepenuhnya digunakan. Sayangnya, saya tidak tahu bagaimana cara melakukannya.

Juga, banyak karakter terbuang pada langkah penguraian.

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

Versi tidak disatukan

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
sinar
sumber
3
Ini gagal melakukan substitusi menghindari penangkapan. Misalnya, ((λ f. (Λ x. (Fx))) (λ y. (Λ x. Y))) mengevaluasi secara salah terhadap (λ x. (Λ x. X)).
Anders Kaseorg
1

Mendapat 231 dengan JavaScript / tanpa 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})

Menerima array 2-elemen. 1singkatan λdan 2 berarti variabel indeks bruijn.

Uji:

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
Viktor Maia
sumber
Ini tidak sesuai dengan spesifikasi input dan output dari masalah.
Anders Kaseorg
1

Python: 1266 karakter (diukur menggunakan 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()))

Bukan yang terpendek oleh tembakan panjang, tapi itu benar menangani alpha-renaming dan semua contoh yang tercantum dalam pos OP.

Björn Lindqvist
sumber
Anda dapat mempersingkat beberapa nama fungsi tersebut, dan mengubahnya menjadi lambda. Anda juga memiliki kelebihan spasi putih di sana
Jo King
(1) Mengganti lekukan 4-ruang dengan satu ruang akan menghemat beberapa byte. (2) Bisakah Anda menggantinya except NameErrordengan adil except? (3) Nama fungsi dua karakter dapat diubah namanya menjadi nama satu karakter. (4) Ada beberapa tempat di mana Anda memiliki tugas yang memiliki ruang di sekitar =. (5) if t[0]=='c'dapat diganti dengan if'c'==t[0].
Buah Esolanging
1045 byte melalui sebagian besar perubahan format seperti lekukan dan lambdas
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);}

Cobalah online!

Ide dasar di sini adalah bahwa kode menggunakan representasi internal berdasarkan pada gagasan de Bruijn indeks - kecuali bahwa saya membalikkan indeks untuk menunjukkan lambda mendalam tentang pengikatan variabel disebut. Dalam kode:

  • E::tmewakili jenis simpul - 0 untuk simpul daun variabel, 1 untuk simpul lambda, dan 2 untuk simpul aplikasi fungsi. (Dipilih sehingga bertepatan dengan arity dari node, yang kebetulan mungkin terjadi.) Lalu E::ldan E::rapakah anak-anak sesuai (hanya E::luntuk simpul lambda), dan E::imerupakan indeks kedalaman lambda untuk simpul daun variabel.
  • Konstruktor E::E(E&o,int d,int e)mengkloning subekspresi yang awalnya di kedalaman lambda duntuk menempel ke lokasi baru di kedalaman lambda d+e. Ini melibatkan mempertahankan variabel di kedalaman lambda kurang dari dsementara meningkatkan variabel di kedalaman lambda setidaknya doleh e.
  • E::smelakukan substitusi subexpression yang vmenjadi variabel jumlah ddi *thissaat decrementing nomor variabel lebih besar dari d(dan eadalah detail internal yang melacak kenaikan lambda mendalam untuk saat dibutuhkan untuk panggilan E::c).
  • E::Rmencari pengurangan beta tunggal untuk melakukan, lebih memilih instance paling atas atau paling kiri menurut pencarian pre-order melalui AST. Ini mengembalikan nol jika ditemukan pengurangan untuk melakukan atau nol jika tidak ditemukan.
  • E::uadalah to_stringtipe operasi yang menyusun kembali string "dapat dibaca manusia" menggunakan nama sintetis untuk variabel. (Perhatikan bahwa karena golf sedikit dari Vfungsi pembantu itu hanya akan menghasilkan nama yang mengandung amelalui i.)
  • Konstruktor E::E(int d, std::map<std::string, int> m, char*&s)melakukan parsing dari string input ske ekspresi AST berdasarkan pemetaan mnama variabel yang saat ini terikat ke indeks kedalaman lambda.
  • f adalah fungsi utama menjawab pertanyaan.

(Seperti yang Anda lihat di link TIO, kode tidak nama variabel menangani dengan beberapa karakter, dan juga mendapat jawaban yang benar dari (\ a. (\ b. a))untuk ((\ f. (\ x. (f x))) (\ y. (\ x. y))). Ini juga kebetulan bahwa kode parsing dapat menangani variabel membayangi tanpa biaya tambahan.)


-16 byte sebagian karena ide oleh ceilingcat (yang juga saya buat sendiri), dan sebagian karena berubah E*a=new E;menjadi E&a=*new E;dan kemudian berubah a->menjadia.

-8 byte lebih karena komentar lain oleh ceilingcat (faktor penugasan dari a.tdari ternary)

-27 byte dari pengonversi parser dan klon menjadi konstruktor E

Daniel Schepler
sumber
-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;}

Versi ini tidak menggunakan variabel bantu (jadi ini tidak mengikuti 100% apa yang dikatakan kalkulus lambda ... karena banyak lainnya di sini ...). Setiap variabel harus sepanjang 1 karakter (seperti beberapa lainnya di sini). Kode uji:

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

hasil:

/*
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))
*/

ini adalah 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; 
}
RosLuP
sumber
Spesifikasi memerlukan \ atau λ, bukan /. Ini juga memerlukan dukungan untuk nama variabel multi-huruf. Selain itu (saya tahu Anda mengetahui hal ini, tapi ya, itu masih salah), ini salah mengevaluasi ((/ f. (/ X. (Fx))) (/ y. (/ X. Y))) ke ( / x. (/ x. x)).
Anders Kaseorg
Saya mengubah / ke \ ada masalah tidak mengizinkan variabel multi-karakter. jika menguji beberapa yang lain ini juga untuk solusi lain
RosLuP