LINUX.ORG.RU

Свой велосипед - вычисления в переданном окружении

 ,


0

3

Захотел я добавить в свой схемоподобный язык давно лежащую на поверхности идею: вычисления в любом переданном контексте (окружении). Дописал 4 строчки кода - добавил новую ядерную особую форму eval-in, которая принимает лямбду (ибо у меня нет окружений как объектов первого класса, но это и не требуется, ибо лямбды содержат их в себе как замыкания) и список, который надо вычислить в окружении этой переданной лямбды. Пример:

; генератор замыканий ;
(defn f (x y) lambda ())
; создание пары объектов-замыканий с разными параметрами ;
(def a (f 1 2) b (f 10 20))
; вычисления в контексте переданного замыкания ;
(print (eval-in a (+ x y)) \n)
(print (eval-in b (def x 30) (+ x y)) \n)
 
........
 
=> 3
50
OK
Все хорошо работает. Но тут я подумал, что можно выпилить эту особую форму обратно из языка, ибо имхо того же можно добиться следующим образом: замыкание возвращает унарную лямбду, ожидающую на входе нульарный макрос, который она будет вычислять в своем окружении. Макрос у нас гражданин первого класса, может передаваться в качестве параметра в функции, и по семантике своего замкнутого окружения не имеет и будет вычисляться в окружении вызова, откуда и будет черпать свои свободные переменные:
; генератор замыканий, принимающих макрос для выполнения в своем контексте ;
(defn f (x y) lambda (m) m)
; создание пары объектов-замыканий с разными параметрами ;
(def a (f 1 2) b (f 10 20))
; вычисления макросов в контексте переданного замыкания ;
(print (a (macro () + x y)) \n)
(print (b (macro () (def x 30) (+ x y))) \n)
- выдает тот же результат. Но потом я подумал еще, и понял, что вариант с макросами уже по возможностям - например, создание новых переменных тут происходит в контексте лямбды, и не меняет контекст f, в отличие от варианта с eval-in. Макросами можно изменять значения переменных контекста f (через set!), но не добавлять новые. Хотя может можно придумать, как обойти это ограничение.

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


Макрос у нас гражданин первого класса

А чем она тогда у вас отличается от лямбд?

Weres ★★★
()
Ответ на: комментарий от Weres

Отличается моделью (семантикой) вычисления - лямбда при создании запоминает ссылку на окружающий контекст а при вычислении связывает предварительно вычисленные в контексте вызова значения аргументов с их формальными именами, добавляет эти связи в свой контекст (создания) и вычисляет тело в нем - как обычная лямбда с лексическим окружением, а макрос при создании никакой контекст не запоминает, а при вычислении заменяет в своем теле связанные переменные невычисленными значениями фактических параметров вызова и далее вычисляет этот замененный терм в контексте вызова - как обычный макрос. Надеюсь, понятно написал.

Ivana
() автор топика
Ответ на: комментарий от Ivana

в пиколиспе динамическое связывание, там ничего не надо явно передавать, функция вычисляется в контексте вызова, как в старинных лиспах

portquest2016
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.