New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add implementation for Clojure-like multi-methods #7

Open
oubiwann opened this Issue Jul 11, 2015 · 1 comment

Comments

Projects
None yet
1 participant
@oubiwann
Member

oubiwann commented Jul 11, 2015

Usage should be something like this:

> (include-lib "los/include/multi-methods.lfe")
> (defmulti area 'type)
> (defmethod area 'rectangle
       ((`(#(length ,l) #(width ,w)))
         (* l w)))
> (area '(#(type triangle) #(base 2) #(height 4)))
  4.0

A non-macro version of this could be done in the following manner:

(defmodule polymorph
  (export all))

(defun area
  ((`(,type . ,rest))
   (dispatch 'area type rest)))

(defun dispatch
  ((fname `#(type ,type) args)
   (call (MODULE) (list_to_atom (++ (atom_to_list fname)
                                    "-"
                                    (atom_to_list type))) args)))

(defun area-triangle
  ((`(#(base ,b) #(height ,h)))
   (* b h (/ 1 2))))

(defun area-rectangle
  ((`(#(length ,l) #(width ,w)))
   (* l w)))

These could then be used in the following manner:

(c "examples/no-macros/polymorph.lfe")
#(module polymorph)
(slurp "examples/no-macros/polymorph.lfe")
#(module polymorph)
> (area '(#(type triangle) #(base 2) #(height 4)))
4.0
> (area '(#(type rectangle) #(length 2) #(width 4)))
8

Additional implementations could be added with ease:

(defun area-square
  ((`(#(side ,s)))
   (* s s)))

(defun area-circle
  ((`(#(radius ,r)))
   (* (math:pi) r r)))

Then use them:

> (area '(#(type square) #(side 2)))
  4
> (area '(#(type circle) #(radius 2)))
  12.566370614359172

See the following:

@oubiwann

This comment has been minimized.

Show comment
Hide comment
@oubiwann

oubiwann Jul 17, 2015

Member

Made some more progress on this tonight (see changes 7ea02cc and d218225). The following now works:

(defmulti area)
(defmulti perim)

(defmethod area 'triangle
  ((`#m(base ,b height ,h))
   (* b h (/ 1 2))))

(defmethod perim 'triangle
  ((`#m(base ,b height ,h))
   (+ b h (math:sqrt (+ (* b b)
                        (* h h))))))

(defmethod area 'circle
  ((`#m(diameter ,d))
    (area `#m(type circle radius ,(/ d 2))))
  ((`#m(radius ,r))
   (* (math:pi) r r)))

(defmethod perim 'circle
  ((`#m(diameter ,d))
    (perim `#m(type circle radius ,(/ d 2))))
  ((`#m(radius ,r))
    (* 2 (math:pi) r)))

With usage being simply this:

> (area #m(type triangle base 6 height 10))
30.0
> (perim #m(type triangle base 6 height 10))
27.6619037896906
> (area #m(type circle diameter 8))
50.26548245743669
> (perim #m(type circle diameter 8))
25.132741228718345

So far, the macros only support the rather trivial usage shown above, with the type hard-coded. The next steps are:

  1. Allow users to pass the attribute name in defmulti
  2. Support multiple attributes (for multiple dispatch)
Member

oubiwann commented Jul 17, 2015

Made some more progress on this tonight (see changes 7ea02cc and d218225). The following now works:

(defmulti area)
(defmulti perim)

(defmethod area 'triangle
  ((`#m(base ,b height ,h))
   (* b h (/ 1 2))))

(defmethod perim 'triangle
  ((`#m(base ,b height ,h))
   (+ b h (math:sqrt (+ (* b b)
                        (* h h))))))

(defmethod area 'circle
  ((`#m(diameter ,d))
    (area `#m(type circle radius ,(/ d 2))))
  ((`#m(radius ,r))
   (* (math:pi) r r)))

(defmethod perim 'circle
  ((`#m(diameter ,d))
    (perim `#m(type circle radius ,(/ d 2))))
  ((`#m(radius ,r))
    (* 2 (math:pi) r)))

With usage being simply this:

> (area #m(type triangle base 6 height 10))
30.0
> (perim #m(type triangle base 6 height 10))
27.6619037896906
> (area #m(type circle diameter 8))
50.26548245743669
> (perim #m(type circle diameter 8))
25.132741228718345

So far, the macros only support the rather trivial usage shown above, with the type hard-coded. The next steps are:

  1. Allow users to pass the attribute name in defmulti
  2. Support multiple attributes (for multiple dispatch)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment