It would be nice in 8.0 or later for the un-evaluated 'exp-n' values in 'case' be allowed to have muliple values in, say, the form of lists. For example,
This is a bit round about but uses a lambda-macro to accept conditions as a string of conditions that can have multiple matches defined.
The functions expandit converts ((1 2 3) 4) into ((1 4) (2 4) (3 4))
or (3 4) into ((3 4)). Expander goes throgh a list of such conditions and expands them with expandit and appends them together. Mycase is a lambda macro that uses expander to make a case statement that is then eval'ed.
So
> (mycase "diane" ( (("bob" "mary" "susie") 'friend) (("tim" "diane") 'boss) ("sam" 'self) ("sammo" 'clever-alias) (true 'stranger) ))
boss
>
As macro don't evaluate the list of conditions is an unquoted list.
I don't think newlisp handles indeterminate length parameter lists eg like lisp does with &rest keyword so conditions must be lumped into one list.
re my comment:
I don't think newlisp handles indeterminate length parameter lists eg like lisp does with &rest keyword so conditions must be lumped into one list.
I've found the args fn for define-macro - I'll try recasting the functions using this.
Nigel
Yes, feel free. However, the definition of expander seems a bit ham fisted - now that args is in the picture there may be a better way of iterating through the conditions that need expansion - but I can't see it.
I tried (map but it puts the expanded conditions one level too deep in the list. Use it as it is but "Improvements are left as an exercise for the student".
Thanks for your kind comment.
Regards
Nigel
When newLISP would compare 'name' it would compare with each expression, including lists, so imagine 'name' is the list: '("bob" "mary" "susie"), so there is no way to handle 'case' with the old syntax but multiple constants for one case-level.
The only thing possible would be to have only the last element in the list be the returned-evaluation:
(case name
("bob" "mary" "susie" body-expression)
....
But at this moment all functions in newLISP which take body expressions for evaluation, like "case", "dotimes", "dolist", "cond", "while" etc. can take multiple body expressions and the last one is the return value:
(case name
("bob" body-1 body-2 body-3) ; evaluation of body-3 gets returned
....
this saves (begin ... ) blocks and would have to be given up to allow multiple switch constants.
We could have a new function 'translate':
(translate name '((bob mary susie friend) (tim diane boss)) 'stranger)
Basically an 'assoc' with variable length sublists and an optional default return. To make this thing small and fast, nothing inside the association list would be evaluated, it would be all constants. In a way this would be a cousin of 'lookup'. 'lookup' has multiple return values in the asssociation, while 'translate' has multiple key values in the association.
Hello
1)RE:
When newLISP would compare 'name' it would compare with each expression, including lists, so imagine 'name' is the list: '("bob" "mary" "susie"), so there is no way to handle 'case' with the old syntax but multiple constants for one case-level.
- true the suggested case variant - and mycase macros - will not allow a list as a (first of a condition
2)RE:
(case name
("bob" body-1 body-2 body-3) ; evaluation of body-3 gets returned
....
this saves (begin ... ) blocks and would have to be given up to allow multiple switch constants.
I don't see that it is given up. The expandit approach of mycase just pastes the (rest onto expanded list items thus:
How about this for a suggested case variant along sammo's lines
(case x (match1? target1 body1) (match2? target2 body2 body3))
Where quoted x - so it can be ("billy" "bones") or "bill" or 2 - is compared with target using specified function match? , if true do bodies.
I've constructed a mycase4 along these lines viz:
# to make a list of length n of repeated quoted elements x
(define (makelistq x n , z) (begin (setq z '()) (for (i 1 n) (setq z (append (list (list 'quote x )) z))) z))
# macro to construct a (cond element that will act as above
(define-macro (makecondeval _x _y) (list (append (list (first (eval _y))) (list (eval _x)) (list (first (rest (eval _y))))) (append (list 'begin ) (rest (rest (eval _y))))))
# macro to string things together to construct and eval a full (cond
# the print is to show what is happening
(define-macro (mycase4 _x) (eval (print (append (list 'cond) (map makecondeval (makelistq (first (args)) (length (rest (args)))) (rest (args)))))))
example of use is:
> (mycase4 "gus" (member '("jak" "sam") 'boss) (= '("billy" "bones") 'friend) (member '("erol" "gus") 'foe))
(cond
((member (quote "gus") '("jak" "sam"))
(begin
'boss))
((= (quote "gus") '("billy" "bones"))
(begin
'friend))
((member (quote "gus") '("erol" "gus"))
(begin
'foe)))foe
Note targets should be quoted if not want evaluation.
for multiple comparisons use member
for list compared to list etc use =
construct any predicate you like for full control
without printing it is:
(define-macro (mycase4 _x) (eval (append (list 'cond) (map makecondeval (makelistq (first (args)) (length (rest (args)))) (rest (args))))))
Below is a captured output with some examples.
A bit of a long post but explaining was hard.
Regards
Nigel
Working all in one place:
newLISP v7.4.0 Copyright (c) 2004 Lutz Mueller. All rights reserved.
> (define (makelistq x n , z) (begin (setq z '()) (for (i 1 n) (setq z (append (list (list 'quote x )) z))) z))
(lambda (x n , z)
(begin
(setq z '())
(for (i 1 n)
(setq z (append (list (list 'quote x)) z))) z))
> (define-macro (makecondeval _x _y) (list (append (list (first (eval _y))) (list (eval _x)) (list (first (rest (eval _y))))) (append (list 'begin ) (rest (rest (eval _y))))))
Hi Sammo
Thanks for fixing expander to make it a lisp function rather than the iterative hack it was before - it never felt right. I don't have proper use of apply in my skills so I'll learn to use it.
Glad you found my thoughts a helpful starting point.