Generatore di calcoli Lambda


10

Non so dove altro porre questa domanda, spero che sia un buon posto.

Sono solo curioso di sapere se è possibile creare un generatore di calcolo lambda; essenzialmente, un ciclo che, a tempo infinito, produrrà ogni possibile funzione di calcolo lambda. (come sotto forma di una stringa).

Poiché il calcolo lambda è così semplice, avendo solo pochi elementi nella sua notazione, ho pensato che sarebbe stato possibile (anche se non molto utile) produrre tutte le possibili combinazioni di quegli elementi della notazione, a partire dalle combinazioni più semplici, e quindi produrre ogni possibile lambda funzione di calcolo.

Certo, non so quasi nulla del calcolo lambda, quindi non ho idea se questo sia davvero possibile.

È? Se è così, è abbastanza semplice come l'ho immaginato, o è tecnicamente possibile, ma così difficile da essere effettivamente impossibile?

PS. Non sto parlando di funzioni beta-ridotte, sto solo parlando di ogni notazione valida di ogni funzione di calcolo lambda.

Risposte:


19

Certo, questo è un esercizio di codifica standard.

Prima di tutto, qualsiasi funzione calcolabile biiettiva, chiamata funzione di associazione. Una scelta standard èp:N2N

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

Si può dimostrare che questa è una biiezione, quindi dato qualsiasi naturale , possiamo calcolare tale che .n , m p ( n , m ) = kkn,mp(n,m)=k

Per enumerare i termini lambda, correggi qualsiasi enumerazione per i nomi delle variabili: .x0,x1,x2,

Quindi, per ogni numero naturale , stampa , definito in modo ricorsivo come segue:l a m b d a ( i )ilambda(i)

  • se è pari, lascia e restituisce la variabilej = i / 2 x jij=i/2xj
  • se è dispari, lasciaj = ( i - 1 ) / 2ij=(i1)/2
    • se è pari, lascia e trova tale che ; calcolare ; domanda dik = 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)
    • se è dispari, lascia e trova tale che ; calcolare ; ritorno astrazionek = ( j - 1 ) / 2 n , m p ( n , m ) = k M = l a m b d a ( m ) ( λ x n . M )jk=(j1)/2n,mp(n,m)=kM=lambda(m)(λxn. M)

Questo programma è giustificato dalla seguente biiezione "algebrica" ​​che coinvolge l'insieme di tutti i termini lambda :Λ

ΛN+(Λ2+N×Λ)

che viene letto come "i termini lambda, sintatticamente, sono l'unione disgiunta di 1) variabili (rappresentate come naturali), 2) applicazioni (create da due termini lambda) e 3) astrazione (una coppia variabile / naturale + termine lambda )".

Detto questo, applichiamo ricorsivamente biiezioni calcolabili ( ) e (lo standard pari / dispari) per ottenere l'algoritmo sopra. p N + N NN2NpN+NN

Questa procedura è generale e funzionerà su quasi tutti i linguaggi generati attraverso una grammatica senza contesto, che fornirà un isomorfismo simile a quello sopra.


Wow, grazie, è possibile che tu possa rappresentare questo pseudo codice? Lo capirò sicuramente meglio perché non ho un diploma di laurea specialistica.
Legit Stack

3
@LegitStack Bene, quanto sopra è pseudo-codice :) È possibile definire una funzione ricorsiva e quindi utilizzare . L'unico passo non banale è trovare tale che : questo può essere fatto provando tutte le coppie con (esistono anche algoritmi più veloci)lambda(n)if n%2==0 ...n,mp(n,m)=kn,mn,mk
chi

1
In effetti, per Wikipedia, l'inverso di questa particolare funzione di associazione può essere trovata tramite . a=12(8k+11),b=12a(a+1),n=bk,m=an
LegionMammal978,

12

Sì. Prendi qualcosa che enumera tutte le possibili stringhe ASCII. Per ogni output, controlla se è una sintassi di calcolo lambda valida che definisce una funzione; in caso contrario, saltalo. (Questo controllo può essere eseguito.) Che elenca tutte le funzioni di calcolo lambda.


5
In sostanza, tutti i problemi come questo vengono risolti invocando la scimmia da battitura ...
xuq01

5
Oppure potresti enumerare direttamente i termini del calcolo lambda. Molto più veloce delle stringhe casuali poiché ogni output è un termine formattato correttamente. Sarebbe come sostituire le scimmie che digitano con un generatore di giochi di Shakespeare.
Dan D.

11

Come è stato menzionato, si tratta solo di enumerare i termini da un linguaggio privo di contesto, quindi assolutamente fattibile. Ma c'è più matematica interessante dietro di essa, andando nel campo della combinatoria analitica.

L'articolo Conteggio e generazione dei termini nel calcolo lambda binario contiene un trattamento del problema di enumerazione e molto altro. Per semplificare le cose, usano qualcosa chiamato il binario lambda calulus , che è solo una codifica dei termini lambda usando gli indici di De Bruijn , quindi non devi nominare le variabili.

Tale documento contiene anche un codice Haskell concreto che implementa il loro algoritmo di generazione. È sicuramente efficacemente possibile.

Mi è capitato di aver scritto un'implementazione del loro approccio a Julia.


7

Sicuro. Possiamo generarli direttamente secondo la definizione dei termini lambda.

In Haskell, definiamo prima il tipo di dati,

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 poi con l'uso di una fiera (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)

li enumeriamo semplicemente, come ad es

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

Guarda, il famoso termine è lì dentro non molto lontano dalla cima!Ω=(λx.xx)(λx.xx)

fjoinè equivalente a Omega Monade s' diagonal.


0

Ho trovato uno strumento online in grado di generare stringhe di esempio da un'espressione regolare: https://www.browserling.com/tools/text-from-regex . Puoi generare molti termini lambda di esempio inserendo qualcosa del genere:

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

Naturalmente per ottenere termini con livelli arbitrari di annidamento, dovrai utilizzare una grammatica senza contesto, che è uno strumento più descrittivo per definire una lingua che un'espressione regolare. Non ho trovato uno strumento esistente per generare frasi in linguaggio di esempio basate su una definizione grammaticale senza contesto, ma non c'è motivo per cui non si possa costruire.


2
I -terms non sono espressioni regolari (come si nota). È dannoso rispondere alla domanda di un principiante in questo modo perché nasconde una distinzione importante (vale a dire tra grammatiche senza contesto ed espressioni regolari). λ
Andrej Bauer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.