Multimethods out of Nausicaa

Posted on May 25, 2016

More work in the ‘typed-languagebranch of Vicare, for both the expander and the built–in types infrastructure. Some more type propagation stuff is implemented for built–in syntaxes.

Everything I discuss here is relative to code in the head of the ‘typed-language’ branch.

Multimethods

I have ported the multimethods library from the Nausicaa language to the typed language implemented by (vicare). The main library is (vicare language-extensions multimethods), the documentation is in the node multimethods of the documentation file vicare-libs. I got pissed with myself while reviewing the documentation: there were still errors in there, even after the multiple reviews I did in the past. Life is hard without proofreaders.

So, what about multimethods? Every Lisper should know about them, and (s)he should know that they are dog slow. Here I will show only a simple program that makes use of multimethods and labels:

#!vicare
(program (demo)
  (options typed-language)
  (import (vicare)
    (vicare language-extensions multimethods)
    (vicare language-extensions labels))

  (define-label <list-coords>
    (nongenerative user:<list-coords>)
    (parent (list <flonum> <flonum> <flonum>))
    (method (x {O <list-coords>})
      (list-ref O 0))
    (method (y {O <list-coords>})
      (list-ref O 1))
    (method (z {O <list-coords>})
      (list-ref O 2)))

  (define-label <vector-coords>
    (nongenerative user:<vector-coords>)
    (parent (vector <flonum> <flonum> <flonum>))
    (method (x {O <vector-coords>})
      (vector-ref O 0))
    (method (y {O <vector-coords>})
      (vector-ref O 1))
    (method (z {O <vector-coords>})
      (vector-ref O 2)))

  (define-record-type <coords>
    (fields {x <flonum>}
            {y <flonum>}
            {z <flonum>}))

  (module (add)
    (define-generic-definer definer
      (operand-type-inspector
       (lambda (obj)
         (cond ((is-a? obj <list-coords>)
                (type-unique-identifiers <list-coords>))
               ((is-a? obj <vector-coords>)
                (type-unique-identifiers <vector-coords>))
               (else
                (type-unique-identifiers-of obj))))))

    (definer add (A B)))

  (define-method (add {A <list-coords>} {B <list-coords>})
    (list (fl+ (.x A) (.x B))
          (fl+ (.y A) (.y B))
          (fl+ (.z A) (.z B))))

  (define-method (add {A <vector-coords>} {B <vector-coords>})
    (vector (fl+ (.x A) (.x B))
            (fl+ (.y A) (.y B))
            (fl+ (.z A) (.z B))))

  (define-method (add {A <coords>} {B <coords>})
    (new <coords>
         (fl+ (.x A) (.x B))
         (fl+ (.y A) (.y B))
         (fl+ (.z A) (.z B))))

  (display (add '(1. 2. 3.) '(10. 20. 30.)))
  (newline)
  (display (add '#(1. 2. 3.) '#(10. 20. 30.)))
  (newline)
  (display (add (new <coords> 1. 2. 3.)
                (new <coords> 10. 20. 30.)))
  (newline)
  (flush-output-port (current-output-port))

  #| end of program |# )

after compiling it we run it:

$ vicare --verbose --compile-program demo.sps --output demo
vicare: expander warning: enabling typed language support for program
vicare: serialising program demo ...
vicare: done

$ ./demo
(11.0 22.0 33.0)
#(11.0 22.0 33.0)
#[record <coords> x=11.0 y=22.0 z=33.0]