Python syntax in Lisp and Scheme

J

Joe Marshall

Alexander Schmolck said:
Did it occur to you that people maybe use python not so much because they are
retards but because it's vastly more effective than CL at the tasks they
currently need to perform? Should I send you a few hundred lines of my python
code so that you can try translating them into CL?

Sounds like an interesting challenge...
 
R

Raffael Cavallaro

Anonymous functions *can* be more clear than any name.

This belief is grounded in a desire to keep the program's language close
to the programming language, rather than moving the program's language
toward the problem domain. This resistance is, I suppose, understanable.
After all, the programmer's expertise is the language of the programming
language, not the language of the problem domain. It is, at least at
first, easier for him to talk in the language that he knows than one
that is new to him. Nevertheless, this is exactly what he must do if he
is to write clear code. The reason we see 300 line function bodies is
that many programmers resist expressing the solution in the language of
the problem domain, preferring instead to write in an idiom that they
already understand, the programming language.

The higher level abstractions of a complex piece of software will, of
necessity, be concepts in the problem domain. These concepts,
representing both entities, and the relationship and interactions among
different entities, will almost certainly already have well established
names in the problem domain. For those that do not, the programmer
should take the time to find apt descriptions of these entities or
interactions _in_the_language_of_the_problem_domain_. These problem
domain names are the appropriate units of the language that the software
should be written in. Named functions and macros are the appropriate
labels for the programmer's software definitions of the concepts of the
problem domain, not anonymous functions.

Unless the problem domain is functional programming itself, the language
that the program is written in should consist of names taken from the
problem domain, not anonymous functional interactions.

At some low level of abstraction, when building the functionality of the
named functions and macros that correspond to the concepts of the
problem domain, the programmer will, of course, need to specify
implementation. These implementations will, where appropriate, use
anonymous functions.

However, once we get above this lower level of abstraction, we will be
dealing with concepts from the problem domain, which _have_names_. These
names from the problem domain, not anonymous functions, and not the
keywords/built-ins of the computer language, should be the language the
program is written in.

Moreover, even at the lower levels of abstraction, we will be passing
through other well explored problem domains, such as arithmetic, string
mainipulation, etc. These domains _also_ have preexisting named
concepts, which can and should be used by the programmer. Most decent
languages have built-in functions or keywords or operators for some of
these things. For others, the programmer can and should take the time to
define named functions and macros for arithmetic, string manipulation,
etc. operations that correspond to concepts in each of these problem
domains.

This stands in direct opposition to those who think that software should
seek to _avoid_ names whenever possible. I, on the other hand find this
simple equation is true:

Names = Clarity
(specifically, names taken from the problem domain)

Some posters here have replied that this is just "obvious," and true
independent of the issue of anonymous functions. But the two issues are
_of_necessity_ related, because you cannot have both names and anonymity.

It seems as if some here believe that names = tedium, or names =
prolixity, or names = exra work. But disdaining this work of finding
appropriate, descriptive, names from the problem domain, is a recipe for
obfuscated code. Worse, it is a recipe for failed software projects. The
failure to find good names from the problem domain indicates a failure
to properly understand the problem domain in its own terms. Failure to
understand the problem domain in its own terms means that the program's
design is almost certainly fatally flawed.

Again, this will be decried as "obvious." However, what should be
obvious is that we cannot have both names, and anonymity.
 
M

Michele Dondi

Of course it's not. But it seems to me that his skepticism regarding
whether that proof _can_ be formalized must in fact be skeptism
regarding whether it's possible to state all the necessary axioms
and deduce the theorem without any appeal to the way things
look.

As I have stressed in my other post, I'm *not* skeptic about the fact
that that proof can be formalized!

I'm simply puzzled thinking of how it would be done, since IMHO it is
a proof that indeed *does* make heavily appeal to the way things look,
and in this sense it is so simple that often one can find it in
popularization books.

(BTW) Also, since you mentioned axiomatic euclidean geometry, I just
don't know anything about it[*], but I don't know wether it is
possible in its formalism to define/talk about "continuous
transformations", that are indeed the basis of that proof.

So, if I am right in my assumption above, while the object of the
proof can be reasonably defined in axiomatic euclidean geometry,
either the theorem can't be proved in that teory or there exists an
alternative proof that does not use continuity arguments.


[*] This means: "so I may well be wrong"!


Michele
--
Comments should say _why_ something is being done.
Oh? My comments always say what _really_ should have happened. :)
- Tore Aursand on comp.lang.perl.misc
 
K

ketil+news

Raffael Cavallaro said:
This belief is grounded in a desire to keep the program's language close
to the programming language, rather than moving the program's language

So, does that mean you disagree?
This stands in direct opposition to those who think that software should
seek to _avoid_ names whenever possible.

As far as I can tell, nobody holds this position.
I, on the other hand find this simple equation is true:
Names = Clarity
(specifically, names taken from the problem domain)

Sure, to some extent. More names isn't always more clarity, though.
And compactness, locality and simplicity also adds to clarity.
Some posters here have replied that this is just "obvious," and true
independent of the issue of anonymous functions. But the two issues are
_of_necessity_ related, because you cannot have both names and anonymity.

You can have, as has been pointed out, a *balance*, naming the
important things (be they functions, data types, or values) while
leaving less important things unnamed.

I and others have come up with simple examples that we feel show that
anonymous functions improve clarity. Your posts are more dogmatic,
which would be fine, except that I apparently fail to interpret your
position correctly.

So, do you agree or not that anonymous functions can improve clarity
in some cases?

If not, are you also against anonymous values of other kinds
(intermediate arithmetic results, say; or types)?

Do you agree with the specific cases posted to this thread?
If not, could you point out why?

-kzm
 
E

Edi Weitz

For simple use of built-in libraries,
http://online.effbot.org/2003_08_01_archive.htm#troll
looks like a good test case.

Quick hack follows.

edi@bird:/tmp > cat troll.lisp
(asdf:eek:os 'asdf:load-op :aserve)
(asdf:eek:os 'asdf:load-op :cl-ppcre)

(defparameter *scanner*
(cl-ppcre:create-scanner
"<a href=\"AuthorThreads.asp[^\"]*\">([^<]+)</a></td>\\s*
<td align=\"center\">[^<]+</td>\\s*
<td align=\"center\">[^<]+</td>\\s*
<td align=\"center\">\\d+</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*
<td align=\"center\">\\d+</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*"))

(defun troll-checker (name)
(let ((target
(net.aserve.client:do-http-request
(format nil "http://netscan.research.microsoft.com/Static/author/authorprofile.asp?searchfor=~A" name)
:protocol :http/1.0)))
(cl-ppcre:do-scans (match-start match-end reg-starts reg-ends *scanner* target)
(flet ((nth-group (n)
(subseq target (aref reg-starts n) (aref reg-ends n))))
(let* ((group (nth-group 0))
(posts (parse-integer (nth-group 1)))
(replies (parse-integer (nth-group 2)))
(threads-touched (parse-integer (nth-group 3)))
(reply-to-post-ratio (/ replies posts))
(threads-to-post-ratio (/ threads-touched posts)))
(unless (< posts 10)
(format t "~55A R~,2F T~,2F ~:[~;TROLL~:[?~;!~]~]~%"
(subseq group 0 (min 55 (length group)))
reply-to-post-ratio
threads-to-post-ratio
(and (> reply-to-post-ratio .8)
(< threads-to-post-ratio .4))
(< threads-to-post-ratio .2))))))))

(compile 'troll-checker)

edi@bird:/tmp > cmucl
; Loading #p"/home/edi/.cmucl-init".
CMU Common Lisp 18e, running on bird.agharta.de
With core: /usr/local/lib/cmucl/lib/lisp.core
Dumped on: Thu, 2003-04-03 15:47:12+02:00 on orion
Send questions and bug reports to your local CMUCL maintainer,
or see <http://www.cons.org/cmucl/support.html>.
Loaded subsystems:
Python 1.1, target Intel x86
CLOS 18e (based on PCL September 16 92 PCL (f))
* (load "troll")

; loading system definition from /usr/local/lisp/Registry/aserve.asd into
; #<The ASDF1017 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM ASERVE {4854AEF5}> as ASERVE
; loading system definition from /usr/local/lisp/Registry/acl-compat.asd into
; #<The ASDF1059 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM ACL-COMPAT {4869AD35}> as ACL-COMPAT
; loading system definition from /usr/local/lisp/Registry/htmlgen.asd into
; #<The ASDF1145 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM HTMLGEN {487E64C5}> as HTMLGEN
; loading system definition from /usr/local/lisp/Registry/cl-ppcre.asd into
; #<The ASDF1813 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM #:CL-PPCRE {48F32835}> as CL-PPCRE
; Compiling LAMBDA (NAME):
; Compiling Top-Level Form:
T
* (troll-checker "(e-mail address removed)")
comp.lang.lisp R0.93 T0.63
NIL
* (troll-checker "(e-mail address removed)")
rec.photo.digital R1.00 T0.76
rec.arts.sf.written R0.99 T0.57
comp.lang.python R0.98 T0.64
rec.photo.equipment.35mm R1.00 T0.73
sci.math R1.00 T0.77
rec.puzzles R1.00 T0.75
comp.theory R1.00 T0.56
comp.graphics.algorithms R1.00 T0.87
comp.sys.mac.apps R1.00 T0.69
NIL
* (troll-checker "(e-mail address removed)")
comp.lang.lisp R0.91 T0.44
fr.comp.os.unix R1.00 T0.70
es.comp.os.linux.programacion R1.00 T0.67
fr.comp.lang.lisp R1.00 T0.40 TROLL?
comp.unix.programmer R1.00 T0.92
sci.space.moderated R1.00 T0.43
gnu.emacs.help R0.95 T0.84
sci.space.policy R1.00 T0.33 TROLL?
alt.folklore.computers R1.00 T0.43
comp.lang.scheme R0.83 T0.58
fr.comp.os.mac-os.x R0.92 T0.83
NIL

Granted, Portable AllegroServe[1] and CL-PPCRE[2] aren't "built-in"
(but freely available, compatible with various CL compilers, and easy
to install) and Python might have a bit more syntactic sugar but it
wasn't _too_ hard to do that in Lisp.

Edi

[1] <http://portableaserve.sf.net/>
[2] <http://weitz.de/cl-ppcre/>
 
A

Alan Gauld

is to write clear code. The reason we see 300 line function bodies is
that many programmers resist expressing the solution in the language of
the problem domain, preferring instead to write in an idiom that they
already understand, the programming language.

Do you have any objective evidence to suggest that this is true?
What proprtion exactly is due to this? The reason I ask is that
most of the long functions I have seen have been products of the
algorithm being implemented. If an algorithm takes 300 lines to
express it should be expressed as 300 lines. I have *never* seen
a long function that is the result of a programmer avoiding using
user vocabulary!

Equally I see no evidence whatsoever to suggest that users
express requirements in short chunks - usually the opposite, we
get presented with long complex prose describing a convoluted
business process and the programmer has to split that into its
natural chunks during analysis!

If anyone has done any research to connect long functions with
ignoring of user language I'm unaware of it and would be most
interested in seeing it.
The higher level abstractions of a complex piece of software will, of
necessity, be concepts in the problem domain.

Not necessarily(*), but I would agree that usually they are, but
at the lower levels the solution space may bear no resemblance to
the problem domain at all!

(*) For example where the solution architecture is based on a
mathematical technique which would be impractical in a manual
business process but is entirely practical using computing power.
As a somewhat dated example - the processes used in computer
crytography for example being entirely different to those used in
manual cryptrography. There will be some concepts in common
but many will be entirely novel.
interactions _in_the_language_of_the_problem_domain_. These problem
domain names are the appropriate units of the language that the software
should be written in. Named functions and macros are the appropriate
labels for the programmer's software definitions of the concepts of the
problem domain, not anonymous functions.

In the general case I agree completely but a blanket statement
that it is always true is absurd. There are many cases when a
programmer is dealing with issues that simply don't arise in the
human scenario. Anonymous functions are often used in
scenarios where a name is meaningless. Even in business processes
it is not unusual to find processes with names like JDI(Just Do
It) or DWN (Do Whatever's Necessary) to deal with extraordinary
scenarios. (Although ironically these are rarely the ones which
require anonymous funtions in code!)
At some low level of abstraction, when building the functionality of the
...
implementation. These implementations will, where appropriate, use
anonymous functions.

Ah, we do agree at this level. So your point only applies to
"high level" functions. The issue then becomes one of deciding at
what point the solution and problem domains separate.
However, once we get above this lower level of abstraction, we will be
dealing with concepts from the problem domain, which _have_names_.

Usually, but not always. Or often highly generic names which are
best implemented using higher order programming techniques
involving anonymous names.
This stands in direct opposition to those who think that software should
seek to _avoid_ names whenever possible. I, on the other hand find this
simple equation is true:

Names = Clarity

Again, in general I agree. But if the name is f and it is only
used for as long as it takes to convey a single use function into
the argument list of another function then I find the naming to
be of little or no value.
Some posters here have replied that this is just "obvious," and true
independent of the issue of anonymous functions. But the two issues are
_of_necessity_ related, because you cannot have both names and anonymity.

I'm not sure I agree there. It happens in the real world all the
time. (Consider Internet Chat Rooms! Many users there desire
anonymity while using a name which may not be their identity.
Indeed they achieve anonynimty through their false identity!)
prolixity, or names = exra work. But disdaining this work of finding
appropriate, descriptive, names from the problem domain, is a recipe for
obfuscated code.

I agree that good names are a good thing and time should be spent
considering appropriate ones but...
Worse, it is a recipe for failed software projects.

Bad naming is rarely if ever the reason for failed projects. It
may contribute by slowing down testing or integration and thus
causing estimate failure (the most comon reason for failed
projects) but naming alone is not enough to cause a failure IMHO.
failure to find good names from the problem domain indicates a failure
to properly understand the problem domain in its own terms. Failure to
understand the problem domain in its own terms means that the program's
design is almost certainly fatally flawed.

Insofar as the problem domain is reflected in the solution space
I agree. Certainly a programmer who does not understand the
vocabulary of his end user is unlikely to create good solutions.

Naming is important where a name aids understanding. If a name is
just there as a marker it serves no purpose. I agree that this
rarely happens at a high level in the design but I think it
happens at a higher level that you suggest. Not often, but often
enough to prevent blanket assertions being made.

Alan G.

Author of the Learn to Program website
http://www.freenetpages.co.uk/hp/alan.gauld
 
K

Kaz Kylheku

Alexander Schmolck said:
Did it occur to you that people maybe use python not so much because they are
retards but because it's vastly more effective than CL at the tasks they
currently need to perform?

People use Python most likely for these reasons:

- they read some articles about it in popular press
- it is relatively new
- it came with their Linux distribution

The second point is important. When something is new, there is a
ready-made explanation for not being popular. When the pointy haired
boss asks why isn't the whole world using Python for everything, you
just have to say ``It's too new, so only the smart, hip people who
have their ears to the ground are using it, but just wait a few
years.''

It's easy to add a positive adornment to the explanation which gives
rise to an expectation of success, and which in turn creates a
psychological pressure to adopt or else be left behind!

Soon, the language starts being mentioned on job advertisements as a
desireable skill, and the pressure starts to snowball. At this point,
hordes of immature programmers are paniced into learning it, just so
they can put it on their resumes and be able to say something about it
in interviews.

But these programmers resent being pressured into learning! They
resent the new programming language, even if they contribute to its
body of popularity.

This is why in ten, fifteen, maybe twenty years, when the popularity
bubble of that language has long burst, there will be hordes of
detractors who will have ready-made seemingly technical explanations
why that language is no longer popular.
 
R

Raffael Cavallaro

So, do you agree or not that anonymous functions can improve clarity
in some cases?

Of course. However, those cases tend to be low level abstractions
precisely because were talking about _anonymous_ functions, not
functional abstractions in general. Their anonymity itself prevents them
from improving the clarity of high level abstractions.

In other words, the higher the level of abstraction, the more we are
talking in the language of the problem domain. The language of the
problem domain has a vocabulary with _names_ for entities and their
interactions. Anonymous functions, by definition _have_no_names_, so
they can't possibly be isomorphic with the language of the problem
domain. If an anonymous function _does_ accomplish something identical
to a named entity or interaction in the problem domain, then you should
give your anonymous function _that_name_ from the problem domain. Now,
of course, it is a named function or macro, not an anonymous function
anymore.

The language of the problem domain, and anonymous functions, are,
_of_necessity_, mutually exclusive, because the domain experts use
_names_, not anonymous functions, when they talk about their domain of
expertise.
 
R

Raffael Cavallaro

In the general case I agree completely but a blanket statement
that it is always true is absurd. There are many cases when a
programmer is dealing with issues that simply don't arise in the
human scenario. Anonymous functions are often used in
scenarios where a name is meaningless.

And in those cases, anonymous functions are perfectly appropriate.

However, when dealing with the existing abstractions of the problem
domain, named functions and macros are superior. I contend that a great
deal more code should be dealing with the existing abstractions of the
problem domain than is currently the norm. (Part of this is premature
optimization - Programmers are reluctant to break code into smaller
named units for fear that the additional code and function calls will be
more computationally costly.) Remember that mathematics, string
manipulation, network protocols, etc., are all well understood problem
domains with _preexisting_named_abstractions_. These named abstractions
are what we should be thinking and programming in, not the primitives of
whatever language we happen to be using, nor even in anonymous
functional abstractions.

In addition, even if the programmer finds some novel way, only possible
in a machine implementation, to express a solution, our ability to think
clearly about that process is greatly aided by giving it a _name_. E.g.,
it is much easier to think about different sorting methods (bubble sort,
quicksort, etc.) by refering to them by name, than it is to have to look
at an implementation of them every time we wish to refer to them.

Naming is a fundamental step in building abstraction. Anonymous
functions, keep us trapped at the level of abstraction at which they are
defined. If we wish to reuse them, we must reiterate them, because we
can't simply refer to them by name. Why not simply name them, and use
the names? This is, after all, how people have been communicating
abstractions since the dawn of spoken language.
 
B

Bengt Richter

|> But the underlying issue was the spurious claim that lambda forms
|> were somehow required for HOFs, which is totally bogus. Python
|> could get by with only 'def', Lisp with only 'defun', and Haskell
|> only '=' and 'where'... and all of them would be just as capable at
|> using combinatorial and other HOFs.

|Yes, but arguments such as these are the first step down the slippery
|slope to Turing Equivalence. For just about any feature in just about
|any language, you could argue that the langugage could get by without
|it ... and taking this to its logical conclusion, you end up with
|assembler.

There is no such slope. OF COURSE everything is *computable* in every
language. That's obvious and trivial. Well, so are lots of things, but
it's not the point I've made.

What I am talking about is HIGHER ORDER FUNCTIONS. I.e. things
(abstractions) that don't exist in assembly language or in Turing
machines. You don't need that abstraction to do any computation, but
obviously, HOFs have a certain utility and beauty.

And you DO NOT NEED lambdas for HOFs! Categorically so--it's not that
you can use only a subset of HOFs if you only have def/defun/=. A
language that doesn't have lambda, but treats functions as first class,
can express EVERY HOF that one that adds lambda can.

ISTM there could be ways that you need BOTH named and un-named functions.
I.e., a function NEEDS a name in order to call itself recursively
(unless you create some specialized syntax for a recursive call).

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.

I.e., even if the function-definition part is identical in syntax and
capability, ISTM the name-binding side effect could be an issue.
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?
(currently for two reasons -- a name is useless here and def
is a statement, not allowed in this contex):
... (lambda value:
... lambda:'My value is %s'%value
... # imagine freedom to have full suites here
... )(y) for y in range(5)
... ] ...
My value is 0
My value is 1
My value is 2
My value is 3
My value is 4

(Not that a bound method (aka callable object if bound method is __call__) might
not be as good or better in many cases, but that might lead to asking whether
you NEED to be able to define functions outside of classes ;-)

ISTM there are uses for lists (and dicts for that matter) of functions
where the def names would at best be ignored side effects. E.g., perhaps
key or macro-key-sequence bindings for an editor, or event bindings for a GUI, etc.
This point is quite neutral as to whether lambda forms are otherwise
worthwhile. It's just a basic fact that a bunch of posters oddly want
to deny.
ISTM you are focusing on the defined function to the exclusion of
the name-binding-as-side-effect, and saying you don't need lambdas
because def's can generate the same functions, but ISTM that's not the whole story ;-)

Regards,
Bengt Richter
 
A

Alex Shinn

Naming is a fundamental step in building abstraction. [...] This is,
after all, how people have been communicating abstractions since the
dawn of spoken language.

Language may have begun with proper names, but these are by definition
*not* abstract. Abstraction comes from being able to combine different
linguistic elements to build more complex ideas without needing to give
them names. We use adjectives and adverbs to modify existing words
without needing to come up with new words, and build further with noun
clauses and prepositions. So you can both "run quickly" and "swim
quickly," which is analogous to a higher order function (quickly)
working on two existing functions (run and swim). You could give
specific names to either of these but indiscriminately naming puts a
burden on the memory. In this case, the further modified function "run
quickly over a short distance" is a common enough concept that it does
get its own name "sprint," but there is no equivalent for when those two
modifiers are applied to "swim." It may be fun to suggest that "swint"
be used, but I don't think anyone would argue that would make the
language more clear, quite the contrary it would make the spoken
language unwieldy.

Naming is of course important, but we'd have a very difficult time
communicating if we had to name everything we wanted to talk about. You
need to choose a good balance of what deserves a name.

And don't name the farm animals, it only makes it harder when you eat
them :)
 
B

Brian McNamara!

Raffael Cavallaro said:
In other words, the higher the level of abstraction, the more we are
talking in the language of the problem domain. The language of the
problem domain has a vocabulary with _names_ for entities and their
interactions. Anonymous functions, by definition _have_no_names_, so
they can't possibly be isomorphic with the language of the problem
domain. If an anonymous function _does_ accomplish something identical
to a named entity or interaction in the problem domain, then you should
give your anonymous function _that_name_ from the problem domain. Now,
of course, it is a named function or macro, not an anonymous function
anymore.

I still disagree. Below is an example where I still think it's best to
use anonymous functions, despite the fact that both (1) it's at a high
level of abstraction and (2) it maps exactly to the problem domain.

Here's the example. You've got some command-line application that
processes some binary files. The details aren't important. You can
run the program like this:

% prog foo bar baz
# processes data files foo, bar, and baz, and then
# saves binary results in foo.sav, bar.sav, and baz.sav

or like this

% prog -p foo
# processes data files (in this case, just "foo")
# and prints human-readable results to the screen

Hopefully you get the basic idea for the application.


Now, I can imagine the program being structured something like this.
(I'm using Haskell, which is the FPL I know best, but it's not my native
tongue, so apologies if I screw up minor details.)

processFile :: String -> IO Info
-- process data file named by string, return Info data structure

printInfo :: Info -> IO ()
-- print Info in human-readable form to stdout

saveInfo :: Info -> String -> IO ()
-- save Info (in binary) to file named by String

Now, somewhere in or near the main() function (that is, at the very
highest level of abstraction for this program), I can imagine seeing
code like this:

-- assume these vars:
fileList :: [String] -- names of files to process
wantPrint :: Bool -- whether user specified '-p' option
...
let forEachFilename op = mapM op fileList
in if wantPrint
then forEachFilename \fn -> do info <- processFile fn
printInfo info
else forEachFilename \fn -> do info <- processFile fn
saveInfo info (fn++".sav")

Note the two anonymous functions:

\fn -> do info <- processFile fn
printInfo info
and
\fn -> do info <- processFile fn
saveInfo info (fn++".sav")

Note that they map exactly to ideas from the problem domain (actually,
to the very user interface of this program). Now, you want me to make
these separate named functions? What ought I call them? Perhaps
"processFileAndPrint" and "processFileAndSave"? Or perhaps we should
use the name as it's known in the user interface, and name them
"doItWithTheDashPeeOption" and "doItWithoutTheDashPeeOption"?

I think that such a strategy would be silly, especially if there is
more than one command-line option, each of which slightly alters the
program's overall behavior. I think that the anonymous functions do a
good job of succinctly specifying the behavior for each option.


I have enjoyed this discussion because it's forced me to think about
what rules I apply when making coding choices (such as whether-or-not to
use an anonymous function). I've found it's surprisingly difficult to
come up with succinct, precise, hard-and-fast rules which capture how I
choose to write code. You have an advantage here: even if we disagree
about what the "best" style is, you can at least describe the rules for
your style, whereas I cannot easily do the same for mine.
 
D

David Mertz

|>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

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

|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.

|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
available spellings are not bad looking IMO. E.g., with no lambda:
... 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.
If you want, you can even 'del' the name 'ValFactory' after the list is
created.

Yours, David...
 
J

Jan Rychter

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)

iD8DBQA/j21GLth4/7/QhDoRAh2nAKCcXh235hUbrwrewoawxQjwOz2vkACfc1s/
5tL3QKMbDoykwZFu3usfesE=
=4tah
-----END PGP SIGNATURE-----
 
J

John M. Gamble

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.

Indeed. Had the first lisp been programmed on a 680x0, we would have
d0 and d1 instead of car and cdr, or worse, had it been done on 8086,
we would have ax and bx...

I think you mean "cd0 and cd1" and "cax and cbx". The Cs in car
and cdr mean "contents". For that matter, the Rs mean register,
so i suppose it would go "cd0r", "cd1r", etc.
 
R

Raffael Cavallaro

[snip]
\fn -> do info <- processFile fn
printInfo info
and
\fn -> do info <- processFile fn
saveInfo info (fn++".sav")
[snip]

What ought I call them? Perhaps
"processFileAndPrint" and "processFileAndSave"?

Yup. Next question. Only someone who hasn't taken a break from coding
for a long time could think that:

\fn -> do info <- processFile fn
printInfo info

is clearer or easier to understand than:

ProcessFileAndPrint


Even more so in lisp:

process-file-and-print
 
R

Raffael Cavallaro

Alex Shinn said:
We use adjectives and adverbs to modify existing words
without needing to come up with new words, and build further with noun
clauses and prepositions. So you can both "run quickly" and "swim
quickly," which is analogous to a higher order function (quickly)
working on two existing functions (run and swim).

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.

We don't say "he ran (large distance covered/unit time)" or "he swam
(large distance covered/unit time)." Instead, we give this abstraction,
(large distance covered/unit time) a name, "quickly."

I am most definitely _not_ arguing against the use of higher order
functions when appropriate. When dealing with concepts of the problem
domain though, those higher order functions should probably have
_names_. And when it is not possible to cast these HOFs in a _syntax_
that fits the usage of the problem domain, these named HOFs will
naturally find their way into macros ;^)

One could conceive of a loose ranking of modes of expression and levels
of abstraction. From lowest (least abstract) to highest:

language primitives
anonymous functions
named functions and higher order anonymous functions
(a tie here because naming is inherently more abstract
than anonymity, and HOFs are of course more abstract
than ordinary functions)
named higher order functions
macros
 
R

Raffael Cavallaro

Alex Shinn said:
We use adjectives and adverbs to modify existing words
without needing to come up with new words, and build further with noun
clauses and prepositions. So you can both "run quickly" and "swim
quickly," which is analogous to a higher order function (quickly)
working on two existing functions (run and swim).

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.

We don't say "he ran (large distance covered/unit time)" or "he swam
(large distance covered/unit time)." Instead, we give this abstraction,
(large distance covered/unit time) a name, "quickly."

I am most definitely _not_ arguing against the use of higher order
functions when appropriate. When dealing with concepts of the problem
domain though, those higher order functions should probably have
_names_. And when it is not possible to cast these HOFs in a _syntax_
that fits the usage of the problem domain, these named HOFs will
naturally find their way into macros ;^)

One could conceive of a loose ranking of modes of expression and levels
of abstraction. From lowest (least abstract) to highest:

language primitives
anonymous functions
named functions and higher order anonymous functions
(a tie here because naming is inherently more abstract
than anonymity, and HOFs are of course more abstract
than ordinary functions)
named higher order functions
macros
 
R

Raffael Cavallaro

Alex Shinn said:
We use adjectives and adverbs to modify existing words
without needing to come up with new words, and build further with noun
clauses and prepositions. So you can both "run quickly" and "swim
quickly," which is analogous to a higher order function (quickly)
working on two existing functions (run and swim).

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.

We don't say "he ran (large distance covered/unit time)" or "he swam
(large distance covered/unit time)." Instead, we give this abstraction,
(large distance covered/unit time) a name, "quickly."

I am most definitely _not_ arguing against the use of higher order
functions when appropriate. When dealing with concepts of the problem
domain though, those higher order functions should probably have
_names_. And when it is not possible to cast these HOFs in a _syntax_
that fits the usage of the problem domain, these named HOFs will
naturally find their way into macros ;^)

One could conceive of a loose ranking of modes of expression and levels
of abstraction. From lowest (least abstract) to highest:

language primitives
anonymous functions
named functions and higher order anonymous functions
(a tie here because naming is inherently more abstract
than anonymity, and HOFs are of course more abstract
than ordinary functions)
named higher order functions
macros
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top