Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lambda... again

45 views
Skip to first unread message

yuriy....@gmail.com

unread,
Oct 22, 2007, 6:48:33 PM10/22/07
to
Yes, I have read about it
http://wiki.tcl.tk/519
http://wiki.tcl.tk/10782

Why didn't anyone use this obvious variant?

proc lambda {p b} {
set name [list lambda $p $b]
if {[info procs $name] eq ""} {
proc $name $p $b
}
return $name
}

General lambda use cases work well:

% [lambda {s1 s2} {puts "s1=$s1 s2=$s2"}] asd cvb
s1=asd s2=cvb

% set aaa [lambda {s1 s2} {puts "s1=$s1 s2=$s2"}]
lambda {s1 s2} {puts "s1=$s1 s2=$s2"}
% $aaa q w
s1=q s2=w

Something wrong?

sleb...@gmail.com

unread,
Oct 22, 2007, 9:22:27 PM10/22/07
to
On Oct 23, 6:48 am, yuriy.ers...@gmail.com wrote:
> Yes, I have read about ithttp://wiki.tcl.tk/519http://wiki.tcl.tk/10782

>
> Why didn't anyone use this obvious variant?
>
> proc lambda {p b} {
> set name [list lambda $p $b]
> if {[info procs $name] eq ""} {
> proc $name $p $b
> }
> return $name
>
> }
>
> General lambda use cases work well:
>
> % [lambda {s1 s2} {puts "s1=$s1 s2=$s2"}] asd cvb
> s1=asd s2=cvb
>
> % set aaa [lambda {s1 s2} {puts "s1=$s1 s2=$s2"}]
> lambda {s1 s2} {puts "s1=$s1 s2=$s2"}
> % $aaa q w
> s1=q s2=w
>

Personally I think the [apply] method that we now have in 8.5 is the
way to go. Lambdas are after all merely values. So there is no reason
to treat a lambda as anything other than a string until you want to
use it as a function. So:

# In tcl a lambda is simply a string:
set aaa {{s1 s2} {puts "s1=$s1 s2=$s2"}}

# Only when you want to use it does it need special treatment:
apply $aaa q w

The advantage is that unlike the proc work-arounds the apply method
has all the advantages of regular variables: local scope, passable as
first class citizens etc.

The disadvantage is that calling a lambda is different from calling a
regular proc (you need to prepend apply to it). Now... if someone
feels like modifying [unknown] so that lambdas can be called like a
proc..... ;-)

suchenwi

unread,
Oct 23, 2007, 3:32:41 AM10/23/07
to
On 23 Okt., 03:22, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:

>
> The disadvantage is that calling a lambda is different from calling a
> regular proc (you need to prepend apply to it). Now... if someone
> feels like modifying [unknown] so that lambdas can be called like a
> proc.....

Oh, that's easily done:
% proc know what {
if ![info complete $what] {error "incomplete command(s) $what"}
proc unknown args $what\n[info body unknown]
}
% know {
if {[llength [lindex $args 0]]==2} {return [eval [linsert $args 0
apply]]}
}
% set try {{a b} {expr {$a * $b}}}
{a b} {expr {$a * $b}}
% $try 7 6
42
It just conflicts with spaces in command names, so don't do both... :^)

sleb...@gmail.com

unread,
Oct 23, 2007, 4:00:37 AM10/23/07
to
On Oct 23, 3:32 pm, suchenwi <richard.suchenwirth-

HA! Now that we have this we can TRULY treat everything as a string.
Proc is no longer necessary. Just store everything in variables!

OTOH since variables are locally scoped writing tcl code in pure
lambdas is going to be annoying:

set something {{} {
global do_something print ;# must "import" all lambdas before
using :-(
$do_something here
$print Done!
}}

set do_something {{x} {
global print ;# typing global all the time quickly gets annoying
$print "doing something: $x"
}}

set print {x {puts "$x\n"}}

$something

suchenwi

unread,
Oct 23, 2007, 4:09:34 AM10/23/07
to
On 23 Okt., 10:00, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
> HA! Now that we have this we can TRULY treat everything as a string.
> Proc is no longer necessary. Just store everything in variables!

See http://wiki.tcl.tk/5892 "If we had no proc"


>
> OTOH since variables are locally scoped writing tcl code in pure
> lambdas is going to be annoying:
>
> set something {{} {
> global do_something print ;# must "import" all lambdas before
> using :-(
> $do_something here
> $print Done!

No.. just say $::do_something, $::print. Or if you use [interp alias]
like in the Wiki page mentioned, you have global names back :^)

Yuriy Ershov

unread,
Oct 23, 2007, 4:34:20 AM10/23/07
to
On 23 , 05:22, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
> Personally I think the [apply] method that we now have in 8.5 is the
> way to go. Lambdas are after all merely values. So there is no reason
> to treat a lambda as anything other than a string until you want to
> use it as a function. So:

We WILL have ;) there's still no release.
At least, I could use this lambda for backward compatibility.
Tcl 8.4 is actual standard now.

> The advantage is that unlike the proc work-arounds the apply method
> has all the advantages of regular variables: local scope, passable as
> first class citizens etc.
>
> The disadvantage is that calling a lambda is different from calling a
> regular proc (you need to prepend apply to it). Now... if someone
> feels like modifying [unknown] so that lambdas can be called like a
> proc..... ;-)

Procs are compiled only once.
And what about apply-lambda?

Yuriy Ershov

unread,
Oct 23, 2007, 4:36:40 AM10/23/07
to
> HA! Now that we have this we can TRULY treat everything as a string.

No ;)
There are arrays

sch...@uni-oldenburg.de

unread,
Oct 23, 2007, 5:27:42 AM10/23/07
to

AFAIK they get their bytecodes cached in the internal rep, so they
only get compiled once like procs.

Michael

Donal K. Fellows

unread,
Oct 23, 2007, 9:18:23 AM10/23/07
to
Michael wrote:
> AFAIK they get their bytecodes cached in the internal rep, so they
> only get compiled once like procs.

Correct.

Donal.

sleb...@gmail.com

unread,
Oct 23, 2007, 10:03:51 AM10/23/07
to
On Oct 23, 4:34 pm, Yuriy Ershov <yuriy.ers...@gmail.com> wrote:
> On 23 , 05:22, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
>
> > Personally I think the [apply] method that we now have in 8.5 is the
> > way to go. Lambdas are after all merely values. So there is no reason
> > to treat a lambda as anything other than a string until you want to
> > use it as a function. So:
>
> We WILL have ;) there's still no release.
> At least, I could use this lambda for backward compatibility.
> Tcl 8.4 is actual standard now.
>

There's no reason why you couldn't implement [apply] in 8.4. It's not
a syntax extension, it's just a special kind of [eval]. Here's one
possible implementation:

proc apply {lambda args} {

# Sanity check:

if {[llength $lambda] != 2} {
error "malformed lambda"
}
foreach {vars script} $lambda break

# Process the args:

if {[lindex $vars end] == "args"} {
set vars [lrange $vars 0 end-1]
set vals [lrange $args 0 [expr {[llength $vars]-1}]]
set args [lrange $args [llength $vars] end]
if {[llength $args] < [llength $vars]} {
error "wrong # of args"
}
} else {
set vals [lrange $args 0 [expr {[llength $vars]-1}]]
if {[llength $args] != [llength $vars]} {
error "wrong # of args"
}
}

# Done preprocessing arguments,
# now do the eval:

eval [string map [list \
%VARS% $vars \
%VALS% $vals \
%ARGS% $args \
%SCRIPT% $script \
] {
if {[llength {%VARS%}]} {
foreach {%VARS%} {%VALS%} break
}
%SCRIPT%
}]
}

In fact, I don't see anything from the code above that requires Tcl
version > 7.3. So in theory we could have had lambdas way back in Tcl
7. The problem is not that Tcl didn't (or doesn't) support lambdas.
The problem is lack of imagination of how to implement lambdas in a
tclish way. I don't know who's idea is it to implement [apply] but the
paradigm shift of having a command to create lambdas to having a
command that treats strings as lambdas is genius -- very tclish.

Yuriy Ershov

unread,
Oct 23, 2007, 11:43:34 AM10/23/07
to
> The problem is lack of imagination of how to implement lambdas in a
> tclish way. I don't know who's idea is it to implement [apply] but the
> paradigm shift of having a command to create lambdas to having a
> command that treats strings as lambdas is genius -- very tclish.

Actually, the word "apply" is not needed.
It is like using the word "CALL" for procedure invocation.
In Tcl, the first word IS the proc name to be called.
So why "apply"?
Being the first word in line, lambda must be automatically called.

miguel

unread,
Oct 23, 2007, 11:50:10 AM10/23/07
to

Because the lambda is an anonymous proc - it has no name. As you said,
the first word IS the proc name - so it can't be the lambda.

suchenwi

unread,
Oct 23, 2007, 12:12:59 PM10/23/07
to
On 23 Okt., 17:43, Yuriy Ershov <yuriy.ers...@gmail.com> wrote:
> Actually, the word "apply" is not needed.
> It is like using the word "CALL" for procedure invocation.
> In Tcl, the first word IS the proc name to be called.
> So why "apply"?
> Being the first word in line, lambda must be automatically called.

One could do without - e.g. with some [unknown] trickery as shown
above. But that's not very efficient.

The first word is the name of the command (and is looked up in a
command table). For efficiency, all lambdas would have to be
registered as commands, which makes them global. So I can understand
the rationale behind the [apply] command. Somehow related to Lisp's
(funcall) or (apply).

Neil Madden

unread,
Oct 23, 2007, 2:12:08 PM10/23/07
to
sleb...@yahoo.com wrote:
...

> OTOH since variables are locally scoped writing tcl code in pure
> lambdas is going to be annoying:
>
> set something {{} {
> global do_something print ;# must "import" all lambdas before
> using :-(
> $do_something here
> $print Done!
> }}
>
> set do_something {{x} {
> global print ;# typing global all the time quickly gets annoying
> $print "doing something: $x"
> }}
>
> set print {x {puts "$x\n"}}
>
> $something

You don't have to store lambdas in variables, you can also [interp
alias] them:

interp alias {} do_something {} apply {{..} {...}}

Although, of course, if you are doing this then it is best to just use a
regular named procedure. The most likely use of a lambda is when it is
passed either to or from a procedure as an argument/return value, so no
importing would be needed.

-- Neil

Yuriy Ershov

unread,
Oct 23, 2007, 4:31:32 PM10/23/07
to
> One could do without - e.g. with some [unknown] trickery as shown
> above. But that's not very efficient.

I would say, that tricks are very inefficient :) - hope they are not
going to be common.
Transparent lambda calls should have been built-in, not emulated.

> The first word is the name of the command (and is looked up in a
> command table). For efficiency, all lambdas would have to be
> registered as commands, which makes them global. So I can understand
> the rationale behind the [apply] command. Somehow related to Lisp's
> (funcall) or (apply).

Well.. it is not just so simple.
There are already several separate tables to search for command name:
built-in commands, global procs, package procs, namespaces, aliases..

The interpreter just need to recognize the special form of lambda as a
"command name". This will make happy everyone :)

Moreover.. I hope, lambdas are not being compiled every time before
execution. There must be some kind of cache.
So, just one more table to lookup..

As for apply, it should accept ordinary proc names then.

Donald G Porter

unread,
Oct 23, 2007, 4:35:36 PM10/23/07
to
Yuriy Ershov wrote:
> Well.. it is not just so simple.
> There are already several separate tables to search for command name:
> built-in commands, global procs, package procs, namespaces, aliases..

No.

All of those things are commands. They are all found in a
command table.

--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

Neil Madden

unread,
Oct 23, 2007, 5:07:33 PM10/23/07
to
Yuriy Ershov wrote:
>> One could do without - e.g. with some [unknown] trickery as shown
>> above. But that's not very efficient.
>
> I would say, that tricks are very inefficient :) - hope they are not
> going to be common.

Indeed, best to avoid such tricks in production code.

> Transparent lambda calls should have been built-in, not emulated.

Why? Does it seriously pain you having to write [apply $fun a b] rather
than just [$fun a b]? That seems to me like a fairly small matter of
syntax for very little gain over what [apply] already provides.
Especially when you consider that lambdas are typically used as
callbacks, and callbacks are usually evaluated with either [eval] or
[uplevel] which neatly allows you to avoid any problems. For example,
did you realise that [apply] works nicely with pretty much every command
in the Tcl and Tk libraries that takes a callback?

# I always recommend using a constructor for lambdas:
proc lambda {params body} { list apply [list $params $body] }
lsort -command [lambda {a b} { ... }] $xs
http::geturl $url -command [lambda tok { ... }]
after 1000 [lambda {} { puts "Hello!" }]
socket -server [lambda {sock addr port} { ... }] 8080
trace add variable foo write [lambda {v1 v2 op} { ... }]
etc etc

These all work fine, as do the great majority of callbacks in tcllib and
other packages. Indeed, I can't think of a counter-example of the top of
my head. So, what exactly isn't transparent about lambdas using [apply]?

...


> The interpreter just need to recognize the special form of lambda as a
> "command name". This will make happy everyone :)

Such an idea was proposed and rejected at the time. [apply] works fine
without any new special forms being introduced and is syntactically
convenient for 95%+ of all use cases I can think of.

>
> Moreover.. I hope, lambdas are not being compiled every time before
> execution. There must be some kind of cache.

That is correct, the byte-code is cached.

> So, just one more table to lookup..

The byte-code is cached directly in the lambda internal representation,
so there is no table lookup (that I know of). If you feel there are
performance problems with [apply] then supply some figures.


-- Neil

Yuriy Ershov

unread,
Oct 23, 2007, 7:34:33 PM10/23/07
to
> You don't have to store lambdas in variables, you can also [interp
> alias] them:
>
> interp alias {} do_something {} apply {{..} {...}}
>
> Although, of course, if you are doing this then it is best to just use a
> regular named procedure. The most likely use of a lambda is when it is
> passed either to or from a procedure as an argument/return value, so no
> importing would be needed.

The worst thing is that lambda implementation proposed in 8.5 doesn't
make lambdas look like ordinary procs.

In every language that support lambdas, it doesn't matter whether a
function has name or not. Reference to lambda is equal to named
function reference in any use case.

But what do we have in Tcl?

If I store an ordinary proc "reference", it is called this way:

% set XX puts
% $XX 123

But if I store lambda, I have to KNOW that!

% set XX {{x} {puts $x}}
% $XX 123 ;# This will NOT work!
% apply $XX 123

What's next?
Suppose, "apply" will accept proc names.
But I don't want to write dummy "apply" for every call. It's not
Fortran! :)

sleb...@gmail.com

unread,
Oct 24, 2007, 3:47:11 AM10/24/07
to
On Oct 24, 5:07 am, Neil Madden <n...@cs.nott.ac.uk> wrote:

> Yuriy Ershov wrote:
> > So, just one more table to lookup..
>
> The byte-code is cached directly in the lambda internal representation,
> so there is no table lookup (that I know of). If you feel there are
> performance problems with [apply] then supply some figures.
>

Sweet.. so the variable itself is marked as a lambda then? (this means
that lambda is just a "type" of object.. like integers, strings,
arrays and lists?) If so does [eval] do the same? Also, does it mean
that the following doesn't get bytecompiled? :

# lambda not stored in a variable:
apply {{x y} {set x [expr {$y*$x}];puts $x}} 20 20


Yuriy Ershov

unread,
Oct 24, 2007, 5:11:10 AM10/24/07
to
> # I always recommend using a constructor for lambdas:
> proc lambda {params body} { list apply [list $params $body] }
> lsort -command [lambda {a b} { ... }] $xs
> http::geturl $url -command [lambda tok { ... }]
> after 1000 [lambda {} { puts "Hello!" }]
> socket -server [lambda {sock addr port} { ... }] 8080
> trace add variable foo write [lambda {v1 v2 op} { ... }]

Okay, I have really overlooked this.
This is handy.

> The byte-code is cached directly in the lambda internal representation,
> so there is no table lookup (that I know of). If you feel there are
> performance problems with [apply] then supply some figures.

This means that variable containing "{{a b} {return a+b}}" will be
compiled (at first use? at assignment? - it doesn't matter) and
cached.

But you propose to store "lambda {{a b} {return a+b}}" everywhere
which is NOT a lambda-expression. Therefore, it may not be compiled
and cached.
This wat, the lambda expression itself gets generated, assigned and
compiled upon each call!

The solution is to allow using lambdas as a command name. Perhaps,
this may require some special form.
.. like {lambda {args} {body}}
;)

And one more advantage.
With apply, deep lambda call stack would have incomprehensible look -
bunch of "apply"'s.
On the contrary, if one had lambdas as commands, they would be visible
on the stack. [info level] would remain usable as well.

miguel

unread,
Oct 24, 2007, 6:12:23 AM10/24/07
to
Yuriy Ershov wrote:
>> # I always recommend using a constructor for lambdas: proc lambda
>> {params body} { list apply [list $params $body] } lsort -command
>> [lambda {a b} { ... }] $xs http::geturl $url -command [lambda tok {
>> ... }] after 1000 [lambda {} { puts "Hello!" }] socket -server
>> [lambda {sock addr port} { ... }] 8080 trace add variable foo write
>> [lambda {v1 v2 op} { ... }]
>
> Okay, I have really overlooked this. This is handy.
>
>> The byte-code is cached directly in the lambda internal
>> representation, so there is no table lookup (that I know of). If
>> you feel there are performance problems with [apply] then supply
>> some figures.
>
> This means that variable containing "{{a b} {return a+b}}" will be
> compiled (at first use? at assignment? - it doesn't matter) and
> cached.

You are not "thinking in Tcl".

The string "{{a b} {return a+b}}" is just a string. When [apply]
encounters it, it interprets it as an anonymous proc and runs it. If you
send it to eg [llength], it will be interpreted as a list. Values are
just strings, commands may interpret them in different manners. An
interesting exercise is to type at the prompt
set set set
and then ask: is "set" now a command? a variable? a variable's value?
The only answer reasonable answer in Tcl is "yes" ...

The fact that anonymous procs are bytecompiled (and the bytecodes are
saved/cached) is just a performance hack.

A variable cannot be compiled - its value can. Note that when you do
set L0 {{a b} {return a+b}}
set L1 $L0
{*}$L0 1 2
the value of L0 is now bytecompiled ... as is the value of L1, they are
the same!

> But you propose to store "lambda {{a b} {return a+b}}" everywhere
> which is NOT a lambda-expression. Therefore, it may not be compiled
> and cached. This wat, the lambda expression itself gets generated,
> assigned and compiled upon each call!
>
> The solution is to allow using lambdas as a command name. Perhaps,
> this may require some special form. .. like {lambda {args} {body}} ;)

Considered, rejected. If lambdas are command names you lose the
automatic lifetime management ("garbage collection"), which is very
important. Commands are long-lived, they exist and occupy memory as long
as you do not delete them. These anonymous procs do not.

You may find it interesting to read the tips in this area:
http://www.tcl.tk/cgi-bin/tct/tip/194 and
http://www.tcl.tk/cgi-bin/tct/tip/187.html.

> And one more advantage. With apply, deep lambda call stack would have
> incomprehensible look - bunch of "apply"'s. On the contrary, if one
> had lambdas as commands, they would be visible on the stack. [info
> level] would remain usable as well.

Would? Have you actually tried it?

% proc showCaller {} {puts **[info level -1]; moo}
% apply {args showCaller} can I see this?
**apply {args showCaller} can I see this?
invalid command name "moo"
% set errorInfo
invalid command name "moo"
while executing
"moo"
(procedure "showCaller" line 1)
invoked from within
"showCaller"
(lambda term "args showCaller" line 1)
invoked from within
"apply {args showCaller} can I see this?"

If you have concrete suggestions as to how to make the call stack
clearer or more useful, please file a bug or RFE.

suchenwi

unread,
Oct 24, 2007, 6:13:48 AM10/24/07
to
On 24 Okt., 11:11, Yuriy Ershov <yuriy.ers...@gmail.com> wrote:
> > # I always recommend using a constructor for lambdas:
> > proc lambda {params body} { list apply [list $params $body] }
> > lsort -command [lambda {a b} { ... }] $xs
> > http::geturl $url -command [lambda tok { ... }]
> > after 1000 [lambda {} { puts "Hello!" }]
> > socket -server [lambda {sock addr port} { ... }] 8080
> > trace add variable foo write [lambda {v1 v2 op} { ... }]

> But you propose to store "lambda {{a b} {return a+b}}" everywhere


> which is NOT a lambda-expression. Therefore, it may not be compiled
> and cached.
> This wat, the lambda expression itself gets generated, assigned and
> compiled upon each call!

No - it's not stored, but "executed immediately". Take


> > trace add variable foo write [lambda {v1 v2 op} { ... }]

This is sugar-coated for
> > trace add variable foo write [list {v1 v2 op} { ... }]
and what gets stored is the two-element {argl body} list. This, when
first [apply]ed, gets compiled, and on later calls just the bytecode
is executed.

miguel

unread,
Oct 24, 2007, 6:22:15 AM10/24/07
to
miguel wrote:
> A variable cannot be compiled - its value can. Note that when you do
> set L0 {{a b} {return a+b}}
> set L1 $L0
> {*}$L0 1 2
> the value of L0 is now bytecompiled ... as is the value of L1, they are
> the same!

Aargh!!! Serves me right for posting before breakfast ...

Either of


set L0 {{a b} {return a+b}}
set L1 $L0

apply $L0 1 2

or

set L0 [list apply {{a b} {return a+b}}]


set L1 $L0
{*}$L0 1 2

An by the way: I am using your proposed body ... it returns the string
"a+b" for any input. I do imagine you wanted
{{a b} {expr $a+$b}}]
which returns the sum.

Andreas Leitgeb

unread,
Oct 24, 2007, 7:37:59 AM10/24/07
to
suchenwi <richard.suchenw...@siemens.com> wrote:
> and what gets stored is the two-element {argl body} list. This, when
> first [apply]ed, gets compiled, and on later calls just the bytecode
> is executed.

I wonder, if the bytecode is attached to the whole thing, or just to
the body.

If it's attached to the whole "{params} {body}" thing, then a simple
[llength $function] would replace the bytecode-rep with the list-rep,
and next time it's got to be recompiled. (otoh, why should someone
treat the lambda as list? perhaps to check for a namespace? or use
lindex as pendant to [info args/body]? not too likely to happen
repeatedly enough to be an issue)
If it's "compiled" to a list, only whose second item has the actual
bytecode attached, then it could perhaps be recombined with a different
parameter list, and result in unexpected behaviour ...

Or is it done even differently (e.g. such that both list-information and
lambda-information is maintained together? also the string-rep?)

PS: I know, as a scripter I shouldn't care about these internals, but
I'm just curious...

miguel

unread,
Oct 24, 2007, 9:29:57 AM10/24/07
to

Heh: the correct answer is RTFS, but you are so nice and polite about it
... what the hell.

The whole [list $params $body ?$ns?] is converted to lambdaType. If you
for instance request the llength, the type shimmers and the bytecompiled
code is lost - it will be regenerated at the next usage.

Neil Madden

unread,
Oct 24, 2007, 10:46:39 AM10/24/07
to

No, that will get byte-compiled. The bytecode is stored in the internal
rep of the Tcl_Obj, not any particular variable. In other words, the
Tcl_Obj used to represent {{x y} {set x ...}} gets a compiled proc
stashed in its internal rep. This bytecode is generated the first time
that value is passed to [apply] and then sticks around until someone
messes with the internal rep.

Note that originally, apply was going to take the arguments separately:
[apply params body args...]. Miguel pointed out that the bytecode
depends on both the script body *and* the parameter list, which is why
they are now combined into a single argument, to give a handy place to
stash the bytecode.

-- Neil

Neil Madden

unread,
Oct 24, 2007, 11:05:46 AM10/24/07
to
Yuriy Ershov wrote:
...

>
> The worst thing is that lambda implementation proposed in 8.5 doesn't
> make lambdas look like ordinary procs.
>
> In every language that support lambdas, it doesn't matter whether a
> function has name or not. Reference to lambda is equal to named
> function reference in any use case.
>
> But what do we have in Tcl?
>
> If I store an ordinary proc "reference", it is called this way:
>
> % set XX puts
> % $XX 123
>
> But if I store lambda, I have to KNOW that!
>
> % set XX {{x} {puts $x}}
> % $XX 123 ;# This will NOT work!
> % apply $XX 123

This isn't an artefact of lambdas, but rather that Tcl has a distinction
between command and variable namespaces, and that it expects a command
*name* not a command itself. Common Lisp is an example of another
language which makes this distinction and also has this same problem:

(defun adder (n)
(lambda (x) (+ x n)))
((adder 1) 2)
--> ERROR: illegal function call
(funcall (adder 1) 2)
--> 3
(apply (adder 1) '(2))
--> 3

Tcl's [apply] is roughly equivalent to CL's (funcall) or (apply).

To get to something like Scheme or Haskell in Tcl, you could drop
variables and use commands for everything:

proc def {name = args} { interp alias {} $name {} {*}$args }
def XX = puts
XX "Hello, World!"
def XX = apply {{x} {puts $x}}
XX "Hello, World!"

Although, of course you lose local variables! I also prefer the Scheme
situation, but that's a bigger change to Tcl than just lambdas.

-- Neil

Donal K. Fellows

unread,
Oct 24, 2007, 11:14:10 AM10/24/07
to
miguel wrote:

> Andreas Leitgeb wrote:
>> If it's "compiled" to a list, only whose second item has the actual
>> bytecode attached, then it could perhaps be recombined with a different
>> parameter list, and result in unexpected behaviour ...
>
> The whole [list $params $body ?$ns?] is converted to lambdaType. If you
> for instance request the llength, the type shimmers and the bytecompiled
> code is lost - it will be regenerated at the next usage.

On the other hand, if you're combining with actual parameters then you
are using the form:
[list apply [list $params $body ?$ns?] $arg1 $arg2 ...]
and in that case adding extra arguments to the outer list won't hurt.
(It's the inner former-list that holds the bytecode inside it.)

Donal.

Joe English

unread,
Oct 24, 2007, 12:17:16 PM10/24/07
to
Yuriy Ershov wrote:
>
> The worst thing is that lambda implementation proposed in 8.5 doesn't
> make lambdas look like ordinary procs.
>
> In every language that support lambdas, it doesn't matter whether a
> function has name or not. Reference to lambda is equal to named
> function reference in any use case.

Not in Common Lisp or in any of the earlier Lisp dialects.
2-Lisps use (FUNCALL) to call procedure values.

> But what do we have in Tcl?

If Tcl is like Lisp at all, it's like a 2-Lisp.
[apply] is Tcl's rough equivalent of Lisp's (FUNCALL).

See also: http://www.nhplace.com/kent/Papers/Technical-Issues.html

You might prefer 1-Lisps (so do I), but Tcl just ain't like that,
and it don't work that way.


--Joe English

0 new messages