I can't get this to match. The match list is created programmatically and the list it is being matched against is stored in another list.
(match '((square ?)) '((square s)))
When I type the code into the repl, it works fine. The above is the printed result of the source command on the form that I build and then eval. When I eval in the repl, it gives me (s). When I eval in the code, it does not. Any ideas?
Works fine for me:
#!/usr/bin/newlisp
(set 'result (match '((square ?)) '((square s))))
(println "=>" result)
(exit)
and when I run it:
~> ./match
=>(s)
>
also tried inside a user defined function, and its fine. Can you isolate the problem in a small file?
Ok, here is the block of code that builds the list and then matches against it:
(setq *methods* '())
(define-macro (define-method)
(letex ((mtd (args 0 0))
(arglist (rest (args 0)))
(body (cons 'begin (rest (args)))))
(push (list 'mtd 'arglist 'body) *methods* -1)
(unless (lambda? 'm)
(set 'mtd (curry call-method 'mtd)))))
(define (arg-match arg-list , (lst '()))
(dolist (elt arg-list)
(if (and (list? elt) (context? (eval (first elt))))
(push (list (first elt) '?) lst -1)
(push '? lst -1)))
lst)
(define (method-lookup mtd-name arglist)
(catch
(begin
(dolist (mtd *methods*)
(let ((matcher (arg-match arglist))
(matchee (nth 1 mtd)))
(println (list 'match matcher matchee))
(if (and (= (first mtd) mtd-name)
(match matcher matchee)) ;; NOT MATCHING
(throw mtd))))
(throw-error "no matching method found"))))
Here is an example use of define-method (also showing another macro, define-class, that effectively does the same thing as the (cons (context) ...) FOOP constructor:
(define-class square ()
(len nil)
(wid nil))
(define-class cube (square)
(hgt nil))
(define-method (test (square s))
(+ (slot-value s 'len) (slot-value s 'wid)))
(define-method (test (cube s))
(+ (slot-value s 'len) (slot-value s 'wid) (slot-value s 'hgt)))
The idea is that define-method stores a function in *methods*. Each method that is defined for the same name has a signature which is used to look it up when the wrapper function is called. I.e., if test is called with s as an instance of square, it matches against the first definition. If it is called with a cube, it matches the second. The form (square s) in the argument list means that it is defined for squares and the variable will be s inside the function. Eventually, I'll add support for default values, commas, etc.
The signature is matched against by constructing a match list using the arguments called. Each argument is tested to see if it's a list and the first item is a context, which is good enough for me to assume it is an instance of a class. If it is, it is paired as (context-symbol '?) and appended to the overall match string.
That match string is then matched against the method signature.
PS this is exploratory code; don't expect good performance out of it :).
I found a clue. If I change arg-match to use (list '? '?) or (list 'square '?) instead of (list (first elt) '?) I get a match. Does that mean that the symbol representing a context cannot be used in match?
A context and a context symbol look the same but are different things:
> (context 'CTX) (context MAIN)
> (list CTX)
(CTX)
> (= (list CTX) '(CTX))
nil
> (= (list 'CTX) '(CTX))
true
> (symbol? (first (list CTX)))
nil
> (symbol? (first '(CTX)))
true
> (context? (first (list CTX)))
true
> (context? (first '(CTX)))
nil
> (context? (eval (first '(CTX))))
true
>
So depending how the list is constructed, you are looking at the symbol of a context or the context itself, both appear to be the same visually.
I tried doing applying quote to the context in arg-match, but that didn't work either (to quote the context symbol). Any idea how I can get this to work? The first argument to match is constructed in arg-match.
we posted at the same time ;-), read my previous post. You could do (eval (first elt)) to compare contexts.
Lutz,
Evaluating the context does not work either. I need to not only match the contexts but also the other arguments as well (although applying the method is not written yet). I finally got it to work with this arg-match:
(define (arg-match arg-list , (lst '()))
(map (lambda (elt)
(if (and (list? elt) (context? (eval (first elt))))
(list (sym (name (first elt))) '?) '?))
arg-list))
...and matching against the whole method entry, using (match (list mtd-name (arg-match arglist) '?) mtd), which just gives met the body of the function (although it needs to be converted to a lambda).