Re: Dotted pair call argument

2012-02-22 Thread David Kastrup
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

2012-02-21 Thread Mark H Weaver
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

2012-02-21 Thread Neil Jerram
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

2012-02-21 Thread David Kastrup
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

2012-02-21 Thread Mark H Weaver
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

2012-02-21 Thread David Kastrup
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

2012-02-21 Thread David Kastrup
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

2012-02-21 Thread Mark H Weaver
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