Gerador de cálculo Lambda


10

Não sei mais aonde fazer essa pergunta, espero que este seja um bom lugar.

Estou curioso para saber se é possível fazer um gerador de cálculo lambda; essencialmente, um loop que, com tempo infinito, produzirá todas as funções possíveis de cálculo lambda. (como na forma de uma string).

Como o cálculo lambda é muito simples, tendo apenas alguns elementos em sua notação, pensei que seria possível (embora não muito útil) produzir todas as combinações possíveis desses elementos de notação, começando pelas combinações mais simples, e assim produzir todos os lambda possíveis função de cálculo.

Claro, eu não sei quase nada sobre cálculo lambda, então não tenho idéia se isso é realmente possível.

É isso? Em caso afirmativo, é bem simples como eu o imaginava, ou é tecnicamente possível, mas tão difícil que é efetivamente impossível?

PS. Não estou falando de funções com redução beta, mas apenas de todas as notações válidas de todas as funções de cálculo lambda.

Respostas:


19

Claro, este é um exercício de codificação padrão.

Antes de tudo, deixe qualquer função computável bijetiva, chamada função de emparelhamento. Uma escolha padrão ép:N2N

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

Pode-se provar que isso é uma bijeção, portanto, dado qualquer natural , podemos calcular n , m de modo que p ( n , m ) = k .kn,mp(n,m)=k

Para enumerar termos lambda, corrija qualquer enumeração para nomes de variáveis: .x0,x1,x2,

Então, para cada número natural , imprima l a m b d a ( i ) , definido recursivamente da seguinte maneira:ilambda(i)

  • se for par, deixe j = i / 2 e retorne a variável x jij=i/2xj
  • se é ímpar, seja j = ( i - 1 ) / 2ij=(i1)/2
    • se for par, deixe k = j / 2 e encontre n , m de modo que p ( n , m ) = k ; calcular N = l a m b d a ( n ) , M = l a m b d a ( m ) ; aplicação de devolução ( N M )jk=j/2n,mp(n,m)=kN=euumambduma(n),M=euumambduma(m)(NM)
    • se for ímpar, seja k = ( j - 1 ) / 2 e encontre n , m tal que p ( n , m ) = k ; calcular M = l a m b d a ( m ) ; abstração de retorno ( λ x n . M )jk=(j-1 1)/2n,mp(n,m)=kM=euumambduma(m)(λxn. M)

Este programa é justificado pela seguinte bijeção "algébrica" ​​envolvendo o conjunto de todos os termos lambda :Λ

ΛN+(Λ2+N×Λ)

que é lido como "os termos lambda, sintaticamente, são a união disjunta de 1) variáveis ​​(representadas como naturais), 2) aplicações (feitas por dois termos lambda) e 3) abstração (um par variável / natural + termo lambda ) ".

Dado isso, aplicamos recursivamente as bijeções computáveis ( p ) e N + NN (o padrão par / ímpar) para obter o algoritmo acima.N2NpN+NN

Este procedimento é geral e funcionará em quase qualquer linguagem gerada por meio de uma gramática livre de contexto, que fornecerá um isomorfismo semelhante ao descrito acima.


Uau, obrigado, é possível que você possa representar esse pseudo-código? Definitivamente, eu entenderia isso melhor, pois não tenho um diploma de cs.
Legit Stack

3
@ LegitStack Bem, o acima é pseudo-código :) Você pode definir uma função recursiva e depois usá-la . O único passo não trivial é encontrar n , m tal que p ( n , m ) = k : isso pode ser feito tentando todos os pares n , m com n , m k (algoritmos mais rápidos também existem)euumambduma(n)if n%2==0 ...n,mp(n,m)=kn,mn,mk
chi

11
De fato, por Wikipedia, o inverso dessa função de emparelhamento específico pode ser encontrado através de . uma=1 12(8k+1 1-1 1),b=1 12uma(uma+1 1),n=b-k,m=uma-n
LegionMammal978

12

Sim. Pegue algo que enumere todas as seqüências ASCII possíveis. Para cada saída, verifique se é uma sintaxe válida de cálculo lambda que define uma função; Caso contrário, pule. (Essa verificação pode ser feita.) Isso enumera todas as funções de cálculo lambda.


5
Essencialmente, todos os problemas como esse são resolvidos invocando o macaco de digitação ...
xuq01 20/18

5
Ou você pode enumerar diretamente os termos do cálculo lambda. Muito mais rápido que seqüências aleatórias, pois cada saída é um termo formatado corretamente. Seria como substituir os macacos de digitação por um gerador de brincadeiras de Shakespeare.
Dan D.

11

Como foi mencionado, isso é apenas enumerando termos de uma linguagem livre de contexto, tão definitivamente factível. Mas há uma matemática mais interessante por trás disso, entrando no campo da combinatória analítica.

O artigo Contando e gerando termos no cálculo lambda binário contém um tratamento do problema de enumeração e muito mais. Para simplificar, eles usam algo chamado binário lambda calulus , que é apenas uma codificação de termos lambda usando índices De Bruijn , para que você não precise nomear variáveis.

Esse documento também contém código Haskell concreto implementando seu algoritmo de geração. É definitivamente efetivamente possível.

Por acaso, escrevi uma implementação de sua abordagem em Julia.


7

Certo. Podemos gerá-los diretamente de acordo com a definição de termos lambda.

Em Haskell, definimos o tipo de dados primeiro,

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 ++ ")"

e depois com o uso de uma feira (er) 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)

apenas as enumeramos, como por exemplo

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

Olha, o famoso Ω=(λx.xx)(λx.xx) termo está lá não tão longe do topo!

fjoiné equivalente ao Omega monad 's diagonal.


0

Encontrei uma ferramenta on-line que pode gerar seqüências de amostra a partir de uma expressão regular: https://www.browserling.com/tools/text-from-regex . Você pode gerar muitos termos lambda de amostra inserindo algo como isto:

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

Obviamente, para obter termos com níveis arbitrários de aninhamento, você precisará usar uma gramática livre de contexto, que é uma ferramenta mais descritiva para definir um idioma do que uma expressão regular. Eu não encontrei uma ferramenta existente para gerar frases de exemplo de linguagem com base em uma definição gramatical livre de contexto, mas não há razão para que uma não possa ser criada.


2
o λ-terms não são expressões regulares (como você observa). É prejudicial responder à pergunta de um iniciante dessa maneira, porque obscurece uma distinção importante (nomeadamente entre gramáticas livres de contexto e expressões regulares).
Andrej Bauer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.