เขียนล่ามสำหรับแคลคูลัสแลมบ์ดาที่ยังไม่พิมพ์


45

ความท้าทายคือการเขียนล่ามสำหรับแคลคูลัสแลมบ์ดาที่ไม่ได้พิมพ์ไว้ในตัวละครให้น้อยที่สุด เรากำหนดแคลคูลัสแลมบ์ดาที่ไม่ได้พิมพ์ดังนี้:

วากยสัมพันธ์

นิพจน์มีสามประเภทดังต่อไปนี้:

  • การแสดงออกแลมบ์ดามีรูปแบบ(λ x. e)ที่xอาจเป็นชื่อตัวแปรทางกฎหมายและeการแสดงออกทางกฎหมายใด ๆ นี่xเรียกว่าพารามิเตอร์และeเรียกว่าร่างกายของฟังก์ชั่น

    เพื่อความง่ายเราได้เพิ่มข้อ จำกัด เพิ่มเติมว่าจะต้องไม่มีตัวแปรที่มีชื่อเดียวกันกับxขอบเขตในปัจจุบัน ตัวแปรเริ่มต้นที่จะอยู่ในขอบเขตเมื่อชื่อของมันปรากฏขึ้นระหว่างและและหยุดที่จะอยู่ในขอบเขตที่สอดคล้องกัน.)

  • แอปพลิเคชั่นมีรูปแบบ(f a)ที่ไหนfและaเป็นนิพจน์ทางกฎหมาย ที่นี่fเรียกว่าฟังก์ชั่นและaเรียกว่าอาร์กิวเมนต์
  • ตัวแปรมีรูปแบบxที่xเป็นชื่อตัวแปรทางกฎหมาย

อรรถศาสตร์

ฟังก์ชั่นถูกนำไปใช้โดยการแทนที่แต่ละพารามิเตอร์ที่เกิดขึ้นในร่างกายฟังก์ชั่นด้วยการโต้แย้ง อีกอย่างเป็นทางการการแสดงออกในรูปแบบ((λ x. e) a)ที่xเป็นชื่อตัวแปรและeและaมีการแสดงออกประเมิน (หรือลด) เพื่อการแสดงออกe'ที่e'เป็นผลมาจากการเปลี่ยนที่เกิดขึ้นแต่ละแห่งxในด้วยea

รูปแบบปกติคือการแสดงออกซึ่งไม่สามารถประเมินเพิ่มเติม

ความท้าทาย

ภารกิจของคุณหากคุณเลือกที่จะยอมรับมันคือการเขียนล่ามซึ่งใช้เป็นนิพจน์ของแคลคูลัสแลมบ์ดาที่ไม่มีการพิมพ์ที่ไม่มีตัวแปรอิสระและสร้างผลลัพธ์ตามรูปแบบปกติของนิพจน์ . หากการแสดงออกไม่มีรูปแบบปกติหรือไม่ใช่การแสดงออกที่ถูกต้องพฤติกรรมที่ไม่ได้กำหนด

โซลูชันที่มีจำนวนอักขระน้อยที่สุดชนะ

หมายเหตุสองประการ:

  • อินพุตอาจถูกอ่านจาก stdin หรือจากชื่อไฟล์ที่กำหนดเป็นอาร์กิวเมนต์บรรทัดคำสั่ง (คุณจะต้องใช้อย่างใดอย่างหนึ่งหรืออื่น ๆ - ไม่ใช่ทั้งสองอย่าง) เอาต์พุตไปที่ stdout
  • อีกทางหนึ่งคุณอาจกำหนดฟังก์ชั่นที่รับอินพุตเป็นสตริงและส่งคืนเอาต์พุตเป็นสตริง
  • หากอักขระที่ไม่ใช่ ASCII เป็นปัญหาสำหรับคุณคุณสามารถใช้เครื่องหมายแบ็กสแลช ( \) แทนλ
  • เรานับจำนวนอักขระไม่ใช่ไบต์ดังนั้นแม้ว่าไฟล์ต้นฉบับของคุณจะถูกเข้ารหัสเป็น Unicode un จะนับเป็นหนึ่งอักขระ
  • ชื่อตัวแปรตามกฎหมายประกอบด้วยตัวอักษรตัวพิมพ์เล็กอย่างน้อยหนึ่งตัวเช่นอักขระระหว่าง a และ z (ไม่จำเป็นต้องสนับสนุนชื่อตัวอักษรและตัวเลขตัวอักษรตัวพิมพ์ใหญ่หรือตัวอักษรที่ไม่ใช่ละติน - แม้ว่าการทำเช่นนั้นจะไม่ทำให้โซลูชันของคุณใช้ไม่ได้)
  • เท่าที่ความท้าทายนี้เกี่ยวข้องไม่มีวงเล็บเป็นตัวเลือก การแสดงออกแลมบ์ดาแต่ละครั้งและการใช้งานฟังก์ชั่นแต่ละอย่างจะถูกล้อมรอบด้วยวงเล็บหนึ่งคู่ ไม่มีชื่อตัวแปรจะถูกล้อมรอบด้วยวงเล็บ
  • น้ำตาลประโยคเช่นการเขียน(λ x y. e)สำหรับการ(λ x. (λ y. e))ไม่จำเป็นต้องได้รับการสนับสนุน
  • หากจำเป็นต้องใช้ความลึกการเรียกซ้ำมากกว่า 100 เพื่อประเมินฟังก์ชันการทำงานนั้นจะไม่ได้กำหนดไว้ นั่นควรจะต่ำเกินพอที่จะใช้งานได้โดยไม่ต้องปรับให้เหมาะสมในทุกภาษาและยังมีขนาดใหญ่พอที่จะสามารถใช้งานนิพจน์ส่วนใหญ่ได้
  • นอกจากนี้คุณยังอาจสมมติว่าการเว้นวรรคจะเป็นในตัวอย่างเช่นไม่มีช่องว่างที่จุดเริ่มต้นและจุดสิ้นสุดของอินพุตหรือก่อนหน้าหนึ่งλหรือ.หนึ่งช่องว่างหลังจาก.และระหว่างฟังก์ชันและอาร์กิวเมนต์และหลังจากλนั้น

ตัวอย่างอินพุตและเอาต์พุต

  • การป้อนข้อมูล: ((λ x. x) (λ y. (λ z. z)))

    เอาท์พุท: (λ y. (λ z. z))

  • การป้อนข้อมูล: (λ x. ((λ y. y) x))

    เอาท์พุท: (λ x. x)

  • การป้อนข้อมูล: ((λ x. (λ y. x)) (λ a. a))

    เอาท์พุท: (λ y. (λ a. a))

  • การป้อนข้อมูล: (((λ 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)))

    เอาท์พุท: อะไร (นี่คือตัวอย่างของการแสดงออกที่ไม่มีรูปแบบปกติ)

  • การป้อนข้อมูล: (((λ x. (λ y. x)) (λ a. a)) ((λx. (x x)) (λx. (x x))))

    เอาท์พุท: (λ a. a)(นี่เป็นตัวอย่างของนิพจน์ที่ไม่ได้ทำให้ปกติถ้าคุณประเมินข้อโต้แย้งก่อนการเรียกใช้ฟังก์ชั่นและเป็นตัวอย่างที่น่าเศร้าที่วิธีแก้ปัญหาของฉันพยายามล้มเหลว)

  • การป้อนข้อมูล: ((λ a. (λ b. (a (a (a b))))) (λ c. (λ d. (c (c d)))))

    เอาท์พุท: `(λ a. (λ b. (a (a (a (a (a (a (a (a b)))))))))) นี่คำนวณ 2 ^ 3 ในเลขคริสตจักร


1
เราสามารถสมมติได้ว่าจะไม่มีการต่อเติมหรือผนวกช่องว่างกับสตริงและช่องว่างนั้นเป็นอย่างอื่นตามที่ระบุไว้ในตัวอย่างอินพุต? นั่นคือไม่มีช่องว่างระหว่างวงเล็บระหว่างจุดและชื่อพารามิเตอร์และอินสแตนซ์อื่น ๆ ของช่องว่างคือ 1 ช่องว่าง
JPvdMerwe

@JPvdMerwe: ใช่จุดดีคุณอาจคิดว่า
sepp2k

มีตัวแปรอิสระหรือไม่? (\y. a)ผมหมายถึงตัวแปรที่ไม่ได้ผูกไว้โดยแลมบ์ดาเหมือนในการแสดงออก
FUZxxl

3
โซลูชันจำนวนมากหรือทั้งหมดที่นี่ไม่สามารถใช้การทดแทนการหลีกเลี่ยงการจับภาพได้! คุณควรเพิ่มกรณีทดสอบเช่น ((λ f. (λ x. (fx))) (λ y. (λ x. y))) ซึ่งควรประเมินเป็น (λ x. (λ z. x)) ไม่ (λ x. (λ x. x))
Anders Kaseorg

1
@ sepp2k คุณได้พิจารณาเพิ่ม ((λ f. (λ x. (fx))) (λ y. (λ x. y))) เป็นกรณีทดสอบและยอมรับคำตอบปัจจุบันที่สร้างอย่างไม่ถูกต้อง (λ x. (λ x. x))?
Anders Kaseorg

คำตอบ:


36

ใหม่:

ฉันบีบมันลงเหลือ644 ตัวอักษรฉันแยกส่วนของ cEll ให้เป็น cOpy และ Par; การเรียกใช้แคชไปยังเซลล์และ cdr เป็นตัวแปรท้องถิ่นชั่วคราวและย้ายตัวแปรท้องถิ่นเหล่านั้นไปยัง globals ในฟังก์ชั่น "terminal" (เช่น. non-recursive) นอกจากนี้ค่าคงที่ทศนิยมจะสั้นกว่าตัวอักษรและธุรกิจที่น่ารังเกียจ ...

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

... ระบุตัวอักษรตัวพิมพ์เล็กอย่างถูกต้อง (สมมติว่า ASCII) แต่ยังยอมรับ `{|} ~ ใด ๆ (ข้อสังเกตเดียวกันเกี่ยวกับ ASCII นี้ทำในวิดีโอที่ยอดเยี่ยมเกี่ยวกับ UTF-8 )

และ 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;}

ก่อนหน้านี้:

ฉันจะได้รับคะแนนโหวตเล็กน้อยสำหรับความพยายามหรือไม่? ฉันทำงานทั้งวันทั้งคืนเป็นเวลาหนึ่งสัปดาห์ ฉันขุดออกกระดาษแมคคาร์ต้นฉบับและเป็นโรคข้อผิดพลาดในกระดาษของตัวเองจนกว่าฉันจะอ่านภาคผนวกที่พอลเกรแฮมรากของเสียงกระเพื่อม ฉันฟุ้งซ่านจนล็อคตัวเองออกจากบ้านจากนั้นลืมไปจนกลับมาถึงบ้านอีกครั้งในเวลา 12:30 น. (สายเล็ก ๆ น้อย ๆ เพื่อโทรหาผู้จัดการอาคารที่อาศัยอยู่นอกเขต) และต้องใช้เวลา คืนที่ยายของฉัน (แฮ็คออกไปจนกว่าแบตเตอรี่แล็ปท็อปของฉันแห้ง)

และหลังจากนั้นก็ไม่ได้ใกล้เคียงกับรายการที่ชนะ!

ฉันไม่แน่ใจว่าจะทำให้สั้นลงได้อย่างไร และฉันได้ใช้อุบายสกปรกทั้งหมดที่ฉันคิดได้! อาจจะไม่สามารถทำได้ในซี

ด้วยความเอื้ออาทรบางอย่างในการนับ (ก้อนแรกใช้สตริงและพิมพ์ผลลัพธ์) มันคือ778 770 709 694ตัวอักษร แต่การที่จะทำให้มันอยู่คนเดียวมันต้องมีsbrkสายนั้น และเพื่อจัดการกับการแสดงออกที่ซับซ้อนมากขึ้นก็ต้องsignalจัดการเช่นกัน และแน่นอนว่ามันไม่สามารถทำให้เป็นโมดูลที่มีรหัสใด ๆ mallocที่พยายามที่จะใช้

ดังนั้นอนิจจานี่คือ:

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

นี่คือบล็อกก่อนการลดขั้นสุดท้าย เทคนิคที่นี่คือเคอร์เซอร์จำนวนเต็มแทนที่จะเป็นพอยน์เตอร์ (การใช้ประโยชน์จากพฤติกรรม 'นัยโดยนัย') และการใช้ 'หน่วยความจำรอยขีดข่วน': char*nเป็นตัวชี้ 'ใหม่' หรือ 'ถัดไป' ลงในพื้นที่ว่าง แต่บางครั้งฉันเขียนสตริงลงในหน่วยความจำจากนั้นเรียก strlen และ increment n; ใช้หน่วยความจำอย่างมีประสิทธิภาพแล้วจัดสรรหลังจากขนาดง่ายต่อการคำนวณ คุณสามารถเห็นได้ว่ามันค่อนข้างตรงจากกระดาษของ McCarthy ยกเว้นcell()ว่าส่วนต่อประสานระหว่างฟังก์ชั่นและการแสดงสตริงของข้อมูลเป็นอย่างไร

#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
ฉันพบเคล็ดลับเพิ่มเติมเพื่อประหยัดอักขระหนึ่งหรือสองตัว แต่ไม่มีอะไรรุนแรง sprintf(n,...);n+=strlen(n)+1;จะดีกว่าถ้าn+=sprintf(n,...)+1;Inverting ไวยากรณ์x[m]ของอาร์เรย์แทนที่จะm[x]อนุญาตให้ฉันแทนที่ทางอ้อมทั้งหมดด้วยมาโคร 'postfix' #define M [m]... x Mซึ่งช่วยประหยัด 1 ถ่านและให้การแบ่งบรรทัด "ฟรี" เนื่องจากช่องว่างจำเป็นต้องแยกโทเค็น
luser droog

ดูเหมือนจะมีความคล้ายคลึงกันบางคนที่มีนี้และ jar.2 xlisp 4.0 จาก IOCCC 1989
luser droog

ฉันพยายามขยายสิ่งนี้ให้เป็นล่ามเสียงกระเพื่อมขึ้น
luser droog

โค้ดที่ใส่ความคิดเห็น// um ...นั้นวนซ้ำผ่านสตริงและวงเล็บนับจนกว่าจะพบการจับคู่แบบโคลสอัพที่ระดับการซ้อนที่ถูกต้อง
luser droog

1
สิ่งนี้ประเมินอย่างไม่ถูกต้อง ((\ f. (\ x. (fx))) (\ y. (\ x. y)))) (\ x. (fx))
Anders Kaseorg

22

ไบนารีแลมบ์ดาแคลคูลัส 186

โปรแกรมที่แสดงในฐานสิบหกด้านล่าง

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

ไม่ยอมรับรูปแบบที่คุณเสนอ ค่อนข้างจะคาดว่าคำแลมบ์ดาในรูปแบบไบนารีแลมบ์แคลคูลัส (BLC) อย่างไรก็ตามมันจะแสดงทุกขั้นตอนในการลดรูปแบบปกติโดยใช้วงเล็บน้อยที่สุด

ตัวอย่าง: การคำนวณ 2 ^ 3 ในเลขคริสตจักร

บันทึกดัมพ์เลขฐานสิบหกด้านบนด้วย xxd -r> symbolic.Blc

หยิบล่าม blc จาก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)))))))

เนื่องจาก hexdump ค่อนข้างอ่านไม่ได้นี่คือรุ่น "ถอดชิ้นส่วน"

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

แทนที่ 00 (แลมบ์ดา) ด้วย \ และ 01 (แอปพลิเคชัน) ด้วย @ ตอนนี้มันเกือบจะอ่านได้เหมือน brainfuck :-)

ดูhttp://www.ioccc.org/2012/tromp/hint.html


7
BLC เพิ่งเกิดขึ้นเพื่อใช้ตัวอักษรไบนารี 00 คือแลมบ์ดา, 01 คือแอปพลิเคชันและ 1 ^ {n} 0 เป็นตัวแปรในเอกภาพ ไม่มีการรวบรวมที่เกี่ยวข้อง
John Tromp

3
คุณจะได้รับปัจจัย x3 ที่ไหน คุณยกประเด็นที่ดีในภาษานั้นที่มีตัวอักษรขนาดเล็กเช่น BF ถูกลงโทษ สำหรับการเปรียบเทียบที่เป็นธรรมขนาดทั้งหมดควรแสดงเป็นบิตและอักขระ BF ใช้เวลาเพียง 3 บิตเท่านั้น ภาษาอื่นส่วนใหญ่ต้องการ 7 บิตสำหรับ ASCII บางภาษาใช้ทั้งหมด 8
John Tromp

1
BTW +1 นี่มันเจ๋งมาก!
luser droog

1
ถ้าแฟร็กทัลในแฟร็กแทรนเป็นที่ยอมรับฉันไม่เห็นว่าทำไมจึงเป็นปัญหา คุณอ่านไม่ออกเหรอ? คุณต้องการ? เรียนรู้!
luser droog

1
สิ่งที่ต้องใช้เพื่อให้อ่านรูปแบบอินพุตจริง ฉันคิดว่านั่นคือสิ่งที่คุณสูญเสีย upvotes ที่อาจเกิดขึ้น
luser droog

14

Haskell, 342 323 317 305 ตัวละคร

นี่เป็นทางออกเดียวที่ประเมิน ((λ f. (λ x. (fx))) (λ y. (λ x. y)) กับผลลัพธ์ที่ถูกต้อง (λ x. (λ z x)) มากกว่า (λ x. (λ x. x)) การติดตั้งแคลคูลัสแลมบ์ดาอย่างถูกต้องต้องใช้การทดแทนการหลีกเลี่ยงการดักจับแม้จะอยู่ภายใต้การรับประกันที่ง่ายขึ้นของปัญหานี้ซึ่งไม่มีตัวแปรที่ทำให้เกิดเงาตัวแปรอื่นในขอบเขตของมัน (โปรแกรมของฉันทำงานได้แม้ไม่มีการรับประกันนี้)

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

หมายเหตุ:

  • สิ่งนี้จะทำงานใน GHC 7.0 ตามที่ต้องการเนื่องจากความท้าทายนี้ถูกตั้งค่าในเดือนมกราคม 2011 มันจะสั้นกว่า 13 ตัวอักษรถ้าฉันได้รับอนุญาตให้ใช้ GHC 7.10

เวอร์ชันที่ไม่อัปโหลดพร้อมเอกสารประกอบ


prog ของคุณใน ideone haskell คอมไพเลอร์ไปยังอินพุต ((\ x. x) (\ y. (\ z. z))) กลับ "ข้อผิดพลาดรันไทม์" แม้ใน ((\\ x. x) (\\ y. ( \\ z. z))) ... มันหมายความว่าอะไร "lex" ใน Haskell?
RosLuP

2
@RosLuP โปรแกรมของฉันยอมรับλไม่ใช่ \
Anders Kaseorg

พิมพ์ imput นี้ ((λ x. x) (λ y. (λ z. z))) ในผลตอบแทน ideone.com: เวลาข้อผิดพลาดรันไทม์: 0 หน่วยความจำ: สัญญาณ 4876: -1
RosLuP

1
@RosLuP Ideone ดูเหมือนว่าจะสนับสนุน Unicode ที่ขาด ลองใช้บรรทัดคำสั่งหรือล่ามออนไลน์อื่น (ใช้งานได้กับRextesterเป็นต้น)
Anders Kaseorg

2
@codeshot ผู้เขียนคำถามได้ให้ความเห็นว่า ((λ f. (λ x. (fx)))) (λ y. (λ x. y))) ↦ (λ x. (λ z. x)) ถูกต้องสำหรับ ปัญหานี้ (เช่นเดียวกับแคลคูลัสแลมบ์ดาจริง)
Anders Kaseorg

13

Python - 321 320

นี่คือความพยายามของฉัน (แก้ไข):

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

สิ่งนี้ดูดี แต่ดูเหมือนจะไม่ทำงาน ฉันได้เพิ่มอินพุทและเอาท์พุทตัวอย่างซึ่งโค้ดของคุณให้ผลลัพธ์ที่ผิด
sepp2k

1
สิ่งนี้ล้มเหลวในการทำการทดแทนการหลีกเลี่ยงการจับภาพ ตัวอย่างเช่น ((\ f. (\ x. (fx))) (\ y. (\ x. y))) ประเมินผลไม่ถูกต้องเป็น (\ x. (\ x. x))
Anders Kaseorg

1
ทำไมสิ่งนี้จึงถูกทำเครื่องหมายเป็นคำตอบเมื่อมันแทบจะไม่ทำงาน? คุณได้ลองใช้อินพุตและเอาต์พุตที่ได้รับจากผู้เขียนหรือไม่?
rbaleksandar

1
กรณีทดสอบที่ผู้เขียนให้มาไม่เพียงพอที่จะแสดงข้อบกพร่องในคำตอบนี้
Anders Kaseorg

1
คำตอบนี้ไม่ถูกต้องหรือสั้นที่สุด มันไม่สามารถหลีกเลี่ยงการดักจับและมีข้อบกพร่องในการแทนที่สตริง
Richard Padley

6

ตัวอักษร Ruby 254

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}

มันสามารถใช้เช่น

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

วิธีการแก้ปัญหายังไม่ได้เล่นกอล์ฟอย่างเต็มที่ แต่เกือบจะอ่านไม่ได้แล้ว


สวัสดีอิจฉาเพื่อนเก่าของฉัน :)
luser droog

สิ่งนี้ล้มเหลวในการทำการทดแทนการหลีกเลี่ยงการจับภาพ ตัวอย่างเช่น ((\ f. (\ x. (fx))) (\ y. (\ x. y))) ประเมินผลไม่ถูกต้องเป็น (\ x. (\ x. x))
Anders Kaseorg

นอกเหนือจากข้อผิดพลาดในการดักจับข้างต้นค่านี้ยังประเมินอย่างไม่ถูกต้อง (\ y. (\ xx. ((\ x. xx) y)))) (\ y. (\ xx. yy)) ซึ่งการแทนที่สตริงที่ overzealous ได้ผลิตขึ้น ตัวแปรที่ไม่มีอยู่ yy
Anders Kaseorg

3

แก้ไข: ตรวจสอบคำตอบของฉันด้านล่างเพื่อ 250 ภายใต้ JavaScript บริสุทธิ์

2852 243 ตัวอักษรโดยใช้ LiveScript (ไม่มี Regex! ไม่ได้เล่นกอล์ฟอย่างเต็มที่ - สามารถปรับปรุงได้)

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

ทดสอบ:

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

ซึ่งก็คือ3^2=9ตามที่ระบุไว้ใน OP

หากใครอยากรู้อยากเห็นนี่เป็นเวอร์ชั่นเพิ่มเติมที่มีความคิดเห็นบางส่วน:

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

สิ่งนี้ไม่สอดคล้องกับข้อกำหนดคุณลักษณะอินพุตและเอาต์พุตจากปัญหา
Anders Kaseorg

3

Waterhouse Arc - 140 ตัวอักษร

(=
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 #\._])

ฉันจะรับ Waterhouse Arc ได้ที่ไหน
Anders Kaseorg

1
ไม่พบว่ามีล่ามไม่ถูกต้อง
cat


@ ASCII- เพียงฉันเท่านั้นที่รู้ว่าอาร์คคืออะไร แต่ส่วน“ วอเตอร์เฮาส์” แนะนำให้ฉันว่าบางภาษาจำเป็นต้องมี คุณได้รับมันให้ทำงาน?
Anders Kaseorg

@AndersKaseorg ไม่เป็นไร พบ
ASCII เท่านั้น

2

C 1,039 ไบต์

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

ตัวแปรอนุญาตให้เป็นอินพุตโดยใช้ตัวอักษรพิมพ์เล็ก [จาก a..z] sys สามารถสร้างตัวแปรโดยใช้ตัวอักษรตัวพิมพ์ใหญ่ [จาก A..Z] หากต้องการในเอาต์พุต ... สมมติว่าการกำหนดค่าอักขระ 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*/

ข้อมูลจำเพาะต้องการ \ หรือλไม่ใช่ / นอกจากนี้ยังต้องการการสนับสนุนชื่อตัวแปรหลายตัวอักษร
Anders Kaseorg

'\ n' สัญลักษณ์อื่น ๆ '\' มีการใช้งานแบบอื่นมันเป็นการใช้งานที่ดีกว่า '/' แทน
RosLuP

1
ถึงกระนั้นความท้าทายก็คือการตอบสนองสเปคไม่ให้ดีขึ้น
Anders Kaseorg

ฉันเขียนบางสิ่งบางอย่างไม่ว่าจะเป็นเพิ่มเติมเล็กน้อย ... แต่ขนาด explode ...
RosLuP


1

Haskell 456 C

มันจะสั้นกว่านี้มากหากใช้คุณสมบัติการประเมินผลที่ขี้เกียจของ Haskell อย่างเต็มที่ น่าเศร้าที่ฉันไม่รู้จะทำยังไง

นอกจากนี้อักขระจำนวนมากจะสูญเปล่าในขั้นตอนการแยกวิเคราะห์

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

เวอร์ชันที่ไม่ดี

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
สิ่งนี้ล้มเหลวในการทำการทดแทนการหลีกเลี่ยงการจับภาพ ตัวอย่างเช่น ((λ f. (λ x. (fx))) (λ y. (λ x. y))) ประเมินผลไม่ถูกต้องเป็น (λ x. (λ x. x))
Anders Kaseorg

1

มี 231 กับ JavaScript / ไม่มี 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})

รับอาร์เรย์ 2 องค์ประกอบ 1ย่อมาจากλและ 2 หมายถึงตัวแปรดัชนี bruijn

ทดสอบ:

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

สิ่งนี้ไม่สอดคล้องกับข้อกำหนดคุณลักษณะอินพุตและเอาต์พุตจากปัญหา
Anders Kaseorg

1

Python: 1266 ตัวอักษร (วัดโดยใช้ 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()))

ไม่ใช่ช็อตที่สั้นที่สุด แต่สามารถจัดการการเปลี่ยนชื่อได้อย่างถูกต้องและตัวอย่างทั้งหมดที่แสดงในโพสต์ OPs


คุณสามารถย่อชื่อฟังก์ชั่นเหล่านั้นให้สั้นลงและเปลี่ยนเป็นฟังก์ชั่น lambdas คุณยังมีช่องว่างเหลือเฟือที่นี่และที่นั่น
โจคิง

(1) การแทนที่การเว้นวรรค 4 ช่องว่างด้วยช่องว่างเดียวจะช่วยประหยัดได้ไม่กี่ไบต์ (2) คุณสามารถแทนที่except NameErrorด้วยเพียงexcept? (3) ชื่อฟังก์ชั่นสองตัวอักษรสามารถเปลี่ยนชื่อเป็นชื่อหนึ่งตัวอักษร (4) มีสถานที่บางที่คุณมีการมอบหมายงานที่มีช่องว่างรอบ ๆ =ที่มี (5) สามารถถูกแทนที่ด้วยif t[0]=='c' if'c'==t[0]
แยกผลไม้

1,045 ไบต์ผ่านการจัดรูปแบบการเปลี่ยนแปลงส่วนใหญ่เช่นการเยื้องและ lambdas
Jo King

0

c ++ (GCC) ,782 766 758 731 ไบต์

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

ลองออนไลน์!

แนวคิดพื้นฐานที่นี่คือรหัสใช้การเป็นตัวแทนภายในขึ้นอยู่กับความคิดของดัชนี de Bruijn - ยกเว้นว่าฉันย้อนกลับดัชนีเพื่อระบุความลึกแลมบ์ดาของการเชื่อมโยงของตัวแปรที่อ้างอิง ในรหัส:

  • E::tแทนชนิดของโหนด - 0 สำหรับโหนดลีฟแบบแปรผัน 1 สำหรับโหนดแลมบ์ดาและ 2 สำหรับโหนดแอปพลิเคชันฟังก์ชัน (เลือกเพื่อให้สอดคล้องกับ arity ของโหนดซึ่งเพิ่งเกิดขึ้นได้) จากนั้นE::lและE::rเป็นเด็กตามความเหมาะสม (เพียงE::lโหนดแลมบ์ดา) และE::iเป็นดัชนีแลมบ์ดาเชิงลึกสำหรับโหนดลีฟของตัวแปร
  • ตัวสร้างE::E(E&o,int d,int e)โคลน subexpression ซึ่งเป็นครั้งแรกที่แลมบ์ดาเชิงลึกสำหรับการวางลงในตำแหน่งใหม่ที่แลมบ์ดาเชิงลึกd d+eนี้เกี่ยวข้องกับการรักษาตัวแปรที่แลมบ์ดาเชิงลึกน้อยกว่าdในขณะที่การเพิ่มตัวแปรที่แลมบ์ดาเชิงลึกอย่างน้อยโดยde
  • E::sทำการทดแทน subexpression vเป็นจำนวนตัวแปรdใน*thisขณะที่ลดจำนวนตัวแปรมากกว่าd(และeเป็นรายละเอียดภายในการติดตามการเพิ่มความลึกแลมบ์ดาเมื่อจำเป็นต้องโทรE::c)
  • E::Rค้นหาการลดเบต้าเดี่ยวเพื่อดำเนินการเลือกอินสแตนซ์บนสุดหรือซ้ายสุดตามการค้นหาล่วงหน้าผ่าน AST มันจะส่งกลับไม่ใช่ศูนย์ถ้ามันพบว่าการลดลงในการดำเนินการหรือเป็นศูนย์ถ้ามันไม่พบ
  • E::uเป็นการto_stringดำเนินการชนิดซึ่งสร้างสตริง "human readable" ใหม่โดยใช้ชื่อสังเคราะห์สำหรับตัวแปร (หมายเหตุว่าเป็นเพราะการเล่นกอล์ฟของเล็ก ๆ น้อย ๆ ของVฟังก์ชั่นช่วยที่มันจะสร้างชื่อที่มีaผ่านi.)
  • คอนสตรัคเตอร์E::E(int d, std::map<std::string, int> m, char*&s)จะแยกวิเคราะห์ของสตริงการป้อนsลงในการแสดงออก AST ขึ้นอยู่กับการทำแผนที่mของชื่อตัวแปรที่ถูกผูกไว้ในปัจจุบันในดัชนีแลมบ์ดาลึก
  • f เป็นฟังก์ชั่นหลักในการตอบคำถาม

(อย่างที่คุณเห็นที่ลิงค์ TIO รหัสจะจัดการชื่อตัวแปรที่มีหลายตัวอักษรและยังได้รับคำตอบที่ถูกต้อง(\ a. (\ b. a))สำหรับ((\ f. (\ x. (f x))) (\ y. (\ x. y)))มันนอกจากนี้ยังเกิดขึ้นที่รหัสการแยกวิเคราะห์สามารถจัดการกับตัวแปรเงาโดยไม่มีค่าใช้จ่ายเพิ่มเติม)


-16 ไบต์บางส่วนเนื่องจากความคิดโดย catcat (ซึ่งฉันได้มาด้วยอย่างอิสระ) และบางส่วนเนื่องจากการเปลี่ยนE*a=new E;ไปE&a=*new E;แล้วเปลี่ยนa->เป็นa.

-8 ไบต์เพิ่มเติมเนื่องจากความคิดเห็นอื่นโดย ceilingcat (แยกตัวประกอบa.tจาก ternary)

-27 ไบต์จากการแปลง parser และโคลนเป็น constructors ของ E


-1

C 637 ไบต์

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

รุ่นนี้ไม่ใช้ตัวแปรเสริม (ดังนั้นจึงไม่เป็นไปตาม 100% สิ่งที่แลมบ์ดาแคลคูลัสพูดว่า ... เป็นอย่างอื่นที่นี่ ... ) ตัวแปรแต่ละตัวจะต้องมีความยาว 1 อักขระ (เหมือนกับที่นี่) รหัสทดสอบ:

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

ผล:

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

นี่คือสิ่งที่ไม่ดีนัก:

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

ข้อมูลจำเพาะต้องการ \ หรือλไม่ใช่ / นอกจากนี้ยังต้องการการสนับสนุนชื่อตัวแปรหลายตัวอักษร นอกจากนี้ (ฉันรู้ว่าคุณรู้เรื่องนี้ แต่ใช่มันยังคงผิด) การประเมินนี้ไม่ถูกต้อง ((/ f. (/ x. (fx))) (/ y. (/ x. y))) เพื่อ ( / x. (/ x. x))
Anders Kaseorg

ฉันเปลี่ยน / เป็น \ มีปัญหาไม่อนุญาตให้ใช้ตัวแปรหลายตัวอักษร ถ้าทดสอบวิธีอื่นก็มีไว้สำหรับโซลูชันอื่นด้วย
RosLuP
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.