Nano Hash - криптовалюты, майнинг, программирование

Как сделать запись из последовательности значений

У меня есть простое определение записи, например

(defrecord User [name email place])

Каков наилучший способ сделать запись со значениями в последовательности

(def my-values ["John" "[email protected]" "Dreamland"])

Я надеялся на что-то вроде

(apply User. my-values)

но это не сработает. В итоге я сделал:

(defn make-user [v]
  (User. (nth v 0) (nth v 1) (nth v 2)))

Но я чувствую, что есть лучший способ добиться этого...

22.12.2010

  • и добавить к ответам: 1. Взгляните на github.com/david-mcneil/defrecord2 предоставить некоторые дополнительные материалы. 2. Я думаю, что они планируют что-то подобное в будущих версиях clojure. 23.12.2010
  • В качестве примечания: вы можете использовать деструктурирующую привязку в своей функции-конструкторе. Только из косметических соображений. (defn make-user [[n e p]] (Пользователь. n e p)). 23.12.2010

Ответы:


1

Внимание: работает только для буквальных последовательностей! (см. комментарий Михала)

Попробуйте этот макрос:

(defmacro instantiate [klass values] 
        `(new ~klass ~@values))

Если вы расширите его с помощью:

(macroexpand '(instantiate User ["John" "[email protected]" "Dreamland"]))

вы получите это:

(new User "John" "[email protected]" "Dreamland")

что в принципе вам и нужно.

И вы можете использовать его для создания экземпляров других типов записей или классов Java. По сути, это просто конструктор класса, который принимает одну последовательность параметров вместо множества параметров.

22.12.2010
  • NB. это будет работать только в том случае, если макрос instantiate получает буквальную последовательность значений. Например. (def vals ["John" "[email protected]" "Dreamland"]), за которым следует (instantiate User vals), не будет работать. Плюс нельзя использовать макрос с apply. 23.12.2010
  • @Михал: Спасибо. Я не подумал об этом угловом случае. К счастью, в случаях, когда используется литерал, применять применять не нужно. 23.12.2010
  • Не то, чтобы мне это нужно, но я нашел неприятный способ, который работает и с небуквенным seqable — (defn instantiate [klass values] (eval (read-string (str "(new " (.getName klass) " " (let [s (str values)] (subs s 1 (- (.length s) 1))) ")")))) 22.01.2011

  • 2

    функция derecord создает скомпилированный класс с некоторыми неизменяемыми полями. это не правильные функции clojure (т.е. не класс, который реализует iFn). Если вы хотите вызвать его конструктор с помощью приложения (который ожидает iFun), вам нужно обернуть его в анонимную функцию, чтобы приложение могло его переварить.

    (apply #(User. %1 %2 %3 %4) my-values)

    это ближе к тому, с чего вы начали, хотя ваш подход к определению конструктора с хорошим описательным именем имеет свое очарование :)

    из API:

    Note that method bodies are
    not closures, the local environment includes only the named fields,
    and those fields can be accessed directy.
    22.12.2010
  • определенно нравится это больше, чем моя n-ая вещь ... но все же я должен отметить все ожидаемые аргументы ... я ищу какой-то общий способ, который можно было бы применить к любому определению записи ... если он есть ... 23.12.2010

  • 3

    Написание собственной функции-конструктора, вероятно, является выходом из положения. Как сказал Артур Ульфельдт, у вас есть функция, которую вы можете использовать как функцию (например, с apply), а не вызов конструктора Java-interop.

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

    (defn- default-user [name]
      (str (.toLowerCase name) "@example.com"))
    
    (defn make-user
      ([name] (make-user name nil nil))
      ([name place] (make-user name nil place))
      ([name user place]
         (when-not name
           (throw (Exception. "Required argument `name` missing/empty.")))
         (let [user (or user (default-user name))]
           (User. name user place))))
    
    (defn make-user-keyword-args [& {:keys [name user place]}]
      (make-user name user place))
    
    (defn make-user-from-hashmap [args]
      (apply make-user (map args [:name :user :place])))
    
    user> (apply make-user ["John" "[email protected]" "Somewhere"])
    #:user.User{:name "John", :email "[email protected]", :place "Somewhere"}
    
    user> (make-user "John")
    #:user.User{:name "John", :email "[email protected]", :place nil}
    
    user> (make-user-keyword-args :place "Somewhere" :name "John")
    #:user.User{:name "John", :email "[email protected]", :place "Somewhere"}
    
    user> (make-user-from-hashmap {:user "foo"})
    ; Evaluation aborted.
    ; java.lang.Exception: Required argument `name` missing/empty.
    
    22.12.2010

    4

    Одна простая вещь, которую вы можете сделать, это использовать деструктурирование.

    (defn make-user [[name email place]]
      (User. name email place))
    

    Тогда вы можете просто назвать это так

    (make-user ["John" "[email protected]" "Dreamland"])
    
    25.12.2010

    5

    Обновление для Clojure 1.4

    derecord теперь определяет ->User и map->User, следуя по стопам Горана, теперь можно

    (defmacro instantiate [rec args] `(apply ~(symbol (str "->" rec)) ~args))
    

    который также работает с небуквенными последовательностями, как в (instantiate User my-values). В качестве альтернативы, по аналогии с map->User можно определить функцию seq->User

    (defmacro def-seq-> [rec] `(defn ~(symbol (str "seq->" rec)) [arg#] (apply ~(symbol (str "->" rec)) arg#)))
    
    (def-seq-> User)
    

    что позволит (seq->User my-values).

    31.03.2013
  • Вы можете просто (apply ->User values); ->User — обычная функция. 28.10.2013
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..