Помогите мне написать мою среду LISP :) LISP, Ruby Hashes - PullRequest
7 голосов
/ 12 января 2011

Я реализую элементарную версию LISP в Ruby только для того, чтобы ознакомиться с некоторыми концепциями.Я основываю свою реализацию на Lispy Питера Норвига (http://norvig.com/lispy.html).

). Здесь я кое-что упускаю, и я был бы признателен за некоторую помощь ...

Он подклассов диктует Python следующим образом:

class Env(dict):
    "An environment: a dict of {'var':val} pairs, with an outer Env."
    def __init__(self, parms=(), args=(), outer=None):
        self.update(zip(parms,args))
        self.outer = outer
    def find(self, var):
        "Find the innermost Env where var appears."
        return self if var in self else self.outer.find(var)

Затем он продолжает объяснять, почему он делает это, а не просто использует диктовку. Однако по какой-то причине его объяснение продолжает проходить через мои глаза и через затылок.

Почему бы не использовать dict, а затем внутри функции eval, когда необходимо создать новую «подпространство», просто возьмите существующий dict и обновите пары ключ / значение, которые необходимо обновить, ипередать этот новый dict в следующий eval?

Не будет ли интерпретатор Python отслеживать предыдущие "внешние" envs? И не будет ли природа рекурсии гарантировать, что значения извлекаются из "inner""to" external "?

Я использую Ruby, и я пытался реализовать все таким образом. Хотя что-то не работает, и это может быть из-за этого, а может и нет.ction, env - обычный хэш:

def eval(x, env = $global_env)
  ........ 
  elsif x[0] == "lambda" then
    ->(*args) { eval(x[2], env.merge(Hash[*x[1].zip(args).flatten(1)])) }
  ........ 
end

Строка, которая, конечно, имеет значение, - это "лямбда".

Если есть функциональная разница, то, что важно, отличается от того, что яя делаю здесь и что Norvig сделал со своим классом Env?Может ли кто-нибудь описать мне случай, когда эти два отклонятся?

Если нет никакой разницы, то, возможно, кто-то может объяснить мне, почему Norvig использует класс Env.Спасибо:)

Ответы [ 2 ]

5 голосов
/ 12 января 2011

Если привязки переменных в вашем Лиспе являются неизменяемыми, то копирование сред эквивалентно связыванию их. Но рассмотрим следующий случай:

(define main
  (lambda ()
    (define i 0)
    (define increment-i
      (lambda ()
        (set! i (+ i 1))))
    (increment-i)
    i))

(main)

Если среда increment-i полностью независима от main (так как это копия), мутация i не будет видна в main и приведенный выше код вернет 0 , Если, с другой стороны, среды связаны, возвращаемое значение будет 1, как и ожидалось.

1 голос
/ 12 января 2011

Мой Python не так хорош, а мой Лисп довольно ржавый, но я сделаю предположение, что происходит: вы не можете избежать указателей даже в тех языках, которые утверждают, что их нет.

eval, о котором вы говорите, не создаст копию dict, он просто сделает копию ссылки, и вы получите две ссылки (переменные AKA), которые ссылаются на (т.е. указать на) тот же базовый объект. То, что происходит, в основном является вариантом этого:

a = [ 'a', 'b', 'c' ]
b = a
a[1] = 'x'

puts a
# => ["a", "x", "c"]
puts b    
# => ["a", "x", "c"]

Его класс Env позволяет изменять среду внутри eval без изменения внешней среды, в то время как метод find позволяет получать доступ к внешней среде без необходимости знать; Кроме того, модификации окажутся во внутренней среде, и эти изменения будут маскировать соответствующие значения во внешней среде; Операции get будут обращаться к локальной среде и внешней среде, операции set изменят только внутреннюю среду.

Полагаю, вы могли бы назвать Env фасадом уровня объекта (а не уровня класса).

Я не уверен, что не так с вашей реализацией ruby, похоже, вы делаете модифицированную копию хэша среды. Можете ли вы уточнить "Что-то не работает, хотя"?

Уточнение: Env является таблицей символов. Материал обтекания / перенаправления в find позволяет вам получить доступ к внешней таблице символов, защищая ее от добавляемых новых символов, новые символы будут добавляться только во внутреннюю таблицу символов. Env по существу управляет закрытием.

...