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


10

Я не знаю, где еще задать этот вопрос, я надеюсь, что это хорошее место.

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

Так как лямбда-исчисление очень простое, имея в своем обозначении всего несколько элементов, я подумал, что можно (хотя и не очень полезно) создать все возможные комбинации этих элементов обозначений, начиная с простейших комбинаций, и тем самым получить все возможные лямбда-выражения. исчисление функции.

Конечно, я почти ничего не знаю о лямбда-исчислении, поэтому понятия не имею, возможно ли это на самом деле.

Это? Если так, это довольно просто, как я предполагал, или это технически возможно, но настолько сложно, что это фактически невозможно?

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

Ответы:


19

Конечно, это стандартное упражнение по кодированию.

Прежде всего, пусть любая биективная вычислимая функция, называемая парной функцией. Стандартный выборп:N2→N

п(N,м)знак равно(N+м)(N+м+1)2+N

Можно доказать, что это биекция, поэтому при любом натуральном мы можем вычислить n , m так , чтобы p ( n , m ) = k .kn,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 ) / 2яJзнак равно(я-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 )JКзнак равноJ/2N,мп(N,м)знак равноКNзнак равноLaмбda(N),Mзнак равноLaмбda(м)(NM)
    • если нечетно, пусть k = ( j - 1 ) / 2 и найдем n , m такое, что p ( n , m ) = k ; вычислить M = l a m b d a ( m ) ; возвратная абстракция ( λ x n . M )JКзнак равно(J-1)/2N,мп(N,м)знак равноКMзнак равноLaмбda(м)(λИксN, M)

Эта программа обоснована следующей «алгебраической» биекцией, включающей множество всех лямбда-членов :Λ

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

который читается как «лямбда-термины, синтаксически - это непересекающееся объединение 1) переменных (представленных как натуральные), 2) приложений (составленных из двух лямбда-терминов) и 3) абстракции (парная переменная / натуральная + лямбда-член )».

Учитывая это, мы рекурсивно применяем вычислимые биекции ( p ) и N + N ≃ N (стандартная четная / нечетная) для получения алгоритма, описанного выше.N2≃NпN+N≃N

Эта процедура является общей и будет работать практически на любом языке, сгенерированном с помощью контекстно-свободной грамматики, которая обеспечит изоморфизм, аналогичный приведенному выше.


Вау, спасибо, возможно, вы могли бы представить, что это псевдокод? Я бы определенно понял это лучше, так как у меня нет степени бакалавра.
— Легит стек

3
@LegitStack Ну, выше приведен псевдокод :) Вы можете определить рекурсивную функцию и затем использовать . Единственный нетривиальный шаг - найти n , m такой, что p ( n , m ) = k : это можно сделать, попробовав все пары n , m с n , m ≤ k (также существуют более быстрые алгоритмы)Laмбda(N)if n%2==0 ...N,мп(N,м)знак равноКN,мN,м≤К
— chi

1
Действительно, согласно Википедии, обратная сторона этой конкретной функции сопряжения может быть найдена через . aзнак равно⌊12(8К+1-1)⌋,бзнак равно12a(a+1),Nзнак равноб-К,мзнак равно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))]

Посмотрите, знаменитый член Ωзнак равно(λИкс,ИксИкс)(λИкс,ИксИкс) находится не так далеко от вершины!

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.