Reputation: 657
Assume I have an ad-hoc hierarchy of entities represented as Clojure keywords, like this:
(def h
(-> (make-hierarchy)
(derive :animal :feline)
(derive :feline :cat)
(derive :feline :lion)
(derive :feline :tiger)))
What would be the best way (preferably using clojure.core.match) to write a match-hierarchy
function so that these contrived examples return expected results:
(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
i.e., match-hierarchy
should return the value corresponding to the first clause whose elements are all either equal to the corresponding element of the value being matched, or its (direct or indirect) ancestors?
I'm happy with using something custom instead of make-hierarchy
to create the hierarchies. I'm also happy with not using core.match if another option is available. However, I need it to work with objects of pre-existing classes, like numbers (e.g., I want to be able to say 3
is a :positive-integer
is an :integer
is a :number
).
Background: I am writing a toy x86 assembler in Clojure, where I need to assemble my instruction based on its name and operands. Currently my code includes something like:
(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)})
(i.e., an INT instruction assembles to two bytes, 0xcd
followed by the interrupt number, unless it's an INT 3
in which case it's only one byte, 0xcc
). I find this somewhat ugly, however, and am looking for a more elegant approach. So instead I'd like to say something along the lines of
(asm-match [(-> instr name keyword) op1 op2]
;; other options
[:int 3 nil] {:opcode 0xcc}
[:int :imm nil] {:opcode 0xcd, :immediate (imm 8 op1)})
Upvotes: 2
Views: 357
Reputation: 18556
(match [(-> instr name keyword) op1 (operand-type op1) (operand-type op2)]
[:int 3 :imm nil] {:opcode 0xcc}
[:int _ :imm nil] {:opcode 0xcd, :immediate (imm 8 op1)})
Does this not work for you?
Upvotes: 4