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


10

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

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

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

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

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

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

Відповіді:


19

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

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

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=(i−1)/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=(j−1)/2n,mp(n,m)=kM=lambda(m)(λxn. M)

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

Λ≃N+(Λ2+N×Λ)

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

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

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


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

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

1
Дійсно, у Вікіпедії зворотну частину цієї функції сполучення можна знайти через . a=⌊12(8k+1−1)⌋,b=12a(a+1),n=b−k,m=a−n
— 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.