Clojure добавить var в пространство имен - PullRequest
0 голосов
/ 03 мая 2018

Как я могу добавить переменную var в пространство имен clojure, т. Е. Чтобы ее можно было извлечь позже через вызов ns-interns?

Это , а не (intern ns sym ...), потому что intern создает var или использует то, к чему привязан var sym. Это различие важно, когда другие пространства имен требуют ns и содержат ссылки на переменные в ns. То, что я прошу, это противоположность ns-unmap.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Фон: ns-interns против ns-map

ns-interns возвращает карту Vars, первоначально интернированную в данном пространстве имен. Невозможно взять Var из одного пространства имен и отобразить его в выводе другого пространства имен ns-interns. Таким образом, если вы хотите, чтобы Var появлялся здесь, вам нужно использовать intern или def.

Напротив, ns-map является более фундаментальным примитивом, который возвращает потенциально большую карту, которая включает в себя «собственные интерны», но также и переменные из других пространств имен, введенных через :require :refer и импортированных классов Java.

(Это более фундаментально, потому что ns-interns работает, вызывая ns-map и фильтруя его так, что сохраняются только Vars, изначально интернированные в данном пространстве имен. Это возможно, потому что Vars отслеживают пространство имен, в котором они были созданы, если любое и любое изначально присвоенное имя. 1 )

Карта, которую возвращает ns-map, - это та, с которой ns-unmap удаляет сопоставления. Обратите внимание, что ns-map и ns-unmap не делают различий между "собственными переменными" и переменными из других пространств имен. Записи var на этой карте создаются, когда вы используете intern или def, но также и при сопоставлении Vars из других пространств имен. Если последнее - то, что вы хотите сделать, есть несколько способов сделать это.

Добавление переменных из других пространств имен в данное пространство имен ns-map

Стандартным способом является использование :require :refer … :rename … или :use :only … :rename … в форме ns или clojure.core/refer :only … :rename … при REPL:

user=> (refer 'clojure.string :only '[lower-case] :rename '{lower-case lc})
nil
user=> (lc "ASDF")
"asdf"

NB. Аргумент, следующий за :only, представляет собой набор символов без пространств имен, которые присваивают именам переменные, которые вы хотите добавить, в их собственном пространстве имен - исходных именах, а карта :rename содержит исходные имена в ключевой позиции и ваши замещающие имена. в положении значения.

Если вы счастливы принять оригинальное имя, вы можете пропустить :rename.

Также можно вызвать clojure.core/require или clojure.core/use, что обеспечит загрузку пространства имен и затем refer Vars, которые вам нужны. Синтаксис такой же, как в форме ns - см. Ниже, - за исключением того, что наборы символов, следующие за :only и :rename, должны быть заключены в кавычки, как при вызове refer выше.

В ns форме вы бы сказали

(:require [clojure.string :refer [lower-case] :rename {lower-case lc}])

или

(:use [clojure.string :only [lower-case] :rename {lower-case lc}])

:require имеет тенденцию быть предпочтительным в наши дни как вопрос стиля.


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

0 голосов
/ 03 мая 2018

Разве вы не можете просто использовать def?:

def
Creates and interns or locates a global var with the name of symbol and a
namespace of the value of the current namespace (*ns*). 

и в коде:

(def alpha)
(def beta :boo)
(intern 'tst.demo.core 'gamma :charlie)

(ns-interns 'tst.demo.core)
    => {alpha  #'tst.demo.core/alpha,  
        beta   #'tst.demo.core/beta
        gamma  #'tst.demo.core/gamma}

Я не уверен, что вы здесь? Все они кажутся одинаковыми.

...