1

Is there a good way to get a generic function to dispatch on the car of a list?

I've been working on a symbolic algebra program, and at the moment am storing a lot of data as lists with different keywords as the cars to indicate type. For example, I have simplices stored as '(:simplex #(0 1 2)), and I have something I'm calling steps for the time being stored as '(:step #(0 1 0 1)). I would like to be able to take the dimension and boundary of both of these, ideally using some built in dispatch mechanism.

Inaimathi
  • 13,853
  • 9
  • 49
  • 93
Riley
  • 982
  • 1
  • 7
  • 19

1 Answers1

3

Bit hacky, but you can do this with eql specialisers.

(defmethod foo ((first (eql :simplex)) (thing vector))
   <method body here>)

You'd then have to call that as either

(foo :step #(0 1 0 1))

or

(apply #'foo '(:step #(0 1 0 1)))

So, for your situation, you'd do something like

(defmethod dimension ((type (eql :simplex)) (thing vector))
  ;; calculate dimension of a SIMPLEX here
  )

(defmethod dimension ((type (eql :step)) (thing vector))
  ;; calculate dimension of a STEP here
  )

and the same for boundary.

If the things you're processing are really meant to be different structures, you might consider defining structs or classes instead of using raw lists. At that point, you could easily just define methods on the appropriate type, which would let you sidestep the awkward calling requirements of this approach.

Inaimathi
  • 13,853
  • 9
  • 49
  • 93
  • You probably meant `funcall` instead of `apply`. – acelent Jul 22 '14 at 20:24
  • 1
    @PauloMadeira - No, I meant `apply`; he's passing in a list whose first element he wants to dispatch on and whose second element is the vector he cares about. Give it a shot in the REPL. – Inaimathi Jul 22 '14 at 21:13