Генератор обчислення лямбда


10

Я не знаю, де б ще задати це питання, сподіваюся, це хороше місце.

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

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

Звичайно, я майже нічого не знаю про обчислення лямбда, тому я не маю уявлення, чи дійсно це можливо.

Є це? Якщо так, чи це досить просто, як я це передбачав, чи це технічно можливо, але настільки складно, що це фактично неможливо?

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

Відповіді:


19

Звичайно, це стандартна вправа кодування.

Перш за все, нехай будь-яка біективна обчислювана функція, яка називається функцією пари. Стандартний вибір єp:N2N

p(n,m)=(n+m)(n+m+1)2+n

Можна довести, що це біекція, тому, даючи будь-який природний , ми можемо обчислити таким, що .n , m p ( n , m ) = kkn,mp(n,m)=k

Щоб перерахувати лямбда-терміни, виправте будь-яке перерахування для імен змінних: .x0,x1,x2,

Потім для кожного натурального числа друкуйте , визначений рекурсивно таким чином:l a m b d a ( i )ilambda(i)

  • якщо парний, нехай і поверне зміннуj = i / 2 x jij=i/2xj
  • якщо непарне, нехайj = ( i - 1 ) / 2ij=(i1)/2
    • якщо парне, нехай і знайдемо таким, що ; обчислити ; повернення заявкиk = j / 2 n , m p ( n , m ) = k N = l a m b d a ( n ) , M = l a m b d a ( m ) ( N M )jk=j/2n,mp(n,m)=kN=lambda(n),M=lambda(m)(NM)
    • якщо непарне, нехай і знайдемо таким, що ; обчислити ; повернути абстракціюjk=(j1)/2n,mp(n,m)=kM=lambda(m)(λxn. M)

Ця програма виправдана наступним "алгебраїчним" біекцією, що включає набір усіх лямбда-термінів :Λ

ΛN+(Λ2+N×Λ)

який читається як "лямбда-терміни, синтаксично - це роз'єднаний об'єднання 1) змінних (представлених як природне), 2) додатків (зробити двома лямбда-термінами) та 3) абстракції (пара змінної / натуральний + лямбда-термін ) ".

Враховуючи це, ми рекурсивно застосовуємо обчислювані біекції ( ) та (стандартний парний / непарний) для отримання вищезгаданого алгоритму.N2NpN+NN

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


Нічого, спасибі, чи можна представляти це псевдокодом? Я б точно зрозумів це краще, оскільки у мене немає ступеня доктора.
Legit Stack

3
@LegitStack Ну, вище зазначено псевдокод :) Ви можете визначити рекурсивну функцію а потім використовувати . Єдиний нетривіальний крок - знаходження таким, що : це можна зробити, спробувавши всі пари з (також існують більш швидкі алгоритми)lambda(n)if n%2==0 ...n,mp(n,m)=kn,mn,mk
chi

1
Дійсно, у Вікіпедії зворотну частину цієї функції сполучення можна знайти через . a=12(8k+11),b=12a(a+1),n=bk,m=an
LegionMammal978

12

Так. Візьміть щось, що перераховує всі можливі рядки ASCII. Для кожного виводу перевірте, чи дійсний синтаксис обчислення лямбда визначає функцію; якщо ні, пропустіть його. (Ця перевірка може бути зроблена.) Тут перелічені всі функції обчислення лямбда.


5
По суті, всі подібні проблеми вирішуються, викликаючи набираючу мавпу ...
xuq01

5
Або ви могли безпосередньо перерахувати терміни обчислення лямбда. Набагато швидше, ніж випадкові рядки, оскільки кожен вихід - це правильно відформатований термін. Це було б як заміна мавп, що друкують, генератором гри Шекспіра.
Ден Д.

11

Як уже згадувалося, це просто перерахування термінів із вільної від контексту мови, настільки однозначно виконаної. Але за цим стоїть цікавіша математика, яка йде в поле алітичної комбінаторики.

Стаття Підрахунок та генерація термінів у двійковому обчисленні лямбда містить трактування проблеми перерахування та багато іншого. Щоб спростити справи, вони використовують щось, що називається двійкове обчислення лямбда , яке є лише кодуванням лямбда-термінів за допомогою індексів Де Бруйна , тому вам не потрібно називати змінні.

Цей документ також містить конкретний код Haskell, що реалізує алгоритм їх генерації. Це, безумовно, ефективно можливо.

Я випадково написав реалізацію свого підходу в Джулії.


7

Звичайно. Ми можемо їх безпосередньо генерувати відповідно до визначення лямбда-термінів.

У Haskell ми спочатку визначаємо тип даних,

data LC a  =  Var  a                -- Constructor <type> <type> ...
           |  App (LC a) (LC a)     --
           |  Lam  a     (LC a)     --  ... alternatives ...

instance Show a => Show (LC a)      -- `LC a` is in Show if `a` is in Show, and
  where
    show (Var i)    =  [c | c <- show i, c /= '\'']
    show (App m n)  =  "("  ++ show m       ++ " " ++ show n ++ ")"
    show (Lam v b)  =  "(^" ++ show (Var v) ++ "." ++ show b ++ ")"

а потім із використанням ярмарку (ер) join,

lambda :: [a] -> [LC a]
lambda vars  =  terms 
  where
  terms  =  fjoin [ map Var vars ,
                    fjoin [ [App t s | t <- terms] | s <- terms ] ,
                    fjoin [ [Lam v s | v <- vars ] | s <- terms ] ]

  fjoin :: [[a]] -> [a]
  fjoin xs  =  go [] xs             -- fairer join
      where 
      go [] []  =  []
      go a  b   =  reverse (concatMap (take 1) a) ++ go 
                       (take 1 b ++ [t | (_:t) <- a]) (drop 1 b)

ми просто перерахуємо їх, як, наприклад

> take 20 $ lambda "xyz"
[x,y,(x x),z,(y x),(^x.x),(x y),(^y.x),((x x) x),(^x.y),(y y),(^z.x),(x (x x)),
 (^y.y),(z x),(^x.(x x)),((x x) y),(^z.y),(y (x x)),(^y.(x x))]

> take 5 $ drop 960 $ lambda "xyz"
[(((x x) y) (z x)),(^y.(^x.((x x) (x x)))),((^x.(x x)) (^x.(x x))),(^x.((^z.x) 
 y)),((z x) ((x x) y))]

Подивіться, знаменитий термін знаходиться там не так далеко від верху!Ω=(λx.xx)(λx.xx)

fjoinеквівалентно Omega монади «s diagonal.


0

Я натрапив на один інструмент в Інтернеті, який може генерувати зразкові рядки з регулярного виразу: https://www.browserling.com/tools/text-from-regex . Ви можете створити багато зразкових лямбда-термінів, ввівши щось подібне:

(\( (lambda \w\. )* \w+ \))* 

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


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