2014-01-09 3 views
4

Что такое алгоритм, который будет перечислять выражения для лямбда-исчисления по порядку длины? Например, (λx.x), (λx.(x x)), (λx.(λy.x)) и так далее?Что такое алгоритм для перечисления лямбда-терминов?

+1

Как вы определяете длину? –

+1

@ KristopherMicinski любой порядок сделает это, я не хотел быть строгим по этому слову. Я просто хотел избежать явных катастроф, таких как генерация '(λx. (Λy. (Λz. ((Z x) (y x) x y y))))' before '(λx.λy.y)', что, очевидно, неверно. – MaiaVictor

ответ

2

В длину я бы выбрал число T -разложений («глубина») в этом BNF из (нетипизированных) лямбда-выражений:

V ::= x | y 
T ::= V | 
     λV.T | 
     (T T) 

В питона вы можете определить генератор, следуя вышеприведенным правилам поколения для данные переменные и заданная глубина, как это:

def lBNF(vars, depth): 
    if depth == 1: 
    for var in vars: 
     yield var 
    elif depth > 1: 
    for var in vars: 
     for lTerm in lBNF(vars,depth-1): 
     yield 'l%s.%s' % (var,lTerm) 
    for i in range(1,depth): 
     for lTerm1 in lBNF(vars,i): 
     for lTerm2 in lBNF(vars,depth-i): 
      yield '(%s %s)' % (lTerm1,lTerm2) 

Теперь вы можете перечислить термины лямбды для/до заданной глубины:

vars = ['x','y'] 
for i in range(1,5): 
    for lTerm in lBNF(vars,i): 
    print lTerm 
+0

Отличный ответ, спасибо! Можно ли изменить его, чтобы он генерировал только замкнутые термины, используя индексы bruijn? – MaiaVictor

+0

@viclib Вы имеете в виду, что нет несвязанных переменных? (никогда не слышал о индексах bruijn) Это потребует некоторой постобработки или некоторой другой умной адаптации ... – coproc

+0

Эх, это просто способ бросить струны. (λ (λ (0 1))) - здесь 0 привязано ко второму λ и 1 привязано к куму. – MaiaVictor

1

См https://arxiv.org/abs/1210.2610, стр 5. Вот несколько примеров кода:

from itertools import chain, count 
from functools import lru_cache 

@lru_cache(maxsize=None) 
def terms(size, level=0): 
    if size == 0: 
     return tuple(range(level)) 
    else: 
     abstractions = (
      ('abs', term) 
      for term in terms(size - 1, level + 1) 
     ) 
     applications = (
      ('app', term1, term2) 
      for i in range(size) 
      for term1 in terms(i, level) 
      for term2 in terms(size - 1 - i, level) 
     ) 
     return tuple(chain(abstractions, applications)) 

def string(term): 
    if isinstance(term, tuple): 
     if term[0] == 'abs': 
      return '(λ {})'.format(string(term[1])) 
     elif term[0] == 'app': 
      return '({} {})'.format(string(term[1]), string(term[2])) 
    else: 
     return term 

for size in count(): 
    print('{} terms of size {}'.format(len(terms(size)), size)) 
    for term in terms(size): 
     pass # input(string(term)) 

Это выводит

0 terms of size 0 
1 terms of size 1 
3 terms of size 2 
14 terms of size 3 
82 terms of size 4 
579 terms of size 5 
4741 terms of size 6 
43977 terms of size 7 
454283 terms of size 8 

и так далее (т.е. this sequence).