Python syntax in Lisp and Scheme

A

Alex Shinn

I think you miss the point - "quickly" is itself a _name_ for an
abstract modifier. If this is the analog of a higher order function, it
is a _named_ higher order function, not an anonymous one.

I was making the analogy that verbs are functions (any functions).
"run" is thus a function of one argument (the person running).
"quickly" is as we both say an HOF which acts on run. My point is the
result of applying the HOF gives us "run quickly" which is itself a
function, and an anonymous one at that because "run quickly" is not a
name but a visible application of an HOF. It's exactly equivalent to

(memoize run)

whereas the named version would require you to define externally

(define run-memoized (memoize run))

a technique which quickly begins to clutter your language with names
like "swint."
 
A

Avi Blackmore

[snip]
From that point of view, "car" and "cdr" are as good
as anything!

Better in one sense, I think. With "first" and "rest", you can't
have fun making bumper stickers that say "My other car is a cdr."

Avi Blackmore
 
B

Bengt Richter

|>And you DO NOT NEED lambdas for HOFs!

(e-mail address removed) (Bengt Richter) wrote previously:
|there could be ways that you need BOTH named and un-named functions.

Nope, you do not NEED both. It can be convenient or expressive to have
both, but it is certainly not necessary for HOFs or any other
computational purpose. And I have yet to see an example where a
hypothetical loss of unnamed functions would *significantly* worsen
expressiveness.

|a function NEEDS a name in order to call itself recursively
You snipped the line following the preceding:
(unless you create some specialized syntax for a recursive call)
Nope. That's the point of the Y combinator; you don't need a name to do
this (just first class anonymous functions). See, for example:

http://en2.wikipedia.org/wiki/Y_combinator
I'd call that a specialized syntax, to serve my purposes ;-)
|OTOH, if you evaluate a def in a namespace where you don't know what
|all the names are, you have a collision risk when you choose a name.
|An un-named function eliminates that risk.

Sure, that can occassionally be useful in eliminating the small risk.
But so can 'grep'. There are always more names out there to use. This
particular convenience is VERY small.
That's what I meant by the first line in
"""
Practically, it is probably rare that you can't use a named function,
but really def is a convenience construct that does name binding after
doing (what would be) a full-fledged lambda thing IMO.
"""
|Why should the following kind of thing be arbitrarily restricted?
| >>> funlist = [
| ... (lambda value:
| ... lambda:'My value is %s'%value
| ... # imagine freedom to have full suites here
| ... )(y) for y in range(5)
| ... ]
| >>> for fun in funlist: print fun()

Obviously, you cannot spell 'funlist' quite that way in Python. But the
The above spelling works fine, being verbatim cut/paste). Just not if you want
to replace the comment as it invites you to imagine. I guess the hypothetical
version is what you were referring to by 'that way.'
available spellings are not bad looking IMO. E.g., with no lambda:
I pre-agreed, following my example with:
"""
(Not that a bound method (aka callable object if bound method is __call__) might
not be as good or better in many cases, ...
"""
... def say_val(x=x): return 'My value is %s' % x
... return say_val
...

I'm not sure the point here. My spelling happens to be Python's (or at
least one option in Python)... and it works fine without any lambdas.

The relevant phrase from the post you are replying to was
"... where the def names would at best be ignored side effects." (Although
you are forced to use the temp bindings to return the function).
If you want, you can even 'del' the name 'ValFactory' after the list is
created.
Sure. Interesting you chose to use the default-value hack rather than
a closure ;-). What I had in mind when I pre-agreed was something like
... def __init__(self, v): self.v=v
... def __call__(self): return 'My value is %s' % self.v
... ...
My value is 0
My value is 1
My value is 2
My value is 3
My value is 4

Regards,
Bengt Richter
 
R

Raffael Cavallaro

map is an abstraction that
specifies that you want to apply a certain operation to each element
of a collection, with adding the offset being the desired operation.

Sorry to reply so late - I didn't see this post.

In the context in which the offsets are added, it isn't necessary to
know that the offsets are added using map, as opposed, for example, to
an interative construct, such as loop. Since we don't need to know _how_
the adding of offsets is done at every location in the source where we
might want to add an offset to the elements of a list or vector, we
should _name_ this bit of functionality. This is an even bigger win
should we ever decide to switch from map to loop, or do, or dolist, etc.
Then we write a single change, not one for every time we use this bit of
functionality.
 
J

james anderson

David said:
...

|a function NEEDS a name in order to call itself recursively

Nope. That's the point of the Y combinator; you don't need a name to do
this (just first class anonymous functions). See, for example:

http://en2.wikipedia.org/wiki/Y_combinator

please bear with me on something which i have evidently misunderstood.
what are the symbols 'h' and 'x' in the referenced exposition on the "y
combinator" if they are not names?
is the essential distinction, that one does not "need" free "names"?

?
 
R

Raffael Cavallaro

My point is the
result of applying the HOF gives us "run quickly" which is itself a
function, and an anonymous one at that because "run quickly" is not a
name but a visible application of an HOF.


I have no problem with a HOF, as long as the HOF corresponds to
something in the language of the problem domain. But it doesn't here. I
think it is telling that your example is taken from the problem domain
of computer science (memoization of functions), not that of the domain.

It's exactly equivalent to

(memoize run)

If we were writing a program that simulated people running and swimming,
it's very doubtful that "quickly" would mean "memoize." "Quickly" would
mean, "with-increased-framerate," or something similar. (Note that
with-increased-framerate would almost certainly be a macro).

In domains outside of functional programming and mathematics, the
concepts of the problem domain don't usually map to applicable HOFs.
People fall in love with HOFs because they are great tools for lower
level implementation. But I don't think they usually map well to the
concepts of problem domains other than mathematics and computer science.
Named functions and macros let us capture the power of HOFs inside a
vocabulary _and_ syntax that matches the problem domain.
 
H

Hans Nowak

Jan said:
I've recently tried to teach someone programming. I thought "Python has
an easy syntax, let's try that". Well, guess what -- she had a really
hard time. Inconsistency was a real problem, as was the confusion
between "statements" and "expressions". When you start programming in
Python, you get really confused -- does this call have side effects or
not? You can't tell by looking at the call.

Strange. A beginner shouldn't have a problem with the distinction between
statements and expressions, and shouldn't know about side effects at all, since
this is a notion introduced by functional languages. Does this beginner, by
any chance, come from a functional programming language, or maybe a strong
mathemathical background?
Also, the syntax was confusing. Yes, indenting the statements is
easy. But the dot notation is all but obvious, especially with its
inconsistent application in Python.

How is it inconsistent? It's used to access an object's attributes.
And where did those square brackets
suddenly come from and when do I use them?

They're syntactic sugar indicating a "data lookup" of some sorts, hence their
application with dicts and lists.
Mind you, this is from a beginner's point of view. Most of you look at
the language syntax from the point of view of a person knowing at least
one (or more) programming languages and having the basic programming
concepts drilled in. It's very different for someone who does not have
that background.

It's possible I guess, different beginners have different ideas, expectations
and experiences, but usually the opposite is true... beginners find Python easy
to use.
An experiment has shown that Scheme was *much* easier to grasp. In
Scheme, you can clearly see where side-effects occur and there are less
syntax rules to follow.

Again, this raises my suspicions that the beginners that were tested have a
mathemathical background. Heck, beginners used Basic for ages... I haven't
heard anyone complain about statements vs expressions, or side effects. They
usually don't even know the distinction.

Cheers,
 
R

Ray Blaak

|a function NEEDS a name in order to call itself recursively

Nope. That's the point of the Y combinator; you don't need a name to do
this (just first class anonymous functions).

Actually you do need a name. The Y combinator is just a way to give a name to
the anonymous function, where the name is a parameter name. It is only with
that name that the recursive invocation is done.
 
D

David Mertz

(e-mail address removed) (Bengt Richter) wrote previously:
|>Nope. That's the point of the Y combinator; you don't need a name to do
|>this (just first class anonymous functions). See, for example:
|> http://en2.wikipedia.org/wiki/Y_combinator
|I'd call that a specialized syntax, to serve my purposes ;-)

Well... it's specialized. But it's not a syntax, just a somewhat odd
HOF. But I would definitely agree that I don't want all my recursion to
be based on anonymous functions.

|>This particular convenience is VERY small.
|That's what I meant by the first line in

Yeah, but I put the 'very' in caps :).

|the hypothetical version is what you were referring to by 'that way.'

Yeah, sorry about my pronoun. I meant "can't spell the full suite..."

|> >>> def ValFactory(x):
|> ... def say_val(x=x): return 'My value is %s' % x
|> ... return say_val
|Sure. Interesting you chose to use the default-value hack rather than
|a closure ;-). What I had in mind when I pre-agreed was something like
| >>> class SayVal(object):
| ... def __init__(self, v): self.v=v
| ... def __call__(self): return 'My value is %s' % self.v

Well... the "default value hack" *IS* a closure.

I know I'm in the minority here, but it feels like more of a hack to me
to make class instances whose (main) purpose is to "act like functions"
(i.e. have custom '.__call__()' methods). In my mind, when I want a
bunch of related callables, the natural approach is writing a function
factory, not a class.

But either way, Bengt's is another perfectly good spelling for a
collection of callables that allow full suites. Not being Dutch, I
can't say which one is the "one obvious way."

Yours, David...
 
D

David Mertz

|[email protected] (David Mertz) writes:
|> |a function NEEDS a name in order to call itself recursively
|> Nope. That's the point of the Y combinator; you don't need a name to do
|> this (just first class anonymous functions).

|Actually you do need a name. The Y combinator is just a way to give a name to
|the anonymous function, where the name is a parameter name. It is only with
|that name that the recursive invocation is done.

Well, OK. This is true. But the context was basically whether you
could write whole programs as big lambda abstractions--e.g. Lisp minus
'defun' and 'set', or Python minus 'def'.

"Normal" recursive programs let the programmer know the name of the
function she is writing, and use that name for the recursion call. You
could use the Y combinator even if pixies would come it at random and
change the bound name 'h' to something else, throughout your code; the
name itself is never -used- beyond the lambda.

Yours, David...
 
D

Dave Benjamin

I know I'm in the minority here, but it feels like more of a hack to me
to make class instances whose (main) purpose is to "act like functions"
(i.e. have custom '.__call__()' methods). In my mind, when I want a
bunch of related callables, the natural approach is writing a function
factory, not a class.

In most cases, I would completely agree with you. Though they are often
interchangeable (closures and callable objects), there is a subtle semantic
difference to me. Is it a stateful function or a callable object? What does
it feel like? I usually go with my intuition.
 
V

Vis Mike

Luke Gorrie said:
Anonymous functions *can* be more clear than any name. Either because
they are short and simple, because it is hard to come up with a good
name, and/or becuase they are ambigous.

Say I want to attach an index to elements of a list. I could write

integers = [1..]
attach_index ls = zip integers ls

or just

attach_index ls = zip [1..] ls

If we're arguing to eliminate names that don't say very much, then

attach_index = zip [1..]

I think dynamic scoping within blocks really trims down on duplication and
make the code easier to read. For example:

employees sort: [ | a b | a date < b date ]

A lot of typing for a simple concept:

employees sort: [ < data ]

I'm not against too much typing to be clear, but rather too much typping
that makes the concept unclear.

-- Mike
Whether you want to give an explicit name to the list of integers is
not given. If the indexed list is local, it is better to use the
definition directly; I don't want to look up the definition of
integers (perhaps in a different module) to check whether it is [1..]
or [0..].

And for the exact same reason you might like to just write "zip [1..]"
instead of using a separate "attach_index" function.

Cheers,
Luke
 
P

Pascal Bourguignon

Pascal Costanza said:
Hartmann said:
I think that's the essential point here. The advantage of the names
car and cdr is that they _don't_ mean anything specific.
gdee, you should read early lisp history ;-). car and cdr ha[d|ve] a
very specific meaning

Yes, but noone (noone at all) refers to that meaning anymore. It's a
historical accident that doesn't really matter anymore when developing
code.[/QUOTE]

For that matter, even the very first LISP _programmer_ did not refer
to that meaning either.

Only the _implementer_ of the first LISP did.
 
K

Ken Shan

Raffael Cavallaro said:
I think you miss the point - "quickly" is itself a _name_ for an
abstract modifier. If this is the analog of a higher order function, it
is a _named_ higher order function, not an anonymous one.

In what sense are "lambda" and "apply" not names?
 
A

A. Lloyd Flanagan

Pascal Costanza said:
AFAIK, Lisp was very popular in the 70's and 80's, but not so in the
90's. At the moment, Common Lisp is attracting a new generation of
programmers.

I was a Lisp fan back when Common Lisp came out. We went from a
stunningly simple language that could be described in a small booklet
to one that couldn't be adequately described in a 300-page tome. It
was about that time that Lisp dropped off the radar.

Now I have a language called Python, which like the original Lisp can
be described simply but has extraordinary power. And _it_ is what is
attracting a new generation of programmers.
 
P

Pascal Costanza

A. Lloyd Flanagan said:
I was a Lisp fan back when Common Lisp came out. We went from a
stunningly simple language that could be described in a small booklet
to one that couldn't be adequately described in a 300-page tome. It
was about that time that Lisp dropped off the radar.

Now I have a language called Python, which like the original Lisp can
be described simply but has extraordinary power. And _it_ is what is
attracting a new generation of programmers.

Common Lisp still has a small core, and most of the stuff of the indeed
large spec would rather be considered standard libraries in more
conventional languages.

Yes, it would probably have been better if Common Lisp designers would
have made this distinction clearer, for example by defining language
layers. That's maybe the only real mistake they have made. [1]


Pascal

[1] Somewhere in this thread someone accused "us" Lispers that we don't
admit that Lisp has "bad" features. The reason why wo don't admit
anything here is not because it doesn't have bad features, but because
the flexibility of Lisp always allows us to code around these
misdesigns. And we don't have to wait for some language designer to
release version x.y of the language to fix a feature of the language.

The fact that Common Lisp is large is indeed the only mistake that we
can't "code around".
 
R

Raffael Cavallaro

Ken Shan said:
In what sense are "lambda" and "apply" not names?

Not names from the problem domain, unless the problem domain is
functional programming.
 
K

Ken Shan

Raffael Cavallaro said:
Not names from the problem domain, unless the problem domain is
functional programming.

But in the style of programming that you advocate, as I understand
it, one does not need to give a name to function application from the
problem domain before using it.
 
R

Rayiner Hashem

Obviously, you haven't tried to actually program in Lisp. Getting used
to the syntax is a matter of one or two weeks at most of actual coding,
provided you use a decent editor that supports parenthesis highlighting
and automatic indentation.
I'd have to concur with this one. Parenthesized-prefix syntax is rather
pretty. What I like is the flexibility in code layout. Ex:

(defun foo (x)
...long function definition here...)

and

int foo(int x)
{
...long function definition here...
}

Are equally natural in their respective syntaxes. However, if you have a
short, simple function:

(defun foo (x) (+ x 2))

is still perfectly natural, while:

int foo(int x) { return x + 2; }

looks a little weird. Most people would write the above similarly to the
first example, which makes it much longer. Block-structured languages in
general tend to suffer from this problem.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top