Re: Dotted pair call argument
Mark H Weaver writes: > David Kastrup writes: > >>> Scheme has a very useful property which your proposed syntax would >>> destroy: any valid expression can be substituted for any other valid >>> expression, and the result has the same meaning except for the >>> substitution. >> >> guile> (display . (close (current-output-port))) >> #guile> >> >> Now try >> >> (define x (close (current-output-port))) >> (display . x) > > Admittedly I could have been more clear, but I certainly didn't mean to > imply that anything that _looks_ like a valid expression can be > replaced. That would be absurd. Exactly. > What I meant is that any _subexpression_ can be replaced with any other > valid expression, without changing the meaning of the program in any > other way. So the solution would be to not call dotted pair endings of argument lists a "subexpression", and everybody will be happy. > Whether something is a subexpression depends on its _position_ within > the larger expression. Yes. That's the point. The dotted list end is a specific position. Not "subexpression" position. If a list is there, it is evaluated element by element. If a non-list is there, we get an error. Instead, I prefer evaluating it and using the evaluated result, whatever it may be, as the argument list tail. Personally, I would not even demand actual argument lists to be proper lists as long as the declared argument list is a dotted list as well: you can still match arguments then. > The only advantage I see to this proposed syntax is that in some > restricted cases it is more aesthetically pleasing. apply can't handle improper lists either. > I suspect that most experienced Schemers have at some point wondered > why dotted-tail notation is not allowed in procedure calls. I > certainly have, but upon further consideration I became convinced that > the pitfalls of adopting such an ambiguous and potentially confusing > syntax far outweigh the advantages. Nothing that is currently valid would change its meaning. -- David Kastrup
Re: Dotted pair call argument
David Kastrup writes: >> Scheme has a very useful property which your proposed syntax would >> destroy: any valid expression can be substituted for any other valid >> expression, and the result has the same meaning except for the >> substitution. > > guile> (display . (close (current-output-port))) > #guile> > > Now try > > (define x (close (current-output-port))) > (display . x) Admittedly I could have been more clear, but I certainly didn't mean to imply that anything that _looks_ like a valid expression can be replaced. That would be absurd. What I meant is that any _subexpression_ can be replaced with any other valid expression, without changing the meaning of the program in any other way. Whether something is a subexpression depends on its _position_ within the larger expression. In (display close (current-output-port)), even if you write it confusingly in dotted-tail notation, (close (current-output-port)) is _not_ a subexpression, because it is not in subexpression position. The only advantage I see to this proposed syntax is that in some restricted cases it is more aesthetically pleasing. I suspect that most experienced Schemers have at some point wondered why dotted-tail notation is not allowed in procedure calls. I certainly have, but upon further consideration I became convinced that the pitfalls of adopting such an ambiguous and potentially confusing syntax far outweigh the advantages. Thanks, Mark
Re: Dotted pair call argument
Mark H Weaver writes: > However, (f . (g x y)) is read as (f g x y), so it's impossible for > 'eval' to distinguish these two cases. Unfortunately, (f g x y) has a > very different meaning than (apply f (g x y)). The first means to apply > 'f' to three arguments. The second means to apply 'g' to two arguments, > and then apply 'f' to the list of arguments resulting from (g x y). Thanks, Mark. I've often wondered the same thing as David, so I appreciate your explanation. Neil
Re: Dotted pair call argument
Mark H Weaver writes: > David Kastrup writes: >> >> A list in dotted tail position is evaluated via (map ... eval) rather >> than (eval ...). I don't see much of a problem with that. > > No, it's worse than that. I think you failed to understand my point, > so let me try again. You propose that (f . x) should be equivalent to > (apply f x). When x is not a pair or (). > Therefore, (f . (g x y)) should also be equivalent to (apply f (g x > y)). But (g x y) is a pair. > To make this more concrete, suppose 'f' is 'vector and 'g' is 'list': > > (vector . (list 1 2)) (list 1 2) is a pair (with the car list and the cdr (1 2)). > If we were to adopt your proposal, users would naturally expect this to > evaluate to #(1 2). However, the evaluator sees (vector list 1 2) and > thus produces a vector of three elements: #(# 1 2). Sure. > In summary, your proposed syntax could only be detected if the dotted > tail happened to be an atom. () is an atom, but it is already treated differently. > Scheme has a very useful property which your proposed syntax would > destroy: any valid expression can be substituted for any other valid > expression, and the result has the same meaning except for the > substitution. guile> (display . (close (current-output-port))) #guile> Now try (define x (close (current-output-port))) (display . x) Good luck. The context already decides what a valid expression is. Not everything looking like one is treated like one. -- David Kastrup
Re: Dotted pair call argument
David Kastrup writes: > Mark H Weaver writes: > >> David Kastrup writes: >>> I guess my "real" problem is that I'd like to do call wrapping by writing >>> >>> (lambda ( . x) (fun . x)) >>> >>> instead of having to write >>> >>> (lambda ( . x) (apply fun x)) >>> >>> I assume eval is not supposed to try dealing with dotted lists? >> >> The problem is that (f . (g x y)) is equivalent to (f g x y). >> Therefore, while Scheme could in theory support procedure calls with a >> dotted tail that happened to be an atom, it would do something rather >> different and confusing if the dotted tail was itself a procedure/macro >> call. > > A list in dotted tail position is evaluated via (map ... eval) rather > than (eval ...). I don't see much of a problem with that. No, it's worse than that. I think you failed to understand my point, so let me try again. You propose that (f . x) should be equivalent to (apply f x). Therefore, (f . (g x y)) should also be equivalent to (apply f (g x y)). However, (f . (g x y)) is read as (f g x y), so it's impossible for 'eval' to distinguish these two cases. Unfortunately, (f g x y) has a very different meaning than (apply f (g x y)). The first means to apply 'f' to three arguments. The second means to apply 'g' to two arguments, and then apply 'f' to the list of arguments resulting from (g x y). To make this more concrete, suppose 'f' is 'vector and 'g' is 'list': (vector . (list 1 2)) If we were to adopt your proposal, users would naturally expect this to evaluate to #(1 2). However, the evaluator sees (vector list 1 2) and thus produces a vector of three elements: #(# 1 2). In summary, your proposed syntax could only be detected if the dotted tail happened to be an atom. Scheme has a very useful property which your proposed syntax would destroy: any valid expression can be substituted for any other valid expression, and the result has the same meaning except for the substitution. This property is desirable for many reasons. Users should be able to freely substitute expressions (possibly using a global find/replace operation, or via macros) without changing the meaning of the resulting expressions in surprising ways. Does this make sense? Mark
Re: Dotted pair call argument
David Kastrup writes: > Mark H Weaver writes: > >> David Kastrup writes: >>> I guess my "real" problem is that I'd like to do call wrapping by writing >>> >>> (lambda ( . x) (fun . x)) >>> >>> instead of having to write >>> >>> (lambda ( . x) (apply fun x)) >>> >>> I assume eval is not supposed to try dealing with dotted lists? >> >> The problem is that (f . (g x y)) is equivalent to (f g x y). >> Therefore, while Scheme could in theory support procedure calls with a >> dotted tail that happened to be an atom, it would do something rather >> different and confusing if the dotted tail was itself a procedure/macro >> call. > > A list in dotted tail position is evaluated via (map ... eval) rather > than (eval ...). I don't see much of a problem with that. > > It works fine for () as one can see: > guile> (+ . ()) > 0 > guile> > > So why not for others? I'll answer this a bit myself. Well, it does work for other lists. Cough, cough. The question is why it doesn't for non-lists. If (f . x) was supposed to be equivalent to (apply f x), then x would need to be evaluated. In (+ . ()), () itself is _not_ being evaluated. So this would be new behavior, and at least different from that of the non-pair (). I'm still not convinced that it would be a bad idea... -- David Kastrup
Re: Dotted pair call argument
Mark H Weaver writes: > David Kastrup writes: >> I guess my "real" problem is that I'd like to do call wrapping by writing >> >> (lambda ( . x) (fun . x)) >> >> instead of having to write >> >> (lambda ( . x) (apply fun x)) >> >> I assume eval is not supposed to try dealing with dotted lists? > > The problem is that (f . (g x y)) is equivalent to (f g x y). > Therefore, while Scheme could in theory support procedure calls with a > dotted tail that happened to be an atom, it would do something rather > different and confusing if the dotted tail was itself a procedure/macro > call. A list in dotted tail position is evaluated via (map ... eval) rather than (eval ...). I don't see much of a problem with that. It works fine for () as one can see: guile> (+ . ()) 0 guile> So why not for others? -- David Kastrup
Re: Dotted pair call argument
David Kastrup writes: > I guess my "real" problem is that I'd like to do call wrapping by writing > > (lambda ( . x) (fun . x)) > > instead of having to write > > (lambda ( . x) (apply fun x)) > > I assume eval is not supposed to try dealing with dotted lists? The problem is that (f . (g x y)) is equivalent to (f g x y). Therefore, while Scheme could in theory support procedure calls with a dotted tail that happened to be an atom, it would do something rather different and confusing if the dotted tail was itself a procedure/macro call. Mark