Generador de cálculo Lambda

10

No sé dónde más hacer esta pregunta, espero que este sea un buen lugar.

Tengo curiosidad por saber si es posible hacer un generador de cálculo lambda; esencialmente, un ciclo que, dado un tiempo infinito, producirá todas las funciones posibles de cálculo lambda. (como en forma de una cadena).

Dado que el cálculo lambda es tan simple, con solo unos pocos elementos para su notación, pensé que podría ser posible (aunque no muy útil) producir todas las combinaciones posibles de esos elementos de notación, comenzando con las combinaciones más simples y, por lo tanto, producir todas las lambda posibles función de cálculo

Por supuesto, no sé casi nada sobre el cálculo lambda, así que no tengo idea de si esto es realmente posible.

¿Lo es? Si es así, ¿es bastante sencillo como lo imaginé, o es técnicamente posible, pero tan difícil que es efectivamente imposible?

PD. No estoy hablando de funciones reducidas en beta, solo estoy hablando de cada notación válida de cada función de cálculo lambda.

Pila legítima
fuente

Respuestas:

19

Claro, este es un ejercicio de codificación estándar.

En primer lugar, deje que cualquier función computable biyectiva, llamada función de emparejamiento. Una opción estándar espags:norte2norte

pags(norte,metro)=(norte+metro)(norte+metro+1)2+norte

Se puede demostrar que se trata de una biyección, por lo tanto, dada cualquier natural , podemos calcular tal que .n , m p ( n , m ) = kknorte,metropags(norte,metro)=k

Para enumerar los términos lambda, arregle cualquier enumeración para nombres de variables: .X0 0,X1,X2,...

Luego, para cada número natural , imprima , definido recursivamente de la siguiente manera:l a m b d a ( i )yolunmetrosireun(yo)

  • si es par, dejemos que y variablej = i / 2 x jyoj=yo/ /2Xj
  • si es impar, dejemos quej = ( i - 1 ) / 2yoj=(yo-1)/ /2
    • si es par, deje y encuentre tal que ; calcular ; solicitud de devoluciónk = 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/ /2norte,metropags(norte,metro)=knorte=lunmetrosireun(norte),METRO=lunmetrosireun(metro)(norteMETRO)
    • si es impar, deje y encuentre tal que ; calcular ; abstracción de retornojk=(j-1)/ /2norte,metropags(norte,metro)=kMETRO=lunmetrosireun(metro)(λXnorte. METRO)

Este programa está justificado por la siguiente biyección "algebraica" que involucra el conjunto de todos los términos lambda :Λ

Λnorte+(Λ2+norte×Λ)

que se lee como "los términos lambda, sintácticamente, son la unión disjunta de 1) variables (representadas como naturales), 2) aplicaciones (hechas por dos términos lambda) y 3) abstracción (un par variable / natural + término lambda ) ".

Dado eso, aplicamos recursivamente biyecciones computables ( ) y (el estándar par / impar) para obtener el algoritmo anterior.norte2nortepagsnorte+nortenorte

Este procedimiento es general y funcionará en casi cualquier lenguaje generado a través de una gramática libre de contexto, que proporcionará un isomorfismo similar al anterior.

chi
fuente
Wow, gracias, ¿es posible que puedas representar este es un pseudocódigo? Definitivamente lo entendería mejor ya que no tengo un título de licenciatura.
Legit Stack
3
@LegitStack Bueno, lo anterior es un pseudocódigo :) Puede definir una función recursiva y luego usar . El único paso no trivial es encontrar n , m tal que p ( n , m ) = k : esto se puede hacer probando todos los pares n , m con n , m k (también existen algoritmos más rápidos)lunmetrosireun(norte)if n%2==0 ...norte,metropags(norte,metro)=knorte,metronorte,metrok
chi
1
un=12(8k+1-1),si=12un(un+1),norte=si-k,metro=un-norte
12

Si. Tome algo que enumere todas las cadenas ASCII posibles. Para cada salida, verifique si es una sintaxis válida de cálculo lambda que define una función; si no, sáltatelo. (Se puede hacer esa verificación). Enumera todas las funciones de cálculo lambda.

DW
fuente
55
Esencialmente, todos los problemas como este se resuelven invocando al mono escribiendo ...
xuq01
55
O podría enumerar directamente los términos de cálculo lambda. Mucho más rápido que las cadenas aleatorias, ya que cada salida es un término con el formato adecuado. Eso sería como reemplazar a los monos que escriben con un generador de juegos de Shakespeare.
Dan D.
11

Como se ha mencionado, esto es solo enumerar términos de un lenguaje libre de contexto, por lo que definitivamente es factible. Pero hay más matemáticas interesantes detrás de esto, entrando en el campo de la combinatoria analítica.

El papel Contar y generar términos en el cálculo lambda binario contiene un tratamiento del problema de enumeración y mucho más. Para simplificar las cosas, usan algo llamado binario lambda calulus , que es solo una codificación de términos lambda usando índices de De Bruijn , por lo que no tiene que nombrar variables.

Ese documento también contiene código concreto de Haskell que implementa su algoritmo de generación. Definitivamente es efectivamente posible.

Resulta que escribí una implementación de su enfoque en Julia.

phipsgabler
fuente
7

Seguro. Podemos generarlos directamente de acuerdo con la definición de términos lambda.

En Haskell, primero definimos el tipo de datos,

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

y luego con el uso de un justo (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)

simplemente los enumeramos, por ejemplo

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

fjoines equivalente a Omega mónada 's diagonal.

Will Ness
fuente
0

Me he encontrado con una herramienta en línea que puede generar cadenas de muestra a partir de una expresión regular: https://www.browserling.com/tools/text-from-regex . Puede generar muchos términos lambda de muestra ingresando algo como esto:

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

Por supuesto, para obtener términos con niveles arbitrarios de anidamiento, necesitará usar una gramática libre de contexto, que es una herramienta más descriptiva para definir un lenguaje que una expresión regular. No he encontrado una herramienta existente para generar oraciones de lenguaje de muestra basadas en una definición gramatical sin contexto, pero no hay razón para que no se pueda construir.

martín
fuente
2
λ