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

10

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

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

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

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

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

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

Стек Легит
источник

Ответы:

19

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

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

п(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 + NN (стандартная четная / нечетная) для получения алгоритма, описанного выше.N2NпN+NN

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

чи
источник
Вау, спасибо, возможно, вы могли бы представить, что это псевдокод? Я бы определенно понял это лучше, так как у меня нет степени бакалавра.
Легит стек
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. Для каждого вывода проверьте, является ли он допустимым синтаксисом лямбда-исчисления, который определяет функцию; если нет, пропустите это. (Эту проверку можно сделать.) Перечисляет все функции лямбда-исчисления.

DW
источник
5
По сути, все подобные проблемы решаются путем вызова набирающей обезьяны ...
xuq01
5
Или вы можете напрямую перечислить термины лямбда-исчисления. Гораздо быстрее, чем случайные строки, поскольку каждый вывод - это правильно отформатированный термин. Это все равно, что заменить печатных обезьян на игровой генератор Шекспира.
Дэн Д.
11

Как уже упоминалось, это просто перечисление терминов из языка без контекста, так что это определенно выполнимо. Но за этим стоит более интересная математика, уходящая в область анлитической комбинаторики.

В статье Подсчет и генерация членов в двоичном лямбда-исчислении содержится обработка проблемы перечисления и многое другое. Чтобы упростить задачу , они используют нечто, называемое двоичным лямбда-каллусом , которое представляет собой просто кодировку лямбда-терминов с использованием индексов Де Брюина , поэтому вам не нужно называть переменные.

Эта статья также содержит конкретный код на Haskell, реализующий алгоритм их генерации. Это определенно эффективно возможно.

Я случайно написал реализацию их подхода в Юлии.

phipsgabler
источник
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
λ