Viết một trình thông dịch cho phép tính lambda chưa được đánh dấu


45

Thách thức là viết một trình thông dịch cho phép tính lambda chưa được gõ trong càng ít ký tự càng tốt. Chúng tôi xác định phép tính lambda chưa được xử lý như sau:

Cú pháp

Có ba loại biểu thức sau:

  • Một biểu thức lambda có dạng (λ x. e)nơi xcó thể là bất kỳ tên biến pháp luật và ebất kỳ biểu hiện quy phạm pháp luật. Ở đây xđược gọi là tham số và eđược gọi là thân hàm.

    Để đơn giản, chúng tôi thêm một hạn chế nữa là không được có một biến có cùng tên như xhiện tại trong phạm vi. Một biến bắt đầu được trong phạm vi khi tên của nó xuất hiện ở giữa .và dừng lại được trong phạm vi ở tương ứng ).

  • Ứng dụng chức năng có dạng (f a)nơi falà biểu pháp lý. Ở đây fđược gọi là hàm và ađược gọi là đối số.
  • Một biến có dạng xtrong đó xlà một tên biến hợp pháp.

Ngữ nghĩa

Một hàm được áp dụng bằng cách thay thế từng lần xuất hiện của tham số trong thân hàm bằng đối số của nó. Chính thức hơn một biểu hiện của hình thức ((λ x. e) a), nơi xlà một tên biến và ealà những biểu hiện, đánh giá lại (hoặc giảm) để biểu thức e'e'là kết quả của việc thay thế từng xảy ra xtrong evới a.

Một hình thức bình thường là một biểu thức không thể được đánh giá thêm.

Các thách thức

Nhiệm vụ của bạn, nếu bạn chọn chấp nhận nó, là viết một trình thông dịch lấy đầu vào là biểu thức của phép tính lambda chưa được xử lý không chứa biến tự do và tạo ra dạng đầu ra của biểu thức (hoặc biểu thức alpha đồng dạng với biểu thức) . Nếu biểu thức không có dạng bình thường hoặc nó không phải là biểu thức hợp lệ, hành vi không được xác định.

Giải pháp với số lượng ký tự nhỏ nhất sẽ thắng.

Một vài lưu ý:

  • Đầu vào có thể được đọc từ stdin hoặc từ tên tệp được cung cấp dưới dạng đối số dòng lệnh (bạn chỉ cần thực hiện cái này hoặc cái kia - không phải cả hai). Đầu ra đi đến thiết bị xuất chuẩn.
  • Ngoài ra, bạn có thể định nghĩa một hàm lấy đầu vào là một chuỗi và trả về đầu ra dưới dạng một chuỗi.
  • Nếu các ký tự không phải ASCII có vấn đề với bạn, bạn có thể sử dụng \ký tự dấu gạch chéo ngược ( ) thay vì.
  • Chúng tôi đếm số lượng ký tự, không phải byte, vì vậy ngay cả khi tệp nguồn của bạn được mã hóa dưới dạng unicode λ tính là một ký tự.
  • Tên biến hợp pháp bao gồm một hoặc nhiều chữ cái viết thường, tức là các ký tự giữa a và z (không cần hỗ trợ tên chữ và số, chữ in hoa hoặc chữ cái không phải là chữ Latinh - tất nhiên, mặc dù vậy sẽ không làm mất hiệu lực giải pháp của bạn).
  • Theo như thách thức này, không có dấu ngoặc đơn là tùy chọn. Mỗi biểu thức lambda và mỗi ứng dụng chức năng sẽ được bao quanh bởi chính xác một cặp dấu ngoặc đơn. Không có tên biến sẽ được bao quanh bởi dấu ngoặc đơn.
  • Đường cú pháp như viết (λ x y. e)cho (λ x. (λ y. e))không cần phải được hỗ trợ.
  • Nếu độ sâu đệ quy hơn 100 được yêu cầu để đánh giá một hàm, hành vi không được xác định. Điều đó phải đủ thấp hơn đủ để được thực hiện mà không cần tối ưu hóa trong tất cả các ngôn ngữ và vẫn đủ lớn để có thể thực hiện hầu hết các biểu thức.
  • Bạn cũng có thể giả định rằng khoảng cách sẽ như trong các ví dụ, nghĩa là không có khoảng trắng ở đầu và cuối của đầu vào hoặc trước một λhoặc .chính xác một khoảng trắng sau một .và giữa một hàm và đối số của nó và sau a λ.

Đầu vào và đầu ra mẫu

  • Đầu vào: ((λ x. x) (λ y. (λ z. z)))

    Đầu ra: (λ y. (λ z. z))

  • Đầu vào: (λ x. ((λ y. y) x))

    Đầu ra: (λ x. x)

  • Đầu vào: ((λ x. (λ y. x)) (λ a. a))

    Đầu ra: (λ y. (λ a. a))

  • Đầu vào: (((λ x. (λ y. x)) (λ a. a)) (λ b. b))

    Đầu ra: (λ a. a)

  • Đầu vào: ((λ x. (λ y. y)) (λ a. a))

    Đầu ra: (λ y. y)

  • Đầu vào: (((λ x. (λ y. y)) (λ a. a)) (λ b. b))

    Đầu ra: (λ b. b)

  • Đầu vào: ((λx. (x x)) (λx. (x x)))

    Đầu ra: bất cứ điều gì (Đây là một ví dụ về biểu thức không có dạng bình thường)

  • Đầu vào: (((λ x. (λ y. x)) (λ a. a)) ((λx. (x x)) (λx. (x x))))

    Đầu ra: (λ a. a)(Đây là một ví dụ về biểu thức không bình thường hóa nếu bạn đánh giá các đối số trước lệnh gọi hàm và đáng buồn là một ví dụ về giải pháp đã thử của tôi không thành công)

  • Đầu vào: ((λ a. (λ b. (a (a (a b))))) (λ c. (λ d. (c (c d)))))

    Đầu ra: `(λ a. (λ b. (a (a (a (a (a (a (a (a b)))))))))) Điều này tính 2 ^ 3 bằng chữ số Church.


1
Chúng ta có thể giả sử rằng sẽ không có khoảng trắng được thêm vào hoặc nối thêm vào chuỗi và khoảng trắng đó được quy định khác trong đầu vào mẫu không? Nghĩa là, không có khoảng trắng giữa các dấu ngoặc, giữa dấu chấm và tên tham số và các trường hợp khác của khoảng trắng là chính xác 1 khoảng trắng.
JPvdMerwe

@JPvdMerwe: Vâng, điểm tốt, bạn có thể cho rằng.
sepp2k

Có bất kỳ biến miễn phí? Tôi có nghĩa là các biến không bị ràng buộc bởi một lambda như trong biểu thức (\y. a).
FUZxxl

3
Nhiều hoặc tất cả các giải pháp ở đây không thực hiện thay thế tránh chụp! Bạn nên thêm một trường hợp thử nghiệm như ((λ f. (Λ x. (Fx))) (y. (Λ x. Y))), sẽ đánh giá thành (λ x. (Λ z. X)), không (λ x. (λ x. x)).
Anders Kaseorg

1
@ sepp2k Bạn đã xem xét thêm ((λ f. (λ x. (fx))) (λ y. (λ x. y))) như một trường hợp thử nghiệm và không chấp nhận câu trả lời hiện tại tạo ra không chính xác (λ x. ( x. x))?
Anders Kaseorg

Câu trả lời:


36

Mới nhất:

Tôi đã vắt nó xuống còn 644 ký tự , tôi đã ghép các phần của cEll vào cOpy và Par; các cuộc gọi được lưu vào bộ nhớ cache đến ô và cdr thành các biến cục bộ tạm thời và di chuyển các biến cục bộ đó sang các khối trong các hàm "terminal" (nghĩa là không đệ quy). Ngoài ra, hằng số thập phân ngắn hơn chữ nhân vật và công việc khó chịu này ...

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

... xác định chính xác các chữ cái viết thường (giả sử ASCII), nhưng cũng chấp nhận bất kỳ `{|} ~. (Quan sát tương tự về ASCII được thực hiện trong video xuất sắc này về 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;}

Sớm hơn:

Tôi có thể nhận được một vài phiếu cho nỗ lực không? Tôi đã làm việc vào ngày và đêm này trong một tuần. Tôi đã đào tờ giấy McCarthy ban đầu và bị dính một lỗi trong chính tờ giấy cho đến khi tôi đọc phần phụ lục của cuốn The Roots of Lisp của Paul Graham . Tôi đã bị phân tâm đến mức tự nhốt mình ra khỏi nhà, sau đó hoàn toàn quên mất cho đến khi trở về nhà vào tối hôm đó lúc 12:30 (hơi muộn để gọi cho người quản lý tòa nhà sống ở quận) và phải chi tiêu đêm ở nhà bà tôi (hack cho đến khi pin máy tính xách tay của tôi khô).

Và sau tất cả, nó thậm chí không gần với mục chiến thắng!

Tôi không chắc làm thế nào để làm cho điều này ngắn hơn; và tôi đã sử dụng tất cả các mánh khóe bẩn thỉu tôi có thể nghĩ ra! Có lẽ nó không thể được thực hiện trong C.

Với sự hào phóng trong việc đếm (đoạn đầu tiên lấy một chuỗi và in ra kết quả), đó là 778 770 709 694 ký tự. Nhưng để làm cho nó độc lập, nó phải có sbrkcuộc gọi đó . Và để xử lý các biểu thức phức tạp hơn, nó cũng cần signalxử lý. Và tất nhiên nó không thể được tạo thành một mô-đun với bất kỳ mã nào cố gắng sử dụng malloc.

Vì vậy, than ôi, đây là:

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

Đây là khối ngay trước khi giảm cuối cùng. Các thủ thuật ở đây là các con trỏ nguyên thay vì con trỏ (lợi dụng hành vi 'ẩn int') và sử dụng 'bộ nhớ đầu': char*nlà con trỏ 'mới' hoặc 'tiếp theo' vào không gian trống. Nhưng đôi khi tôi viết một chuỗi vào bộ nhớ, sau đó gọi strlen và tăng n; sử dụng hiệu quả bộ nhớ và sau đó phân bổ nó, sau khi kích thước dễ tính toán hơn. Bạn có thể thấy nó khá trực tiếp từ bài báo McCarthy, ngoại trừ cell()giao diện giữa các chức năng và biểu diễn chuỗi dữ liệu.

#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
Tôi tìm thấy một vài thủ thuật nữa để cứu một hoặc hai nhân vật, nhưng không có gì triệt để. sprintf(n,...);n+=strlen(n)+1;sẽ tốt hơn khi n+=sprintf(n,...)+1;Đảo ngược cú pháp mảng x[m]thay vì m[x]cho phép tôi thay thế tất cả các phần tử bằng macro 'postfix' #define M [m]... x Mgiúp lưu 1 char và ngắt dòng "miễn phí" vì khoảng trắng là cần thiết để tách các mã thông báo.
luser droog

Dường như có một số điểm tương đồng với điều này và jar.2 xlisp 4.0 từ IOCCC 1989 .
luser droog

Tôi đã cố gắng mở rộng nó thành một trình thông dịch Lisp đầy đủ hơn .
kẻ lừa đảo người lái xe

Mã nhận xét // um ...đang lặp qua chuỗi và đếm dấu ngoặc đơn cho đến khi tìm thấy kết quả gần đúng ở mức lồng nhau chính xác.
luser droog 19/215

1
Điều này đánh giá không chính xác ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) thành (\ x. (Fx)).
Anders Kaseorg

22

Nhị phân Lambda tính 186

Chương trình hiển thị trong kết xuất hex bên dưới

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

không chấp nhận hoàn toàn định dạng bạn đề xuất. Thay vào đó, nó mong đợi một thuật ngữ lambda ở định dạng lambda nhị phân (blc). Tuy nhiên, nó hiển thị từng bước trong việc giảm biểu mẫu thông thường, sử dụng dấu ngoặc đơn tối thiểu.

Ví dụ: tính 2 ^ 3 bằng chữ số Church

Lưu kết xuất hex ở trên với xxd -r> tượng trưng.Blc

Lấy thông dịch viên blc từ 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)))))))

Vì hexdump khá khó đọc, nên đây là phiên bản "tháo rời"

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

thay thế 00 (lambda) bằng \ và 01 (ứng dụng) bằng @ Bây giờ, nó gần như dễ đọc như brainfuck :-)

Đồng thời xem http://www.ioccc.org/2012/tromp/hint.html


7
BLC chỉ xảy ra để sử dụng một bảng chữ cái nhị phân. 00 là lambda, 01 là ứng dụng và 1 ^ {n} 0 là một biến trong unary. Không có phần tổng hợp liên quan.
John Tromp

3
Nơi nào bạn nhận được một yếu tố x3? Bạn thực sự nêu lên một điểm tốt trong các ngôn ngữ có bảng chữ cái nguồn nhỏ hơn như BF bị phạt. Để so sánh công bằng, tất cả các kích thước nên được thể hiện bằng bit và mỗi ký tự BF chỉ mất 3 bit. Hầu hết các ngôn ngữ khác cần 7 bit cho ASCII, một số sử dụng tất cả 8.
John Tromp

1
BTW +1 Điều này thật tuyệt!
luser droog

1
Nếu fractran trong fractran là chấp nhận được, tôi không hiểu tại sao điều này lại là một vấn đề. Bạn không thể đọc nó? Bạn muốn? Học hỏi!
luser droog

1
Điều gì sẽ làm cho nó đọc định dạng đầu vào thực tế? Tôi nghĩ đó là nơi bạn đang mất đi những tiềm năng.
kẻ lừa đảo kẻ lừa đảo

14

Haskell, 342 323 317 305 ký tự

Theo văn bản này, đây là giải pháp duy nhất đánh giá ((λ f. (Λ x. (Fx))) (λ y. (X. Y))) cho kết quả chính xác (λ x. (Λ z. x)) chứ không phải (λ x. (x. x)). Việc thực hiện đúng phép tính lambda đòi hỏi phải thay thế tránh bắt , ngay cả trong vấn đề đơn giản hóa này đảm bảo rằng không có biến nào làm mờ một biến khác trong phạm vi của nó. (Chương trình của tôi xảy ra để làm việc ngay cả khi không có sự đảm bảo này.)

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

Ghi chú:

  • Điều này chạy trong GHC 7.0, theo yêu cầu vì thử thách này đã được đặt vào tháng 1 năm 2011. Nó sẽ ngắn hơn 13 ký tự nếu tôi được phép sử dụng GHC 7.10.

Phiên bản Ungolfed với tài liệu.


prog của bạn trong trình biên dịch ideone haskell cho đầu vào ((\ x. x) (\ y. (\ z. z))) trả về "lỗi thời gian chạy" ngay cả trong ((\ x. x) (\\ y. ( \\ z. z))) ... "lex" trong Haskell nghĩa là gì?
RosLuP

2
@RosLuP Chương trình của tôi chấp nhận λ, không phải \.
Anders Kaseorg

nhập thông số này ((λ x. x) (λ y. (z. z))) trong ideone.com return: Thời gian lỗi thời gian chạy: 0 bộ nhớ: 4876 tín hiệu: -1
RosLuP

1
@RosLuP Ideone dường như đã phá vỡ hỗ trợ Unicode. Hãy thử dòng lệnh hoặc một trình thông dịch trực tuyến khác ( ví dụ: nó hoạt động trên Rextester ).
Anders Kaseorg

2
@codeshot Tác giả câu hỏi đã nhận xét rằng ((λ f. (λ x. (fx))) (λ y. (x. y))) ↦ (x. (λ z. x)) là đúng cho vấn đề này (giống như phép tính lambda thật).
Anders Kaseorg

13

Con trăn - 321 320

Đây là nỗ lực (cố định) của tôi:

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

Điều này có vẻ tốt, nhưng dường như không hoạt động. Tôi đã thêm một số ví dụ đầu vào và đầu ra, mà mã của bạn tạo ra kết quả sai.
sepp2k

1
Điều này không thực hiện thay thế tránh chụp. Ví dụ: ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) đánh giá không chính xác thành (\ x. (\ X. X)).
Anders Kaseorg

1
Tại sao điều này được đánh dấu là một câu trả lời khi nó hầu như không hoạt động? Bạn đã thử các đầu vào và đầu ra nhất định của tác giả?
rbaleksandar

1
Các trường hợp kiểm tra do tác giả cung cấp là không đủ để chứng minh các lỗi trong câu trả lời này.
Anders Kaseorg

1
Câu trả lời này không đúng cũng không ngắn nhất. Nó không tránh được việc chụp và có lỗi thay thế chuỗi.
Richard Padley

6

Ruby 254 ký tự

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}

Nó có thể được sử dụng như

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

Giải pháp chưa được đánh gôn hoàn toàn nhưng gần như không thể đọc được.


xin chào ghen tị, người bạn cũ của tôi :)
luser droog

Điều này không thực hiện thay thế tránh chụp. Ví dụ: ((\ f. (\ X. (Fx))) (\ y. (\ X. Y))) đánh giá không chính xác thành (\ x. (\ X. X)).
Anders Kaseorg

Ngoài lỗi chụp ở trên, điều này cũng đánh giá không chính xác (\ y. (\ Xx. ((\ X. Xx) y))) thành (\ y. (\ Xx. Yy)), trong đó việc thay thế chuỗi quá mức đã được tạo ra biến không tồn tại yy.
Anders Kaseorg

3

Chỉnh sửa: kiểm tra câu trả lời của tôi dưới đây cho 250 dưới JavaScript thuần túy.

2852 243 ký tự sử dụng LiveScript (Không có Regex! Không được đánh gôn hoàn toàn - có thể được cải thiện)

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

Kiểm tra:

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

Đó là 3^2=9, như đã nêu trên OP.

Nếu bất cứ ai tò mò, đây là một phiên bản mở rộng với một số ý kiến:

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

Điều này không phù hợp với các thông số kỹ thuật đầu vào và đầu ra từ vấn đề.
Anders Kaseorg

3

Waterhouse Arc - 140 ký tự

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

Tôi có thể lấy Waterhouse Arc ở đâu?
Anders Kaseorg

1
Không có giá trị như một thông dịch viên không được tìm thấy
mèo

@AndersKaseorg tại đây
ASCII chỉ có

@ ASCII-chỉ tôi mới biết Arc là gì, nhưng phần của Water Water Tiết đã gợi ý cho tôi rằng một số phương ngữ cụ thể là cần thiết. Bạn đã nhận được nó để chạy?
Anders Kaseorg

@AndersKaseorg Đừng bận tâm. Đã tìm thấy nó
ASCII - chỉ

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

Các biến cho phép làm đầu vào bằng các chữ cái viết thường [từ a..z] các sys có thể tạo các biến bằng chữ in hoa [từ A..Z] nếu cần trong đầu ra ... Giả sử cấu hình ký tự 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*/

Đặc tả yêu cầu \ hoặc λ, không /. Nó cũng yêu cầu hỗ trợ cho các tên biến nhiều chữ cái.
Anders Kaseorg

Biểu tượng '\ n' vv '\' có những cách sử dụng khác, thay vào đó là sử dụng tốt hơn '/'
RosLuP

1
Tuy nhiên, thách thức là để đáp ứng các đặc điểm kỹ thuật, không làm cho nó tốt hơn.
Anders Kaseorg

tôi đã viết một cái gì đó cho phù hợp hơn một chút ... nhưng kích thước bùng nổ ...
RosLuP


1

Haskell 456 C

Nó có thể ngắn hơn nhiều nếu tính năng đánh giá lười biếng của Haskell được sử dụng đầy đủ. Đáng buồn thay, tôi không biết làm thế nào để làm điều đó.

Ngoài ra, nhiều ký tự bị lãng phí trong bước phân tích cú pháp.

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

Phiên bản ung dung

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
Điều này không thực hiện thay thế tránh chụp. Ví dụ: ((λ f. (Λ x. (Fx))) (y. (Λ x. Y))) đánh giá không chính xác thành (λ x. (Λ x. X)).
Anders Kaseorg

1

Có 231 với JavaScript / không có 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})

Nhận mảng 2 yếu tố. 1là viết tắt của λvà 2 là viết tắt của một biến chỉ số bruijn.

Kiểm tra:

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

Điều này không phù hợp với các thông số kỹ thuật đầu vào và đầu ra từ vấn đề.
Anders Kaseorg

1

Python: 1266 ký tự (được đo bằng 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()))

Không phải là ngắn nhất bởi một cú sút xa, nhưng nó xử lý chính xác việc đổi tên alpha và tất cả các ví dụ được liệt kê trong bài OP.


Bạn có thể rút ngắn một số tên hàm đó và biến một số trong số chúng thành lambdas. Bạn cũng có một số khoảng trắng dư thừa ở đây và đó
Jo King

(1) Thay thế thụt lề 4 không gian bằng một khoảng trắng sẽ tiết kiệm được một vài byte. (2) Bạn có thể thay thế except NameErrorchỉ except? (3) Tên hàm hai ký tự có thể được đổi tên thành tên một ký tự. (4) Có một vài nơi bạn có các bài tập có khoảng trống xung quanh =. (5) if t[0]=='c'có thể được thay thế bằng if'c'==t[0].
Esolanging Fruit

1045 byte thông qua hầu hết các thay đổi định dạng như thụt lề và 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);}

Hãy thử trực tuyến!

Ý tưởng cơ bản ở đây là mã sử dụng biểu diễn bên trong dựa trên ý tưởng của các chỉ số de Bruijn - ngoại trừ việc tôi đảo ngược các chỉ số để chỉ ra độ sâu lambda của ràng buộc của biến được đề cập. Trong mã:

  • E::tđại diện cho loại nút - 0 cho nút lá biến, 1 cho nút lambda và 2 cho nút ứng dụng chức năng. (Được chọn sao cho trùng khớp với độ chụm của nút, điều này hoàn toàn có thể xảy ra.) Sau đó E::lE::rlà những đứa trẻ thích hợp (chỉ E::lvới một nút lambda), và E::ilà chỉ số độ sâu lambda cho một nút lá thay đổi.
  • Các nhà xây dựng E::E(E&o,int d,int e)nhân bản một biểu hiện phụ ban đầu ở độ sâu lambda dđể dán vào một vị trí mới ở độ sâu lambda d+e. Điều này liên quan đến việc bảo toàn các biến ở độ sâu lambda ít hơn dtrong khi tăng các biến ở độ sâu lambda ít nhất là dbằng e.
  • E::sthực hiện thay thế biểu thức con vthành số biến dtrong *thiskhi giảm số biến lớn hơn d(và elà một chi tiết bên trong theo dõi mức tăng độ sâu lambda khi cần gọi E::c).
  • E::Rtìm kiếm một lần giảm beta duy nhất để thực hiện, ưu tiên các trường hợp hàng đầu hoặc hầu hết bên trái theo tìm kiếm đặt hàng trước thông qua AST. Nó trả về giá trị khác nếu nó tìm thấy mức giảm để thực hiện hoặc bằng 0 nếu không tìm thấy.
  • E::ulà một to_stringloại hoạt động phục hồi chuỗi "con người có thể đọc được" bằng cách sử dụng tên tổng hợp cho các biến. (Lưu ý rằng do một chút Vchức năng của trình trợ giúp, nó sẽ chỉ tạo ra các tên có chứa athông qua i.)
  • Hàm tạo E::E(int d, std::map<std::string, int> m, char*&s)thực hiện phân tích chuỗi đầu svào thành biểu thức AST dựa trên ánh xạ mcác tên biến hiện bị ràng buộc vào các chỉ số độ sâu lambda.
  • f là chức năng chính trả lời câu hỏi.

(Như bạn có thể thấy tại liên kết TIO, mã lệnh thực hiện tên biến xử lý với nhiều nhân vật, và nó cũng nhận được một câu trả lời đúng của (\ a. (\ b. a))cho ((\ f. (\ x. (f x))) (\ y. (\ x. y))). Nó cũng chỉ cần như vậy xảy ra rằng mã phân tích cú pháp có thể xử lý shadowing biến không phải trả thêm chi phí.)


-16 byte một phần do ý tưởng của ceilingcat (mà tôi cũng đã đưa ra một cách độc lập), và một phần do thay đổi E*a=new E;để E&a=*new E;rồi thay đổi a->đểa.

-8 nhiều byte hơn do một bình luận khác của Barecat (yếu tố chuyển nhượng a.ttừ ternary)

-27 byte từ chuyển đổi trình phân tích cú pháp và sao chép vào các hàm tạo của 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;}

Phiên bản này không sử dụng các biến phụ trợ (vì vậy phiên bản này không tuân theo 100% những gì tính toán lambda nói ... như nhiều thứ khác ở đây ...). Mỗi biến phải dài 1 chararcter (như một số khác ở đây). Mã kiểm tra:

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

các kết quả:

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

đây là một người bán ung:

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

Đặc tả yêu cầu \ hoặc λ, không /. Nó cũng yêu cầu hỗ trợ cho các tên biến nhiều chữ cái. Ngoài ra (tôi biết bạn biết điều này, nhưng vâng, nó vẫn sai), điều này đánh giá không chính xác ((/ f. (/ X. (Fx))) (/ y. (/ X. Y))) thành ( / tình dục)).
Anders Kaseorg

Tôi thay đổi / thành \ có vấn đề không cho phép biến nhiều ký tự. nếu kiểm tra một số thứ khác thì đây cũng là giải pháp khác
RosLuP
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.