Return Entire Thread First 100 Posts Prev 100 Next 100 Last 50 Posts Report Thread Style: Yotsuba, Pseud0ch, Terminal

Pages: 1-

Keyword arguments in R7RS


Things are getting spicy.
Neil Van Dyke
To get the keyword arguments discussion started, I'll provide a quick,
loosely-defined strawperson...
* Keywords look like ":foo", "foo:", or "#:foo", depending on your dialect.
* The main use of keywords is to name "keyword arguments" in procedure
applications and syntax uses, such as for optional arguments or for clarity.
* "lambda" is extended to permit keyword arguments to be defined, each
of which argument may have a default value.  The argument is optional
iff a default value was defined.
* The various syntax definition forms should permit syntax transformers
to be keyword-aware as well.
* Example:
(define f (lambda (a b c (:foo 42) :bar)  foo))
(f 1 2 3 :foo 4 :bar 5) ==> 4
(f 1 2 3 :bar 5) ==> 42
(f 1 2 3) =error=> :bar keyword argument required
(f 1 2 3 :foo 4 :bar 5 :zoo 6) =error=> unrecognized keyword :zoo
* Note: If keywords are first-class values, and you want to pass a
keyword as an argument in an application in a position in which it might
be parsed as a keyword, you cannot put  a keyword literal into the
application syntax directly.
* I probably wouldn't have keyword arguments in WG2, but their
implementation in WG2 would likely impose requirements on WG1.

Working Group 1 thread:
Working Group 2 thread:

...what do the resident clispers in prague think? Should they exist in the core language or should we have a supplementary (i.e. "defun" in all its glory) macro for WG2 Scheme?


As a CLer, I think keyword arguments are very useful(among the other lambdalist arguments such as &optional and&rest(well, you can write it using dot notation too)) in writing highly-parametrized functions and reducing boilerplate code.

If CL didn't have them, they would be trivial to implement with macros and compiler-macros - the other needed component being a destructuring-bind, but that can also be written portably.

I'm not sure how hard would be to add support for them as a library in Scheme, but probably wouldn't be terribly hard.

There is one major advantage to having the language include native support for them: people will use them everywhere, which shapes your language and implementation as well as how other people write code. If they are not included in the language specification, then less people will use them in actual code.


depending on your dialect.


You forgot the Scheme standardization litmus test: can a student implement it into an interpreter in less than a week?


Implementing R6RS is already quite a bit of work.
You can implement keyword arguments in some 2-3+ pages of code.


R7RS Discussion? On my /prog/?

My take:
- Just fucking standardise parameters already
- Only syntax-rules in "core" scheme, I'd vote for syntax-case in "big" scheme
- Allow for Ascii-only implementations, but the unicode spec should be followed if you want to support any additional characters.
- Records should be their own types (this could be built on a base make-disjoint-type procedure) and by default should require you to specify the names of the accessors/mutators/predicates. Implementations could provide their own way to build records that generate names using non-hygienic macros, or this could be a standard library.


The whole concept of parameter *objects* are nice (i.e. you don't want to carry around dynamic bindings, too) but goddamn I want to dismember whoever thought of that name.


There was an attempt to make a portable library for Keyword Arguments (srfi 88) and Optional Positional and Named Parameters (srfi 89), but they are only supported by 5 and 3 schemes respectively.


Indeed, but its a standard name by now, and is used by virtually everyone.


Freakin' transput was a standard name in ALGOL 68 and look where it is now. If we're going to pisstake off it we can at least pull a T and rename it for posterity.


This is the Scheme community we are talking about, if we don't use that name, then we are probably never going to standardise it. I also kind of like parameterize


I can only see this useful if you're writing functions with huge numbers of optional parameters. Otherwise it just makes the code more verbose.


Making the code more verbose isn't inherently a bad thing, It can be useful if it makes the code more clear. I mean what does point(1,2,3); mean? Does it mean that it has three co-ordinates, or does it have 2 and say a color value of 3? How can we know without looking at the documentation? The order of the parameters isn't always useful in determining what a function means. It may be more illuminating to have point(x=1,y=2,z=3); or point(x=1, y=2, color=3); or indeed point(x=1, color=2, y=3. Now, we no longer need to know the argument order.
To take a more schemey example, the function number->string takes a number and an optional radix.
(number->string 12) ;=>"12"
(number->string 12 2) ;=>"1100"
If we imagine we wanted a more general number->string that takes one or more numbers and e.g. converts all the numbers and then concatentates them, then the logical extension would be to add more parameters to the end with a dotted list. But then we have a problem that if we want to take 2 or more numbers we need to supply the radix i.e.
(number->string 12 2) ;=>"1100" not what we want
(number->string 12 10 2) ;=> "122"
This requires extra arguments and makes the resulting code less clear. If radix was always a keyword parameter, then we could write
(number->string 12 2) ;=>"122"
(number->string 12 2 #:radix 2) ;=> "110010"

The important thing is not "How verbose is this", but "how readable is this".


Seems more intuitive to me, arguments or their handling routines can be easily misplaced. Why you can't retain the old form and keep these parameters too?


Do you mean "why can't we have both point(1,2,3) and point(z=3,x=1,y=2)"?
In some languages you can. I'm agnostic as to whether named parameters should always be named.


Here's a few examples:

These functions all have copious keyword arguments, but usually you want to specify either none in the simplest case, or one or two, or maybe all of them in some rare case. I've encountered all these situations in practice.
Specifying what you only need can reduce the amount of code your write in the case you only need a few keword arguments, and will increase readability/documentation in the rest. It's also useful if you care less about the order of arguments and more about their meaning.

In the case of complex interfaces packaged under a single function, keyword arguments are the solution. Just imagine what would Win32 API be if they would have used something like keyword arguments - no more NULL, NULL, NULL, NULL.


Those who do not understand OOP are condemned to reinvent it, poorly.


And what do keyword arguments have to do with OOP?and scheme already has reinvented OOP at least 15 times


I don't see what keyword arguments have to do with OO.
Why would you need to create an object/structure just so you could pass some parameters. Keyword arguments are much more lightweight and usually faster.
CL and Scheme already have fairly advanced OO facilities (CLOS+MOP are already far from anything you get in modern OO languages when it comes to features).

One should not confuse keyword/optional/rest arguments with what those in lesser OO systems do to get similar functionality: They make an object, add the fields for the parameters they want, and then make a dozen ugly constructors for every combination of arguments they prefer(overloaded). You then need an IDE to actually be able to properly create an instance of that object. That doesn't seem proper at all to me.

Speaking of keyword arguments and OO, initializing a structure in CL is done via keyword arguments, and making a new instance of a class is done that way too:
(make-instance 'class-name :initarg1 value-of-init-arg1 :initarg2 value-of-init-arg2)
(make-instance 'circle :radius 5 :color :red)

A structure:
(defstruct circle radius color)
(make-circle :radius 6 :color 'my-own-personal-brand-of-green)


Keyword arguments are messy but useful; I'd support them in WG2 but not WG1. One fundamental problem with keywords is that they don't obey lexical scope, and that always causes name clashes as soon as you start to combine things. I like SRFI 39 because it obeys lexical scope, and you can use parameters like keyword arguments in many situations. I would welcome SRFI 39 to WG1 and WG2, but it's not essential like SRFI 9.
While keyword arguments probably won't make it in WG1, optional arguments might. Riastradh has a nice proposal at <>;.


Could you explain how they don't obey lexical scope or cause name clashes? Some examples maybe?
I'm only familiar with them from CL, I don't know how different they are in Scheme than in CL. In CL, keywords are plain old symbols which lie in the KEYWORD package, which can be thought of as having an empty nickname, so you can write :some-keyword and the name would get interned(if it didn't exist) in said KEYWORD package. When you use a keyword, you do pollute said KEYWORD package, but that's not really a problem, as that's the intended purpose of the package - to simply store global names which can be used anywhere, as opposed to symbols which are interned in the current *package* or some other package. #:symbol is an uninterned symbol and (eq '#:symbol '#:symbol);=> NIL, but (let ((sym '#:symbol)) (eq sym sym)) ;=> T.

Keyword arguments could be implemented portably by just taking the entire argument list and destructuring it(or a limited form of destructuring, depending on what you're defining - a function, a macro, ...) according to its lambda list. Of course compilers are free to implement this much more efficiently, in ways that don't involve consing up argument lists (such as defining a compiler macro which does the destructuring at compile-time when possible (always possible except in cases of FUNCALL/APPLY usage) and calling a function/lambda with a constant number of args - this optimization is applicable for optional args as well).

What I'm confused about is where the problem you mentioned lies. The only problem I can see with keywords is that in CL, they require a junk package to be implemented, but if you think about it, there's nothing wrong about it, as long as you don't use keywords for other things than what they're meant to be used for.


Oh, and of course, when interning a symbol in the keyword package, its value is set to itself, thus it's becomes a self-evaluating symbol.


I don't know much about the existing alternatives, but I just want an alternative datum syntax for symbols and a standard destructuring method, really. Having qualified symbols evaluate to symbol data smells like a bad hack.


It actually does make sense. That's what self-evaluating symbols are. Keywords are self-evaluating. Think about it, if a symbol is self-evaluating, what value should you get when you evaluate one, eh? Of course, if keywords were not self-evaluating, all you would have to do is quote them ':kwd.


Someone ask The Sussman to propose GJS Jay Sussman Feat. JSB Sebastian Bach - We conjure the spirits of the computer with our spells as official theme song for Scheme.


He's in WG1, you have to ask the Steering Committee


See Shinn for a quick round-up of the semantics of keywords:

Alex Shinn:
Brian Harvey...
We don't actually need to make any such request, since the
WG2 charter requires that any valid WG1 program be a valid
WG2 program.  If :foo and foo: are symbols in WG1, they must
be symbols in WG2.

Of course, this could still work if WG2 keywords were in
fact symbols, and thus usable as identifiers.  But in
addition to syntactic differences, implementations seem to
disagree greatly on the actual semantics of keywords.

In both Chicken and Kawa, keywords are semantically a
special type of self-quoting symbol.  symbol? returns #t for
them, and you can bind values to them with define (but then
not be able to access those values directly).

In the other implementations, keywords are fully disjoint
from symbols.

In PLT unquoted keywords are not first-class:

(list #:foo)

stdin::0: application: missing argument expression after keyword at: #:foo in: (#%app list #:foo)

(list #:foo #t)

list: does not accept keyword arguments; arguments were: #:foo #t

You need to quote them:

(list '#:foo)


These semantic differences seem much more problematic than
any syntactic concerns.


there, problem solved


Consider the following wrapper:

(define (increase-counter s)
  (display "Increasing counter ") (display s) (newline))

(define (wrap-with-counter f default-name)
  (lambda (#:name (name default-name) . rest)
    (increase-counter name)
    (apply f rest)))

This works fine until I try to combine it with the following totally unrelated procedure, which may be in a different library.

(define (create-object #:name (name "default object name"))
  (list 'object name))

I cannot solve this without changing one of them. I cannot import one of the keywords with a different name like I can with an SRFI 39 parameter. The two keywords are the same even though they obviously shouldn't be, just because they happen to use the same name.


I agree, named parameters can be a little more clear when reading the code, but that also means every time you use a function you'll have to remember the exact names of the parameters, not just their purpose.


these stupid R(6 and onwards)RS fucks should just learn common lisp and stop destroying scheme.


Then use WG1 R7RS, it's got the Sussman


Right. Which means it's not even a solution


The names don't propagate through the different expressions, they are only valid in the originating lambda. I don't think anyone would propose keyword arguments be bound dynamically.
This is true. Are you arguing that this makes them worse? It's a different solution, but not a worse one.
While it's a shame how R6RS turned out, I don't think it's fair to crucify R7RS at this early stage. At least wait until they have presented something more tangible than a bunch of ideas.
That depends on the question. There is no complete solution to the problem of having to remember function arguments order/keyword names, other than to use some generous IDE. And this isn't even a complete solution in languages which encourage the use of first class procedures.


No propagating seriously hampers the use of keywords and it's not what PLT, SBCL, SRFI 89 and Chicken (DSSSL) do.
On the other hand it avoids my lexical scoping point and it makes optimization trivial.


Are you GAY?
Are you a NIGGER?
Are you a GAY NIGGER?

If you answered "Yes" to all of the above questions, then GNAA (GAY NIGGER ASSOCIATION OF AMERICA) might be exactly what you've been looking for!

Newer Posts

Name: Email:
Entire Thread Last 50 Posts First 100 Posts Thread List Report Thread