Я лениво изучаю PicoLisp и нахожусь в недоумении о том, как писать функции метапрограммирования, которые традиционно обрабатываются с помощью макросов (на других диалектах lisp).Самым большим источником беспокойства для меня является то, что я не понимаю, как я могу предотвратить затенение имен переменных.Просмотр примеров в Метапрограммирование 101 , во всяком случае, просто запутал меня.
Примеры того, как реализовать функцию mapeach
, как видно из связанной статьи:
[de mapeach "Args" # expression
(let [(@Var @List . @Body) "Args"]
(macro
(mapcar
'((@Var) . @Body)
@List ]
(de mapeach "Args"
(mapcar
(cons (cons (car "Args")) (cddr "Args"))
(eval (cadr "Args")) ) )
(de mapeach "Args"
(mapcar
'(("E")
(bind (car "Args")
(set (car "Args") "E")
(run (cddr "Args")) ) )
(eval (cadr "Args")) ) )
(de mapeach "Args"
(let "Vars" (pop '"Args")
(apply mapcar
(mapcar eval (cut (length "Vars") '"Args"))
(cons "Vars" "Args") ) ) )
Я проверил каждый из них с помощью вызова (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
.Как и ожидалось, интерпретатор PicoLisp (запущенный с помощью команды pil +
) испытывает сбой и вылетает.Я предполагаю, что это потому, что mapeach
"Args"
затеняет "Args"
, определенный в точке вызова.
Я также попробовал обе их реализации map@
("более симпатичная" альтернатива mapeach
).
(de map@ "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '@'
(eval (car "Args")) ) )
(de map@ "Args"
(mapcar
'((@) (run (cdr "Args")))
(eval (car "Args")) ) )
Я использовал (let "Args" * (map@ (1 2 3) ("Args" @ @)))
для проверки каждой из этих реализаций.Как ни странно, когда я впервые протестировал первую реализацию, он не только не segfault, но и действительно дал правильный результат (1 4 9)
.Каждый последующий тест привел к ошибке.Для ясности, фрагмент из приглашения:
: (de map@ "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '@'
(eval (car "Args")) ) )
-> map@
: (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
!? (mapeach N (1 2 3) ("Args" N N))
mapeach -- Undefined
?
: (let "Args" * (map@ (1 2 3) ("Args" @ @)))
-> (1 4 9)
Я полагаю, что segfault каким-то образом был предотвращен вызовом (тогда) неопределенной функции mapeach
, я также попытался (ooga booga)
, что аналогично предотвратилоСигфоЕсли у меня нет ошибочного вызова, отделяющего определение от правильного вызова, всегда происходит ошибка.
В конечном итоге это завершается двумя вопросами:
- Как я могу предотвратить скрытие имени?Очевидно, что примеры в этом отношении не увенчались успехом.
- Почему этот вызов map @ не приводит к segfault?