Named parameters
-
- Posts: 2038
- Joined: Tue Nov 29, 2005 8:28 pm
- Location: latiitude 50N longitude 3W
- Contact:
Named parameters
One thing I liked about AppleScript was the way you could supply named parameters for functions. I've been wondering whether it's possible to do something similar in newLISP.
The problem to be solved is when you write a function that has a fair few arguments and you'd prefer to not have to supply them in a specific order, but you'd be happy to label them in the function call.
I think the recent use of the colon in newLISP might prevent its use for this purpose?
The problem to be solved is when you write a function that has a fair few arguments and you'd prefer to not have to supply them in a specific order, but you'd be happy to label them in the function call.
I think the recent use of the colon in newLISP might prevent its use for this purpose?
Re: Named parameters
My attempt (just out of the text editor, not tested heavily):cormullion wrote:The problem to be solved is when you write a function that has a fair few arguments and you'd prefer to not have to supply them in a specific order, but you'd be happy to label them in the function call.
I think the recent use of the colon in newLISP might prevent its use for this purpose?
Code: Select all
(define-macro (defkey header)
(let (_makedef (fn (_x) (if (symbol? _x)
(list _x nil)
(list (_x 0) (eval (_x 1))))))
(letex ((Name (header 0))
(Default (map _makedef (1 header)))
(Body (cons 'begin (args))))
(define-macro (Name)
(letn ((_default 'Default)
(_arglist (args))
(_offset-nil (find ': _arglist))
(_offset-len (if _offset-nil _offset-nil (length _arglist)))
(_pos-default (0 _offset-len _default))
(_pos-arglist (0 _offset-len _arglist))
(_key-arglist (_offset-len _arglist)))
(map set (map first _default) (map last _default))
(map set (map first _pos-default) (map eval _pos-arglist))
(if (!= (% (length _key-arglist) 3) 0) (throw 'error))
(dolist (_triple (explode _key-arglist 3))
(local (_tag _key _val)
(map set '(_tag _key _val) _triple)
(if (!= _tag ':) (throw error))
(set _key (eval _val))))
Body)))))
Code: Select all
(defkey (f a (b 20) c)
(list a b c))
(f 10 :c (* 3 10))
With newLISP you can grow your lists from the right side!
Vote for named parameters!
I've playing with that once time before.
But there is a problem, and you can see it in your example just after typing 'f':
I found that this is very much code overhead, if that function will be called frequently.
So I've decide that there must be a sort of code preprocessor here, which will transform each combination of arguments used in a code to a short form of usage.
For ex: we have (f-internal a b c)
And (f :c 1) transforms to (f-internal nil nil 1) by preprocessor.
....but, if so, thinking in common, probably, here is a place for some engine that will allow to produce newlisp code from human-like language constructs.
But I have no idea here...
I've playing with that once time before.
But there is a problem, and you can see it in your example just after typing 'f':
Code: Select all
> f
(lambda-macro ()
(letn ((_default '((a nil) (b 20) (c nil))) (_arglist (args)) (_offset-nil (find
': _arglist))
(_offset-len
(if _offset-nil
_offset-nil
(length _arglist)))
(_pos-default (0 _offset-len _default))
(_pos-arglist (0 _offset-len _arglist))
(_key-arglist (_offset-len _arglist)))
(map set (map first _default) (map last _default))
(map set (map first _pos-default) (map eval _pos-arglist))
(if (!= (% (length _key-arglist) 3) 0)
(throw 'error))
(dolist (_triple (explode _key-arglist 3))
(local (_tag _key _val)
(map set '(_tag _key _val) _triple)
(if (!= _tag ':)
(throw error))
(set _key (eval _val))))
(begin
(list a b c))))
So I've decide that there must be a sort of code preprocessor here, which will transform each combination of arguments used in a code to a short form of usage.
For ex: we have (f-internal a b c)
And (f :c 1) transforms to (f-internal nil nil 1) by preprocessor.
....but, if so, thinking in common, probably, here is a place for some engine that will allow to produce newlisp code from human-like language constructs.
But I have no idea here...
WBR, Dmi
There is exactly one of the points of common newlisp critique from CL party: we have no macros. What is called "macro" in newlisp is called f-expr in most other lisps. I myself have found newlisp good enough for me, but there is a sad true here: no "before execution" time macro transformer.Dmi wrote:I found that this is very much code overhead, if that function will be called frequently.
So I've decide that there must be a sort of code preprocessor here, which will transform each combination of arguments used in a code to a short form of usage.
With newLISP you can grow your lists from the right side!
CL is a preprocessed and compiled language. Creating something like named parameters in an interpreted language creates a lot of overhead during runtime.
Any macro compiling or preprocessing would take away from the dynamic character of the language. But using the new reader function (renamed 'read-expr' in 9.3.3) you could write a preprocessor and create your own language (in between the limits of newLISP syntax and parser).
Any macro compiling or preprocessing would take away from the dynamic character of the language. But using the new reader function (renamed 'read-expr' in 9.3.3) you could write a preprocessor and create your own language (in between the limits of newLISP syntax and parser).
<I've forgot the name>'s law: complex enough program written in any language contains a lisp interpreter inside.Lutz wrote:you could write a preprocessor and create your own language
<I've forgot the name too>'s corollary: including programs written in lisp.
With newLISP you can grow your lists from the right side!
-
- Posts: 394
- Joined: Wed Apr 26, 2006 3:37 am
- Location: Oregon, USA
- Contact:
Based on the work followed by the OCaml developers, we may find that keyword arguments go hand-in-hand with default arguments.
I've been playing with passing associations using the form '(parameter value) and then parsing (args) with assoc. Still working on it.
Here is something else with less overhead:
Default arguments will not work with this method, as newLISP uses the nil argument instead of the default.
Just another tool in the toolbox ;-)
m i c h a e l
I've been playing with passing associations using the form '(parameter value) and then parsing (args) with assoc. Still working on it.
Here is something else with less overhead:
Code: Select all
> ;; first, a demo function:
(define (f a b c) (cons (or a 1) (dup (list (or b 2) (or c 3)))))
(lambda (a b c) (cons (or a 1) (dup (list (or b 2) (or c 3)))))
> ;; notice how the function was defined in respect to the arguments
>
> ;; using the function in the usual way:
> (f)
(1 (2 3) (2 3))
> (f 9)
(9 (2 3) (2 3))
> (f 9 8 7)
(9 (8 7) (8 7))
> ;; what if we wanted to supply the third argument and default the first two?
> ;; our function definition allows us to do this:
> (f nil nil 9)
(1 (2 9) (2 9))
> ;; and to make it shorter and more attractive, we could do this:
> (set '_ nil)
nil
> (f _ _ 8)
(1 (2 8) (2 8))
>
Just another tool in the toolbox ;-)
m i c h a e l
-
- Posts: 2038
- Joined: Tue Nov 29, 2005 8:28 pm
- Location: latiitude 50N longitude 3W
- Contact:
Oh well, no worries. I was thinking mainly of the 'ease of use' angle - although that never comes without a corresponding price to be paid. I just like the idea of not having to remember the arguments in the correct order every time.Lutz wrote:Creating something like named parameters in an interpreted language creates a lot of overhead during runtime.
The nearest I've got to what I want was
Code: Select all
(define (func aslist)
(letn ((l (lookup 'len aslist))
(w (lookup 'width aslist))
(h (lookup 'height aslist)))
(println {len is } l )
(println {width } w)
(println {height } h)
))
(func '((width 20) (len 10) (height 30)))
len is 10
width 20
height 30
this one avoids the extra pair of parenthesis and quote:
ps: added the true flag, which was introduced later in 9.4.5. This insures that parameters are evaluated:
Code: Select all
(define-macro (foo)
(local (len width height)
(bind (args) true)
(println "len:" len " width:" width " height:" height)
))
> (foo (width 20) (height 30) (len 10))
len:10 width:20 height:30
Code: Select all
> (foo (width (+ 15 5)) (height 30) (len 10))
len:10 width:20 height:30
Last edited by Lutz on Tue Dec 02, 2008 5:29 pm, edited 1 time in total.
The problem with that is that the arguments bound within the function are bound externally to the function. You could use the same technique I used in destructuring-bind:
Using letex and let together to create a valid let param-list:
The real solution is to use a factory function that would expand a function body to the above.
Code: Select all
(define-macro (destructuring-bind)
(letex ((unifier (args 0))
(target (args 1))
(body (rest (rest (args)))))
(let unifier
(bind (unify 'unifier 'target))
(dolist (expr 'body)
(eval expr)))))
Code: Select all
(define (foo)
(letex ((arg-list (args)))
(let arg-list
(println x)
(println y))))
(foo '(x 1) '(y 2))
Wow, I say what I've said in another topic :Lutz wrote:this one avoids the extra pair of parenthesis and quote:
ps: or use (apply set (flat (args))) instead of (bind (args)), if assignments have to be evaluated.Code: Select all
(define-macro (foo) (local (len width height) (bind (args)) (println "len:" len " width:" width " height:" height) )) > (foo (width 20) (height 30) (len 10)) len:10 width:20 height:30
With newLISP ...
:)... in any case we can get through!
That's right, but not exactly, bacause of nature of newlisp.Cyril wrote: There is exactly one of the points of common newlisp critique from CL party: we have no macros. What is called "macro" in newlisp is called f-expr in most other lisps. I myself have found newlisp good enough for me, but there is a sad true here: no "before execution" time macro transformer.
In fact we can already have a preprocessor that can parse already loaded context, using (symbols) etc. and transform any sequences of symbols and values into newlisp-compatible function calls. And no (reader) needed here despite it's great improvement either.
The bad news is that there's no stable and useful concept & technics for such transformations yet.
WBR, Dmi
-
- Posts: 2038
- Joined: Tue Nov 29, 2005 8:28 pm
- Location: latiitude 50N longitude 3W
- Contact:
I like this solution - it's idiomatic but short and easy to remember and doesn't require pre-definitions. Will try it out. Thanks!Jeff wrote:Using letex and let together to create a valid let param-list:
Code: Select all
(define (foo) (letex ((arg-list (args))) (let arg-list (println x) (println y)))) (foo '(x 1) '(y 2))
Another solution with default arguments :
output:
:)
Code: Select all
(define (func)
(letn (lst (if (args) (first (args)))
a (or (lookup 'a lst) 10)
b (or (lookup 'b lst) 10)
c (or (lookup 'c lst) 10))
(println "a: " a )
(println "b: " b)
(println "c: " c)))
(func '((b 20) (c 40) (a 30)))
(func '((c 100)))
(func)
Code: Select all
a: 30
b: 20
c: 40
a: 10
b: 10
c: 100
a: 10
b: 10
c: 10
And even better :
Code: Select all
(define (func)
(letn (lst (args)
a (or (lookup 'a lst) 10)
b (or (lookup 'b lst) 10)
c (or (lookup 'c lst) 10))
(println "a: " a )
(println "b: " b)
(println "c: " c)))
(func '(b 20) '(c 40) '(a 30))
(func '(c 100))
(func)