Предположим, у меня есть специальная иерархия объектов, представленных как ключевые слова Clojure, например:
(def h
(-> (make-hierarchy)
(derive :animal :feline)
(derive :feline :cat)
(derive :feline :lion)
(derive :feline :tiger)))
Как лучше всего (желательно с использованием clojure.core.match ) написать функцию match-hierarchy
, чтобы эти выдуманные примеры возвращали ожидаемые результаты:
(defn example [x y]
(match-hierarchy h [x y]
[:cat :cat] 0
[:cat :feline] 1
[:cat :animal] 2
[:animal :animal] 3))
(example :cat :cat)
;=> 0
(example :cat :tiger)
;=> 1
(example :tiger :tiger)
;=> 3
т.е., match-hierarchy
должен возвращать значение, соответствующее первому предложению, все элементы которого либо равны соответствующему элементу сопоставляемого значения, либо его (прямым или косвенным) предкам?
Я счастлив использовать что-то нестандартное вместо make-hierarchy
для создания иерархий. Я также счастлив, что не использую core.match, если доступна другая опция. Однако он мне нужен для работы с объектами уже существующих классов, такими как числа (например, я хочу сказать, что 3
это :positive-integer
это :integer
это :number
).
Справочная информация : Я пишу сборщик игрушек x86 в Clojure, где мне нужно собрать инструкцию, основываясь на ее имени и операндах. В настоящее время мой код включает в себя что-то вроде:
(match [(-> instr name keyword) (operand-type op1) (operand-type op2)]
;; other options
[:int :imm nil] (if (= op1 3)
{:opcode 0xcc}
{:opcode 0xcd, :immediate (imm 8 op1)})
(т. Е. Инструкция INT собирается в два байта, 0xcd
с последующим номером прерывания, , если - это INT 3
, в этом случае это только один байт, 0xcc
). Однако я нахожу это несколько уродливым и ищу более элегантный подход. Поэтому вместо этого я хотел бы сказать что-то вроде
(asm-match [(-> instr name keyword) op1 op2]
;; other options
[:int 3 nil] {:opcode 0xcc}
[:int :imm nil] {:opcode 0xcd, :immediate (imm 8 op1)})