Вопрос о Метапрограммировании Clojure (для новичка!)

Все, я начинаю смотреть на язык Clojure и имел пару вопросов о чем-то, что я пытаюсь сделать. Широкая задача состоит в том, чтобы исказить функцию последовательности every? кому: all?. Я уверен, что существует функция или макрос, который делает искажение (или что-то вдоль тех строк), но я хотел видеть, было ли это возможно с некоторыми основными конструкциями, я знаю к настоящему времени. Мой подход был для определения вызванной функции all? это применяет его аргументы every? реализация.

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

1) Определение именованных функций с Ключевыми словами бросает ошибки. По-видимому, это хочет clojure.lang.IObj.

user=> (defn :foo "bar")     
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0)

Существует ли функция для кастинга Ключевого слова к IObj или других средств параметризовать название недавно определенной функции с некоторыми предоставленными значению? (В Ruby, define_method среди других методов делает это),

irb(main)> self.class.instance_eval do
irb(main)* define_method(:foo) { "bar" }
irb(main)> end
=> #<Proc>
irb(main)> foo
=> "bar"

2) Соберите все аргументы функции в единственную переменную. Даже основные функции такой как (+ 1 2 3 4) возьмите переменную сумму аргументов. Все функциональные методы определения, которые я видел до сих пор, берут определенную сумму аргументов, без пути только к агрегировали все в списке для обработки в теле функции. Еще раз то, для чего я иду, сделано в Ruby как так:

irb(main)> def foo(*args)
irb(main)> p args
irb(main)> end
=> nil
irb(main)> foo(1, 2, 3)
[1, 2, 3]
=> nil

Спасибо за любую справку можно предоставить мне!

11
задан Evan Senter 6 July 2010 в 03:02
поделиться

3 ответа

Я отвечу в виде маркированного списка, так как вопросы можно аккуратно разделить на несколько отдельных вопросов.

  • Что-то, что неявно содержится в том, что будет следовать, но что, возможно, заслуживает отдельной пули: объекты верхнего уровня, созданные def & Co. (и, в частности, defn ) являются варсами. Итак, на самом деле вам нужно создать псевдоним Var ; функции - это просто обычные значения, у которых на самом деле нет имен (за исключением того, что они могут иметь имя, привязанное к себе локально внутри их тела; однако это не имеет отношения к рассматриваемой проблеме).

  • В Clojure действительно есть «макрос псевдонимов» - clojure.contrib.def / defalias :

     (используйте '[clojure.contrib.def: only [defalias]])
    (defalias foo bar)
    ; => foo теперь можно использовать вместо bar
    

    Преимущество этого метода перед (def foo bar) заключается в том, что он копирует поверх метаданных (таких как строка документации); похоже, он даже работает с макросами в текущем HEAD, хотя я помню ошибку, которая предотвращала это в более ранних версиях.

  • Варки называются символами, а не ключевыми словами. Символьные литералы в Clojure (и других Lisp) не начинаются с двоеточия (: foo - это ключевое слово, а не символ). Таким образом, чтобы определить функцию с именем foo , вы должны написать

     (defn foo [...] ...)
    
  • defn - это вспомогательный макрос, упрощающий создание новых переменных, содержащих функции, позволяя программисту использовать сочетание def и fn синтаксис.Итак, defn не может быть и речи для создания переменных с уже существующими значениями (которые могут быть функциями), как это требуется для создания псевдонимов; используйте вместо него defalias или просто def .

  • Чтобы создать вариативную функцию, используйте следующий синтаксис:

     (fn [x y & args] ...)
    

    x и y будут обязательными позиционными аргументами; остальные аргументы, переданные функции (любое их количество), будут собраны в последовательность и доступны под именем args . Вам не нужно указывать какие-либо «обязательные позиционные аргументы», если они не нужны: (fn [& args] ...) .

    Чтобы создать Var, содержащий вариативную функцию, используйте

     (defn foo [x y & args] ...)
    
  • Чтобы применить функцию к некоторым аргументам, которые вы собрали в seqable объект (например, args seq в приведенных выше примерах или, возможно, вектор и т. Д.), Используйте apply ]:

     (определить все? [& Аргументы]
     (применить каждые? args))
    
  • Если вы хотите написать функцию для создания псевдонимов - в отличие от макроса - вам необходимо изучить функции intern , with-meta , мета - и, возможно, разрешить / ns-resolve , в зависимости от того, должна ли функция принимать символы или Vars. Я оставлю заполнение деталей в качестве упражнения для читателя. : -)

17
ответ дан 3 December 2019 в 03:51
поделиться

Все, что вам нужно сделать, это привязать каждый? функция для всех? символ, который выполняется через def:

(def all? every?)

Подробнее об этом см. Макрос Clojure для создания синонима функции

6
ответ дан 3 December 2019 в 03:51
поделиться

Не думаю, что я могу здесь что-то добавить к существующим объяснениям, за исключением, возможно, заполнения пары пробелов в словаре путешественника Ruby по сбору аргументов и деструктуризации:

(defn foo [& args]                 ; Ruby: def foo(*args)
  (println args))    
user=> (foo 1 2 3)
(1 2 3)

(defn foo [& args] 
  (+ args))   
user=> (foo 1 2 3)
java.lang.ClassCastException       ; + takes numbers, not a list

(defn foo [& args] 
  (apply + args))                  ; apply: as Ruby proc.call(*args)
user=> (foo 1 2 3)
6

(defn foo [& args]
  (let [[a b & other] args]        ; Ruby: a, b, *other = args
    (println a b other)))
user=> (foo 1 2 3)
1 2 (3)
3
ответ дан 3 December 2019 в 03:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: