Напишіть перекладача для нетипового обчислення лямбда


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в eна a.

Нормальна форма - це вираз, який далі неможливо оцінити.

Змагання

Якщо ви вирішите прийняти це, ваша місія полягає в тому, щоб написати інтерпретатора, який приймає за свій вклад вираз нетипізованого обчислення лямбда, що не містить вільних змінних, і створює як його вихід нормальну форму вираження (або вираз альфа-відповідний йому) . Якщо вираз не має нормальної форми або не є дійсним виразом, поведінка не визначена.

Виграє рішення з найменшою кількістю символів.

Пара приміток:

  • Вхід може бути прочитаний зі stdin або з імені файлу, заданого як аргумент командного рядка (вам потрібно реалізувати лише те чи інше - не те й інше). Вихід йде на stdout.
  • Крім того, ви можете визначити функцію, яка приймає вхід як рядок і повертає результат як рядок.
  • Якщо символи, що не належать до ASCII, є для вас проблематичними, ви можете використовувати \символ зворотної косої ( ) замість λ.
  • Ми підраховуємо кількість символів, а не байти, тому навіть якщо ваш вихідний файл кодується як unicode λ, вважається одним символом.
  • Юридичні назви змінних складаються з однієї або декількох малих літер, тобто символів між a і z (не потрібно підтримувати буквено-цифрові імена, великі літери або не латинські літери - хоча це, звичайно, не може визнати недійсним ваше рішення).
  • Що стосується цього завдання, жодні дужки не є обов'язковими. Кожен вираз лямбда та кожен додаток функції буде оточений рівно однією парою дужок. Жодне ім'я змінної не буде оточене дужками.
  • Синтаксичний цукор, як писати (λ x y. e)для (λ x. (λ y. e)), не потрібно підтримувати.
  • Якщо для оцінки функції потрібна глибина рекурсії більше 100, поведінка не визначена. Це повинно бути більш ніж низьким, щоб його можна було здійснити без оптимізації на всіх мовах і все ще достатньо великим, щоб можна було виконувати більшість виразів.
  • Ви також можете припустити, що інтервал буде таким, як у прикладах, тобто немає пробілів на початку та в кінці вводу або перед a λабо .та саме одним пробілом після a .та між функцією та її аргументом та після a λ.

Зразок введення та виведення

  • Вхід: ((λ 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)).
Андерс Касеорг

1
@ sepp2k Чи розглядали ви додавання ((λ f. (λ x. (fx)))) (λ y. (λ x. y))) як тестовий випадок та неприйняття поточної відповіді, яка неправильно видає (λ x. (λ х. х))?
Anders Kaseorg

Відповіді:


36

Найновіші:

Я стиснув його до 644 знаків , я створив частини cEll на cOpy та Par; кешували виклики до комірок та cdr у тимчасові локальні змінні та переміщували ці локальні змінні до глобальних у "термінальних" (тобто нерекурсивних) функціях. Крім того, десяткові константи коротші, ніж букви символів, і ця неприємна справа ...

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

... правильно ідентифікує малі літери (припускаючи ASCII), але також приймає будь-яку з {{}} ~. (Це ж спостереження про ASCII зроблено у цьому чудовому відео про 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;}

Раніше:

Чи можу я отримати кілька голосів за зусилля? Я працюю в цей день і вночі протягом тижня. Я розкопав оригінальний папір Маккарті і мене мучив клоп у самому папері, поки я не прочитав додаток до Пола Грема «Коріння Ліса» . Мене так відволікало, що я замкнув себе з дому, а потім зовсім забув, поки не приїхав додому в ту ніч о 12:30 (трохи пізно зателефонував керівнику будівлі, який живе в районі), і мені довелося провести ніч у моєї бабусі (злому, поки акумулятор мого ноутбука не висох.)

І зрештою, це навіть не близько до виграшного вступу!

Я не впевнений, як зробити це коротшим; і я використав усі брудні хитрощі, про які я можу придумати! Можливо, це неможливо зробити в C.

Маючи велику щедрість у підрахунку (перший шматок бере рядок і друкує результат), це 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;
}

Ось блок перед остаточними скороченнями. Тут прийоми - це цілі курсори замість покажчиків (скориставшись поведінкою "неявного int") та використання "пам'яті подряпин": char*nвказівник "новий" або "наступний" у вільний простір. Але іноді я записую рядок у пам'ять, тоді називаю strlen та збільшення n; ефективно використовувати пам'ять, а потім розподілити її, після того, як розмір буде легше обчислити. Ви можете бачити, що це майже прямо з документа Маккарті, за винятком 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;Інвертування синтаксису масиву 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 (додаток) на @ Тепер це майже так само читабельно, як мозковий ебать :-)

Також див. Http://www.ioccc.org/2012/tromp/hint.html


7
BLC просто трапляється використовувати двійковий алфавіт. 00 - лямбда, 01 - додаток, а 1 ^ {n} 0 - змінна унар. Компіляція не бере участь.
Джон Тромп

3
Звідки у вас коефіцієнт x3? Ви насправді піднімаєте гарну крапку в тому, що мови з меншими алфавітами-джерелами, такими як BF, штрафуються. Для справедливого порівняння всі розміри повинні бути виражені у бітах, а символи BF мають лише 3 біти. Більшість інших мов потребують 7 біт для ASCII, а деякі використовують усі 8.
Джон Тромп

1
До речі +1 Це чортово круто!
luser droog

1
Якщо фрактран у фрактрані прийнятний, я не бачу, чому це взагалі має бути проблемою. Ви не можете його прочитати? Ти хочеш? Вчіться!
luser droog

1
Що потрібно, щоб він прочитав фактичний формат введення? Я думаю, що саме тут ви втрачаєте потенційні результати.
luser droog

14

Haskell, 342 323 317 305 символів

Станом на це написання, це єдине рішення, яке оцінює ((λ f. (Λ x. (Fx)))) (λ y. (Λ x. Y))) правильний результат (λ x. (Λ z. х)), а не (λ 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.

Безгольова версія з документацією.


ваша прога в компіляторі ideone haskell на вхід ((\ x. x) (\ y. (\ z. z))) повертає "помилку часу запуску" навіть у ((\\ x. x) (\\ y. ( \\ z. z))) ... що це означає "lex" у Haskell?
RosLuP

2
@RosLuP Моя програма приймає λ, а не \.
Андерс 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)) є правильним для ця проблема (подібно до справжнього обчислення лямбда).
Андерс Касеорг

13

Пітон - 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)).
Андерс Касеорг

1
Чому це позначається як відповідь, коли він ледве працює? Ви спробували подані автором дані та входи?
rbaleksandar

1
Наданих автором тестових випадків недостатньо для демонстрації помилок у цій відповіді.
Anders Kaseorg

1
Ця відповідь не є ні правильною, ні найкоротшою. Він не може уникнути захоплення та має помилки підстановки рядків.
Річард Падлі

6

Рубін 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)).
Андерс Касеорг

На додаток до вищезгаданої помилки захоплення, це також неправильно оцінює (\ y. (\ Xx. ((\ X. Xx) y))) до (\ y. (\ Xx. Yy)), де виробляється надмірна заміна рядків неіснуюча змінна 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, як зазначено в ОП.

Якщо хтось цікавий, ось розширена версія з деякими коментарями:

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

Це не відповідає специфікаціям вводу та виводу з проблеми.
Андерс Касеорг

3

Дуга у воді - 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 #\._])

Де я можу взяти дугу у воді?
Anders Kaseorg

1
Недійсний як перекладач ніде не знайдено
кіт

@AndersKaseorg тут
лише ASCII

@ ASCII - тільки я знаю, що таке дуга, але частина «Waterhouse» підказала мені, що потрібен якийсь конкретний діалект. Ви змусили його бігати?
Anders Kaseorg

@AndersKaseorg Неважливо. Знайшли його
лише ASCII

2

C 1039 байт

#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], система може генерувати змінні, використовуючи великі літери [від 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
Але все ж таки завдання - задовольнити специфікацію, а не зробити її кращою.
Андерс Касеорг

я написав щось для того, щоб було трохи більше відповідати ... але розмір вибухне ...
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()))

Не найкоротший з дальнього пострілу, але він правильно обробляє альфа-перейменування та всі приклади, перелічені в ОП.


Ви можете скоротити деякі з цих функцій і перетворити деякі з них на лямбда. У вас також є дещо надмірно пробіли
Джо Кінг,

(1) Заміна 4-пробільного відступу одним пробілом заощадить досить багато байтів. (2) Чи можете ви замінити except NameErrorна справедливі except? (3) Двосимвольні імена функцій можуть бути перейменовані в одноіменні імена. (4) Є кілька місць, де у вас є завдання, які мають пробіли навколо =. (5) if t[0]=='c'можна замінити на if'c'==t[0].
Esolanging Fruit

1045 байт через зміни в основному форматування, такі як відступ та лямбда
Джо Кінг,

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 для вузла додатка функції. (Вибирається таким чином, щоб він збігався з аритом вузла, який, можливо, є можливим.) Тоді E::lі E::rє дітьми, як годиться (лише E::lдля лямбда-вузла), і E::iє показником глибини лямбда для змінного вузла листка.
  • Конструктор E::E(E&o,int d,int e)клонує підвираз, який був спочатку на глибині лямбда, dщоб вставити його в нове місце на глибині лямбда d+e. Це включає збереження змінних на лямбда-глибині менше, ніж dпри збільшенні змінних на лямбда-глибині принаймні dна e.
  • E::sробить заміну підвыражения vна змінну кількість dна *thisчас зменшення числа змінних, що перевищує deє внутрішньою деталлю, що відстежує приріст глибини лямбда, коли потрібно викликати E::c).
  • E::Rздійснює пошук одного бета-скорочення для виконання, віддаючи перевагу екземплярам верхнього або лівого числа відповідно до попереднього замовлення через AST. Він повертає ненульовий, якщо знайшов зменшення для виконання або нуль, якщо не знайшов жодного.
  • E::u- це to_stringоперація типу, яка відновлює "читабельну людиною" рядок, використовуючи синтетичні імена для змінних. (Зверніть увагу , що з - за невеликої грою в гольф на 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 байт , частково з - за ідеї ceilingcat (який я також придумали незалежно один від одного), і частково за рахунок зміни E*a=new E;до , E&a=*new E;а потім змінити a->доa.

-8 більше байтів завдяки черговому коментарю, який надає roofcat (присвоєння фактора a.tвід тернарного)

-27 байт від перетворення парсера та клонування в конструктори 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))) до ( / х. (/ х. х)).
Anders Kaseorg

Я змінюю / на \ є проблема не дозволити зміну кількох символів. якщо тестувати якийсь інший, це теж для іншого рішення
RosLuP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.