Home > Archive > Functional > August 2007 > Re: shootout: implementing an interpreter for a simple procedural
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here] Pages: Pages: [1] 2
| Author |
Re: shootout: implementing an interpreter for a simple procedural
|
|
| André Thieme 2007-07-22, 7:09 pm |
| Jon Harrop schrieb:
> I finally managed to get a version working using the new camlp4 system to
> implement an in-line extensible parser. The result is a 68-line interpreter
> that runs more quickly than all other implementations so far:
>
> I think it is particularly interesting to note that the parser is shorter,
> faster and more extensible than the Qi implementation even though the
> target grammar is an s-expr!
The question is what you mean with "shorter".
In principle you can express a problem exactly the same in Lisp as you
could in OCaml (or Haskell).
These languages offer two interesting features: syntactic sugar for a
small set of lambdas (currying) and patter matching. Haskell also offers
lazyness which reduces the need for some macros (and can result in worse
performance).
On top of that there is not really much more that one can find in for
example OCaml. Currying and PM are also available in Lisp. In Lisp there
also is a dynamic environment and macros. These macros can also access
the Lisp environment at run time (well, any Lisp programming always
happens at runtime).
So, from that we know that in principle Lisp programs should be the same
(or shorter), complexity wise.
Counting lines makes not much sense for Lisp. Although it supports all
these programming paradigms it has a very unique style which will blow
up the LOC count in several cases. But from this it doesn't follow, that
coding takes longer.
This one liner: (defun make-accumulator (n) (lambda (i) (incf n i)))
gets usually written in three visible lines:
(defun make-accumulator (n)
(lambda (i)
(incf n i)))
OCaml has a lot of syntax which allows generally to express algorithms
with a smaller number of lines/chars (compared to Lisp).
Or see this Haskell function:
powerset = foldr (\x ys -> ys ++ (map (x:) ys)) [[]]
In Lisp we can do exactly the same one liner. Here it is (also in one
line, in some sense):
(defun powerset (set)
(reduce (lambda (x ys)
(append ys (mapcar (lambda (y)
(cons x y))
ys)))
set
:initial-value '(())
:from-end t))
Lisp does not offer a separate foldr and foldl. Reduce is doing both.
But in the case of a foldr we need to add :from-ent t
Here is the same Haskell code, indented with Lisp style:
powerset set =
foldr (\x ys ->
++ ys (map (\y
x:y)
ys))
[[]]
set
If Haskell also would use one function for foldr and foldl we also had
to add this line.
So, these two functions do exactly the same. Haskell uses more syntatic
sugar which cuts down the byte count.
When we take this in mind then the Lisp code that was presented took up
much less lines. Maybe around your OCaml solution. But it is very hard
to compare.
But it seems that your OCaml programs execute the task much faster.
Conceptually the Lisp programs don't have to be more complicated.
From that perspective I think your statement that your implementation
is shorter is not correct.
André
--
| |
| Joachim Durchholz 2007-07-23, 4:11 am |
| André Thieme schrieb:
> Counting lines makes not much sense for Lisp. Although it supports all
> these programming paradigms it has a very unique style which will blow
> up the LOC count in several cases. But from this it doesn't follow, that
> coding takes longer.
>
> This one liner: (defun make-accumulator (n) (lambda (i) (incf n i)))
> gets usually written in three visible lines:
> (defun make-accumulator (n)
> (lambda (i)
> (incf n i)))
There are two answers to that:
1. Coding doesn't take longer, but you can't place the same amount of
code on a screenful, so debugging and maintenance will take longer.
Note that your typical generic FPL not only fits on a line, it even
takes less of a line; the syntactic Haskell equivalent of the above
example would look like this:
make-accumulator N = incf N
(No, Haskell isn't cheating, it simply doesn't have or need macros and
quoting, so it can encode the same code with far less symbols.)
Now that's 27 instead of 52 characters, which means I can put nearly
double the code on a single line without cramming it.
(I'd expect OCaml to be slightly more verbose. Jon?)
2. You can always count nodes in the AST instead of lines of code. For
the above example, you'd end up at roughly the same figures for Lisp and
your generic FPL, but as soon as you declare macros in Lisp, the FPL
needs less nodes.
(There may be other effects. Jon?)
Regards,
Jo
| |
| Pascal Costanza 2007-07-23, 7:07 pm |
| Jon Harrop wrote:
> Tamas Papp wrote:
>
> Sure, but the vast majority of OCaml and Haskell coders who could use their
> excellent macro systems choose not to.
>
> I do not doubt that Lisp's macros are extremely useful for Lisp programmers
> but I would contest any generalization that macros are necessary for
> programming or that all languages should have macro systems, which is an
> opinion often put forward on c.l.l.
....or you just misunderstand them.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Cesar Rabak 2007-07-23, 7:07 pm |
| Jon Harrop escreveu:
> Joachim Durchholz wrote:
[snipped]
>
> Are you saying that macros reduce code size?
>
>
> Pattern matching is the single biggest advantage and is the main reason why
> OCaml, SML, Haskell and F# are all much more concise than Common Lisp. Look
> at the amount of code doing destructing in the above examples.
>
Humm... I still find your comparison loaded: you rule out the use of
libraries for pattern matching in Lisp. Why?
| |
| Dan Bensen 2007-07-23, 7:07 pm |
| Cesar Rabak wrote:
> Jon Harrop escreveu:
> Humm... I still find your comparison loaded: you rule out the use of
> libraries for pattern matching in Lisp. Why?
Because it sells books.
--
Dan
www.prairienet.org/~dsb/
| |
| André Thieme 2007-07-23, 7:07 pm |
| Joachim Durchholz schrieb:
> André Thieme schrieb:
>
> There are two answers to that:
>
> 1. Coding doesn't take longer, but you can't place the same amount of
> code on a screenful, so debugging and maintenance will take longer.
This might be true for several cases.
I also see the scenario in mind where longer names for variables or
functions bring in advantages for readability.
However, if you wanted then you could compress code in Lisp as well.
For example with my DEF:
(def make-accumulator (n) [incf n])
> Note that your typical generic FPL not only fits on a line, it even
> takes less of a line; the syntactic Haskell equivalent of the above
> example would look like this:
Well, for some situations you are right, for others you are not.
It depends on what you want to do.
I gave the example about calculating the powerset.
One other Haskell solution is for example this one:
powerset = filterM (const [True, False])
To do the same in Lisp you first need to write like 40 LOC preparation
code.
In other situations Lisp can be the better option.
Joel Raymond wrote about Erlangs advantages over Haskell:
http://wagerlabs.com/2006/1/1/haske...rlang-reloaded/
For example point 3.2 was talking about static typing and the extra
code it needed.
> make-accumulator N = incf N
Hmm, does Haskell have infc?
Is that some monad that can do the destructive manipulation on N?
What is the minus (between "make" and "accumulator") doing when it is
placed on the right side of a "="?
> (No, Haskell isn't cheating, it simply doesn't have or need macros and
> quoting, so it can encode the same code with far less symbols.)
It is true that the need for Macros in Haskell is reduced. This comes
from implicit currying but mainly from lazyness.
In Lisp you could do the same. You could teach Lisp implicit currying
and also implicit lazyness (altough I think that it would feel really
bad).
So yes, several things that are expressed in Lisp with Macros would be
expressed without them in Haskell. However, I am not sure if that comes
without performance hits.
> Now that's 27 instead of 52 characters, which means I can put nearly
> double the code on a single line without cramming it.
With short code examples it will probably often happen.
> 2. You can always count nodes in the AST instead of lines of code. For
> the above example, you'd end up at roughly the same figures for Lisp and
> your generic FPL, but as soon as you declare macros in Lisp, the FPL
> needs less nodes.
This might be a little misunderstanding.
Usually after introducing macros the count of nodes is reduced.
André
--
| |
| Cesar Rabak 2007-07-23, 10:05 pm |
| Dan Bensen escreveu:
> Cesar Rabak wrote:
>
> Because it sells books.
>
I see. . .
| |
| Joachim Durchholz 2007-07-24, 8:06 am |
| Matthias Benkard schrieb:
>
> Not really.
>
> First of all, INCF is a macro.
That's why I wrote "syntactic equivalent".
I was all talking about the overhead of having parentheses.
> How do you curry a macro? That doesn't make much sense to me.
I don't see any problems applying currying to macros that wouldn't apply
to functions, or vice versa.
You can explain currying as a purely syntactic device. You can "explain
it away" for functions by resorting to HOFs (and that's a useful
perspective for some questions around currying), but you don't have to.
> Second, INCF takes a place as its first argument, not a value.
Seems like a macro thing to me.
> Third, INCF takes a variable number of arguments. How is the compiler
> supposed to know wheter MAKE-ACCUMULATOR is of type Number a => a -> a
> or of type Number a => a?
There's no difference. In Haskell, make-accumulator would be exactly
equivalent to incf.
> So yes, claiming that the above pieces of code are syntactically
> equivalent _is_ cheating (macros are part of the syntax, after all).
> You may argue about the utility of macros, but that's beside the
> point, for the fact is, Common Lisp _does_ have macros (and places,
> and variable number argument lists, both of which I find extremely
> useful), and they're not going away anytime soon.
There is no difference between a macro and a function in Haskell.
In Haskell, there is no semantic difference between compile-time and
run-time evaluation, so any macro would be a function and vice versa.
(That's a general property of pure languages, and not due to Haskell's
nonstrict evaluation strategy.)
You *can* have macros in Haskell (just plop in a preprocessor), but they
aren't nearly as pressingly needed as in an impure language. (That may
be the reason why preprocessors are more en vogue for OCaml than for
Haskell.)
> I have yet to see a syntax that is
> both as flexible as and more concise than that of Common Lisp.
Drop the superfluous parentheses, for example. A minimum amount of
operator precedence and layout rules eliminates 99% of them.
That's "just lexical conciseness", you'll say, and you'd be correct.
However, when I look at the sheer percentage of screen estate these
parentheses are taking up, it's getting too much.
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 8:06 am |
| Jon Harrop schrieb:
> Joachim Durchholz wrote:
>
> Even if there is four times as much code?
Not enough of a difference to get above the noise level.
I spend 90% of my programming time designing things. (The other 90% are
debugging and maintenance, of course *g*)
I also happen to be a rather adept blind typist, so I wouldn't even
*think* about the parentheses.
>
> Lisp's verbosity stems primarily from its use of whitespace and parentheses
> as well as a lack of pattern matching.
Ah, right, lack of pattern matching tends to bloat any code.
I didn't notice this since the example code given didn't have any case
distinctions.
I'm still surprised it isn't already in widespread use in any new
language. I've been seriously missing that in any language that I've
been using since I got to know the concept (and even before).
> You can see this in almost any
> comparable programs written in the two languages (or any languages with the
> similar features, e.g. Haskell vs Scheme). Look at the intersect routines
> from my ray tracer. First the Lisp:
>
> (defun intersect (orig dir scene)
> (labels ((aux (lam normal scene)
> (let* ((center (sphere-center scene))
> (lamt (ray-sphere orig
> dir
> center
> (sphere-radius scene))))
> (if (>= lamt lam)
> (values lam normal)
> (etypecase scene
> (group
> (dolist (kid (group-children scene))
> (setf (values lam normal)
> (aux lam normal kid)))
> (values lam normal))
> (sphere
> (values lamt (unitise
> (-v (+v orig (*v lamt dir)) center)))))))))
> (aux infinity zero scene)))
>
> Then the OCaml:
>
> let rec intersect o d (l, _ as hit) (c, r, s) =
> let l' = ray_sphere o d c s in
> if l' >= l then hit else match s with
> [] -> l', unitise (o +| l' *| d -| c)
> | ss -> List.fold_left (intersect o d) hit ss
I think the Lisp would look better if it weren'd indented so much.
It might even get slightly shorter because some stuff could be written
inline.
(I can't say whether the above Lisp could be written more concisely though.)
>
> Are you saying that macros reduce code size?
First, I'm (wrongly) assuming that Lisp's relative verboseness comes
from parentheses (and additional whitespace needed because those
parentheses force you into more line wraps).
Seconds, I'm saying that needing macros means that you often writen the
same semantics twice, once as a function and once (for those cases where
it's a useful optimization) as a macro.
So a language that works well without macros is shorter.
(I assume that macros are more a library thing, not something that gets
written routinely or redundantly, so I don't think the effect is large.)
So, no, I'm saying that needing macros tends to increase code size,
though I can't say it would be much and suspect it isn't much indeed.
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 8:06 am |
| David Golden schrieb:
>
> Very, very lame, Jonnie boy.
Plonk.
| |
| Joachim Durchholz 2007-07-24, 7:08 pm |
| Tony Finch schrieb:
> I think the comparison would be fairer if you used the same variable names
> in each language. You've used words in the Lisp and single letters in the
> O'Caml, which undermines your argument.
Only partly.
In shorter code, fully descriptive names aren't as relevant since you
have fewer lines to check for cross-referencing code.
I see these name terseness elsewhere in functional code, including code
from people who are generally considered as "writing good style". (Take
a look at the Haskell Prelude, for example.)
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 7:08 pm |
| Cesar Rabak schrieb:
> Humm... I still find your comparison loaded: you rule out the use of
> libraries for pattern matching in Lisp. Why?
My answer would be:
Using a pattern matching library adds yet another dependency to your
code. Unless you know that the library is well-maintained, you don't
want this kind of dependency.
In other words, I suspect it would find lots of use it if became part of
the CLOS standard.
Regards,
Jo
| |
| Pascal Costanza 2007-07-24, 7:08 pm |
| Paul Rubin wrote:
> André Thieme <address.good.until.2007.dec.26@justmail.de> writes:
>
> You can't do anything of the sort. Consider that Haskell has no
> language support for exceptions or continuations, because they're
> implemented straightforwardly as library modules, using a combination
> of lazy evaluation and currying. They can't be implemented that way
> in Lisp, so exceptions are built into the language
No, exceptions can be implemented in a Common Lisp without exceptions
already built in. For example, see
http://www.nhplace.com/kent/CL/Revision-18.lisp
They are built into ANSI Common Lisp because (a) ANSI Common Lisp
doesn't make a distinction between built-in and library functionality
and (b) it's important that the same condition system is used throughout
your program, so that libraries can more easily react to exceptions from
other libraries.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Pascal Costanza 2007-07-24, 7:08 pm |
| Jon Harrop wrote:
> Lisp doesn't require tail calls and does require dynamic binding
> which undermines tail calls so few Lisps actually do tail calls and there
> is no standard.
Most Common Lisp implementations support tail call optimization in one
form or the other. It is true that there is no standard way to ensure
this, but saying that few Lisps do this is definitely wrong.
Dynamically scoped variables don't undermine tail calls either.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
|
|
| Joachim Durchholz 2007-07-24, 7:08 pm |
| David Golden schrieb:
> Joachim Durchholz wrote:
>
>
> And makes the code massively more annoying to read. In fact,
> the baroque syntax is the main reason I dislike Haskell
That's just as silly as saying "Lisp is unreadable because of those Lots
of Irritating Superfluous Parentheses".
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 7:08 pm |
| Pascal Bourguignon schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
>
> Oops! Now you'll have to teach this minimum amount of operator
> precedence and layout rules to the billions of macros out there.
Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
most parentheses.
The usual arithmetic/comparison/boolean/definitional hierarchy will do
fine, with the additional twist that juxtaposition is an operator that
binds most tightly (so sin x + 5 is (sin x) + 5, just as mathematical
tradition would have it).
User-defined operators shouldn't get additional precedences. Unless
you're doing an embedded language and have collected a *lot* empirical
data about operator usage in it, and are quite confident that you got
the precedences right. (Even Pascal got the relative precedence of
boolean and comparison operators wrong. And Niklas Wirth certainly has
spent a great deal of care on that one.)
Oh, and actually precedence shouldn't be attached to the function
definitions but to the operator symbols. We're talking initial parsing
here (whether by humand or machine), that's the step that happens before
semantics of any kind comes into play.
Even if you redefine +, it should keep its precedence level after all...
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 7:08 pm |
| Jon Harrop schrieb:
> Joachim Durchholz wrote:
>
> No way. You really wouldn't rather inherit 100kLOC of code that does the
> same thing as 400kLOC of code?
Frankly, I wouldn't care whether the imported code is 100kLoC or
400kLoC. I'd care more whether it's stable and has a healthy community.
The situation wasn't about importing code anyway, it was about writing
it. And for that, a factor-4 blowup isn't exactly what I'd like, but
it's definitely not a show stopper. Not if the AST is the same (I'd moan
about it, of course, but I've been writing 250kB of PHP without too much
pain in the past two years, and PHP is worse than anything we've been
discussing here!)
Regards,
Jo
| |
| Joachim Durchholz 2007-07-24, 7:08 pm |
| jayessay schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
>
>
> This is incorrect for several reasons, the most obvious being the lack
> of accounting for the variable arity of incf...
Haskell is a currying language, so at least this counterargument doesn't
hold.
With some handwaving, the above could could be written as
make-accumulator N ... = incf N ...
with the understanding that the three dots stand for an arbitrary number
of parameters to be copied through verbatim from left to right.
Actually, in Haskell,
make-accumulator N = incf N
is equivalent to
make-accumulator = incf
with the sole exception that the first declaration forces
make-accumulator to have at least one parameter.
Hope this clears it up a little.
Regards,
Jo
| |
| André Thieme 2007-07-24, 7:08 pm |
| Paul Rubin schrieb:
> Matthias Benkard <mulkiatsch@gmail.com> writes:
>
> incf is a macro because macros are the only way to make Lisp forms
> that don't evaluate their args.
This is half true. What happens in Haskell automatically is what you
have to do in ML and Lisp manually - embed code blocks in an (anonymous)
function object. In Lisp you can provide your own version of eval and
make code lazy by default.
> Haskell uses lazy evaluation and
> therefore all kinds of things that Lisp uses macros for, are done in
> Haskell as ordinary functions.
I think most trivial macros can be done with this lazy way in Haskell.
At the cost of runtime overhead.
One example are reader macros.
People sometimes complain about mathmatical notation in Lisp.
I complain about the one in other programming languages. In Lisp one
would write [7x₆ + 9π³ - 6ˣ]
vs 7*x[6] + 9*pi*pi*pi - pow(6, x)
Of course you could do the same in Haskell:
readableMath"7x₆ + 9π³ - 6ˣ"
At runtime some parser would begin its work. In Lisp it gets translated
into efficient machine code at compile time. But if someone wants he/she
could do it the same way as an OCaml or Haskell or Erlang user would.
I am also not sure how the less than 16 LOC of
http://www.gigamonkeys.com/book/pra...-framework.html
would look in one of these languages.
> Of course incf mutates its argument,
> which normally isn't done in Haskell. So you'd only code something
> like incf as a monad action.
Would you provide the one liner that is doing incf?
André
--
| |
| André Thieme 2007-07-24, 7:08 pm |
| Andy Freeman schrieb:
> On Jul 24, 5:59 am, Joachim Durchholz <j...@durchholz.org> wrote:
>
> (1) One doesn't "need" macros any more than one "needs" iteration
> statments - both are merely more convenient than the alternatives in
> certain situations.
> (2) "often"? I almost never write something as both a macro and a
> function. In fact, the whole point of writing something as a macro is
> usually that there's no reasonable way to write the semantics as a
> function.
>
> For example, consider python 2.6's "with" statement. There's no clean
> way to write it as a function, so pre 2.6 code basically repeats
> with's definition everywhere the functionality is used.
No clean way to do it in Python.
In Lisp and Haskell one could get such a "statement" in a clean way.
André
--
| |
| André Thieme 2007-07-24, 7:08 pm |
| Paul Rubin schrieb:
> André Thieme <address.good.until.2007.dec.26@justmail.de> writes:
>
> You can't do anything of the sort.
This is not correct.
> Consider that Haskell has no
> language support for exceptions or continuations, because they're
> implemented straightforwardly as library modules,
The same is true for Lisp. It comes with an exception system which is
programmed in Lisp. If you want you can make your own during the w end
and others can import it as a lib. For an exception system it mostly
makes sense if everyone is using the same. I guess that Haskell could in
principle have 30 of them but probably only one is widely used.
> using a combination of lazy evaluation and currying.
In Lisp it is done with a mix of functional programming, currying,
imperative programming and some few macros.
> They can't be implemented that way in Lisp
This is not correct.
You could implement implicit currying or lazyness in Lisp and put it
online as a lib that can be loaded into a running program.
Implicit lazyness would be a tough task, nothing for 30 minutes.
Maybe in Haskell you can do the same: write a lib that when loaded will
make Haskell implicitily eager. Don't know if that is possible and if
yes how easy it would be.
André
--
| |
| Markus E Leypold 2007-07-25, 8:05 am |
|
> Tony Finch schrieb:
>
> Only partly.
> In shorter code, fully descriptive names aren't as relevant since you
Rule of thumb for me: The larger the scope the more descriptive the
variable name should be. Actually modify that by how far away the
corresponding type definitions have been made:
let f l = ... (* bad *)
let f customer_list = ... (* better *)
let f (customers : customer list) = ... (* best *)
But
let f (customers ...) =
...
let process cs ... =
...
in
process customers ... ;;
because all information is there locally to derive what 'cs' is.
> have fewer lines to check for cross-referencing code.
> I see these name terseness elsewhere in functional code, including
> code from people who are generally considered as "writing good
> style". (Take a look at the Haskell Prelude, for example.)
:-).
I think this is a bit like naming conventions in physics: Even in
printed texts, it's always V that is used for voltage. In the same
spirit I use n,k,i for integers and l (or sometimes haskell style 'xs'
or 'as') for (local) variables. Of course code becomes less
understandable for other people this way, but that's what types are
for (so I try to choose descriptive type names and then l, being of
type 'customer list' is immediately understandable again).
Regards -- Markus
| |
| Joachim Durchholz 2007-07-25, 8:05 am |
| Pascal Bourguignon schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
>
>
> Like in:
>
> #define a(x,y) x*y
>
> perhaps?
If you really thought I were advocating C macros, you should seriously
consider getting professional help.
> To be able to use this macro as:
>
> (int)a(1.0+2.0,3.0+4.0)
>
> you need to actually define it as:
>
> #define a(x,y) ((x)*(y))
>
> so much for operator precedence and layout rules.
Strawman argument.
First, I've been talking about precedences in functions, not in macros.
(The only language that I know where this kind of problem arises even in
functions is Tcl. Guess which language I'll refuse to program in.)
Second, the C preprocessor does substitution at the character level
(sometimes at the token level if it's more recent than K&R C). That's a
far cry from modern preprocessing which does the substitutions at the
AST level, where this kind of problem doesn't arise in the first place.
> In lisp, you merely write it as:
>
> (defmacro a (x y) `(* ,x ,y))
>
> less parentheses than in C!
Suggesting pro-C advocacy is considered a serious offense here in
comp.lang.functional, you know ;-)
Regards,
jo
| |
| Joachim Durchholz 2007-07-25, 8:05 am |
| André Thieme schrieb:
>
> The same is true for Lisp. It comes with an exception system which is
> programmed in Lisp. If you want you can make your own during the w end
> and others can import it as a lib.
Hm... I think that w end would be just the programming.
Designing an exception system well requires a great deal of experience.
> For an exception system it mostly
> makes sense if everyone is using the same. I guess that Haskell could in
> principle have 30 of them but probably only one is widely used.
Confirm.
> This is not correct.
> You could implement implicit currying or lazyness in Lisp and put it
> online as a lib that can be loaded into a running program.
> Implicit lazyness would be a tough task, nothing for 30 minutes.
In any language where that is possible at all.
Implicit laziness requires a great deal of support from the run-time
system to get even near acceptable performance. I don't think that Lisp
could do that; you'd essentially end up reimplementing Haskell in Lisp
(or a lazy Lisp in Lisp).
> Maybe in Haskell you can do the same: write a lib that when loaded will
> make Haskell implicitily eager. Don't know if that is possible and if
> yes how easy it would be.
No, that's not possible.
You can't look "under the hood of the implementation" in Haskell as you
would in Lisp.
Novices often try to achieve efficiency by forcing expressions into
eager evaluation. Most fail, because the eagerness operators in Haskell
are nontrivial to use; even those who succeed have rather ugly code and
drop the practice quickly.
OTOH there are other optimization techniques that work well.
(Memoization is a popular alternative and does not require you to hash
your code up.)
Leaving optimization and debugging purposes aside, I haven't seen
anybody wanting eager evaluation in Haskell in years, not even in
specific situations and most certainly not as a by-default strategy. (I
believe the latter is more because those who find lazy evaluation
utterly unpalatable don't use Haskell for long.)
Regards,
Jo
| |
| Joachim Durchholz 2007-07-25, 7:07 pm |
| Bah. Answering is pointless if the other person just redefines the topic
to make a point.
| |
| Joachim Durchholz 2007-07-25, 7:07 pm |
| Matthias Benkard schrieb:
> Hi,
>
>
>
> Well, what I was trying to say was that the given pieces of code were
> _not_ syntactically equivalent, because in Lisp, INCF is a part of the
> syntax, whereas in Haskell, it is not.
Heck, this entire subthread is about syntax and parentheses.
I don't get why people insist on changing the subject to to pick a nit.
I'm well aware that macros are a different concept than functions.
But that's not what I'm talking about; all I want to say is that Lisp's
insistence on not having operator precedence comes at the price of
having to write lots of parentheses when entering code. And that these
parentheses, tiny as they are in isolation, take up a good deal of
screen space because there are so many of them.
If I were talking about semantic differences, I'd have said that the
difference between macros and functions vanishes in pure languages, so
you can leave it to the compiler do decide what to consider a macro and
what to consider a function.
I'd also have pointed out that the various quoting mechanisms are
superfluous in Haskell; the subtle semantic differences between quoting
mechanisms is what keeps me from using Lisp. (And possibly others, too;
learning the differences is hard, and applying the right quoting
mechanism and the right level of quoting can be difficult unless you
know exactly what you're doing - there's a rather steep learning curve
in that particular area of Lisp, an area that doesn't even exist in most
other languages.)
>
> Yes, that's the point. In other languages, you would need an
> additional syntactic device to distinguish places from values. As
> INCF defines its own syntax, that is not necessary in Lisp.
What, then, is a place?
>
> Macros are different from functions not only in their time of
> evaluation, but also in their semantics. Their purpose is not
> precomputing stuff at compile-time, but the definition of new syntax
> and transformation of code.
Code transformation is done by the compiler in Haskell.
Abstraction (i.e. new languages) is daily staple in Haskell. Sure,
Haskell embedded languages cannot do fancy syntax, but if you're fine
with frugal syntax, you define your embedded language simply as a set of
HOFs to use.
All without macros...
>
> That may be one reason. Another reason may be the higher complexity
> and intrusiveness of macros in a language with complex syntax.
Seems reasonable.
>
> Oh yes, lexical conciseness is a form of conciseness all right. I'd
> love to see the syntax you're thinking of.
Hmm... I think I already outlined it elsewhere.
Anyway, here goes:
First, a predefined set of operator precedences. Precedence levels would
be the usual suspects:
Binding =
Boolean Additive |
Boolean Multiplicative &
Comparison < = > <= >= !=
Arithmetic Additive + -
Arithmetic Multiplicative * /
Throw in an "indendation is another way to write parentheses" rule.
Stick with parentheses otherwise.
Creating new precedence levels should be possible, but be a rare exception.
This is just a rough sketch.
The point of the indentation rule is that you can freely trade
horizontal and vertical space. And you don't need closing parentheses
anymore (I think humans concentrate on the beginning of a parentheseized
expression, the ends are curiously uninteresting - and indentation rules
are asymmetric, inverting the lines of a structurally indented program
is not the same as inverting the order of symbols in parenthesized
expressions).
Regards,
Jo
| |
| Dan Bensen 2007-07-25, 7:07 pm |
| >>>> Jon Harrop escreveu:
[color=darkred]
[color=darkred]
Markus E Leypold wrote:[color=darkred]
> Actually I don't see:
> 1. Jon didn't hype his book in this thread.
First of all, Marcus, Jon's signature does advertise his book, so
he has directly advertised his book in this thread simply by posting
to it. As for "hyping", it's not necessary to promote the book
directly. It may be enough to draw programmers toward OCaml by making
comparisons that are unfairly biased against Lisp, which Jon has been
doing repeatedly.
> 2. That someone is working in a given subject area X and actually is
> making money from it -- is that disqualifying him from making
> useful and true statements on usenet?
Markus, do you consider it "true and useful" to say that pattern-
matching libraries are "Greenspunning"? Do you think ML languages
are "much more concise" than Lisp? I don't think those statements
are either true or useful. I don't think libraries and simple macros
are Greenspunning, and I don't think the ML family is "much" more
concise than Lisp when you take macros into account.
--
Dan
www.prairienet.org/~dsb/
| |
| Pascal Costanza 2007-07-26, 7:06 pm |
| Pascal Costanza wrote:
> Jon Harrop wrote:
>
> Quoted out of context.
Jon, I didn't get the intent of your post the first time around, and I
apologize for my knee-jerk reaction.
Here is a more precise answer: For a good exception handling system, you
don't need full continuations. One-shot escaping continuations +
unwind-protect / try-finally / dynamic-wind, or the like, are
sufficient, and core Common Lisp has both. You don't need to implement
an interpreter for a different language that has continuations for
implementing exception handling in core Common Lisp, and this is what
the implementation behind the link above shows. So this has nothing to
do with Turing equivalence - we have a true embedding of exception
handling here.
So how are the benchmarks for my last version of the minim interpreter
coming along?
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| André Thieme 2007-07-26, 7:06 pm |
| Joachim Durchholz schrieb:
> I'm well aware that macros are a different concept than functions.
>
> But that's not what I'm talking about; all I want to say is that Lisp's
> insistence on not having operator precedence comes at the price of
> having to write lots of parentheses when entering code. And that these
> parentheses, tiny as they are in isolation, take up a good deal of
> screen space because there are so many of them.
That Lisp has all these parens has mainly two reasons.
First: they organize code itself in trees, making it trivially
transformable.
Translation into a syntax tree is not important anymore, because code
already is one. Having so easy accessible macros comes from representing
code inside one of the most flexible datastructures.
But even if we ignore that there is another design descision:
having functions that can take any number of arguments.
To make that possible you need two tokens. The parens just look
better than most other stuff.
One might think: hey, why not making the first argument to a function
call always the number of arguments that will follow?
Then no parens are needed. Instead of (+ 1 2 3) we would say:
+ 3 1 2 3
But then the problem is that an argument can be a function call itself.
So we need another token for that which means: function application will
follow. Let's make it "§". So instead of (+ 1 (* 1 2) 3) we say:
+ 3 1 $ * 2 1 2 3
Again we have two tokens. The new argument and §, instead of ( and ).
And if you ask me: I know which I prefer.
With the descision of allowing functions that take any number of
arguments Lisp has the nice feature that packing data into a list before
making it an argument is done by the compiler.
(+ 1 2 3) instead of (+ (list 1 2 3))
> What, then, is a place?
Do you know C? Think about something that is on the left side of a "=".
Left hand value.
x[5] = 100;
Then x[5] is the place. A place is a syntactical construct that looks
like accessing a value. x[5] will in nearly all cases get replaced by
the compiler with its value. But on the left side of a = it behaves
different. If x[5] == 17 then
x[5] = 100;
does not mean
17 = 100;
> Code transformation is done by the compiler in Haskell.
> Abstraction (i.e. new languages) is daily staple in Haskell. Sure,
> Haskell embedded languages cannot do fancy syntax, but if you're fine
> with frugal syntax, you define your embedded language simply as a set of
> HOFs to use.
You can do the same in Lisp by making things lazy. In Lisp it would be
uglier than in Haskell because you would explicitily say
(delay (+ 1 2 3)) and (force xyz).
And yes, I think with lazy evaluation Haskell comes much closer to what
macros can do in a usable way than most other languages.
> All without macros...
Lisp could also do it. But it does not have to rely on lazyness.
In Lisp you get very nice syntactical abstractions.
All without lazyness...
André
--
| |
| André Thieme 2007-07-26, 10:05 pm |
| Jon Harrop schrieb:
> André Thieme wrote:
>
> Assuming, of course, that you never want to communicate with the outside
> world, where everyone has ditched s-exprs in favour of a plethora of
> domain-specific syntaxes: C, C++, Java, C#, regexps, dna, protein, html,
> xml, svg, sql.
html is in nearly all cases like s-expressions plus noise and xml is
in all cases like s-expressions plus noise.
I don't know if there exist more lines of code in the languages C, C++,
Java and C# or more xml...
> In practice, s-exprs are so rare outside Lisp/Scheme that a "syntax is not
> important anymore" attitude gets you nowhere.
Although Java and C# are so called modern languages with lots of syntax
they are usually much more verbose than Lisp code.
Which Syntax is better for what case? As soon your language comes with
syntax someone else (the language designer) decided what the users have
to use. Every year a new language comes out and suggests to use a new
syntax. Each has its specific advantages. Lisp is the language that
initially comes without syntax. This puts you into the position to have
them all.
>
> Turing argument.
You are not right this time. It is easy in Lisp.
Explicit laziness can be done in a few LOC. Look into PAIP.
André
--
| |
| Dan Bensen 2007-07-27, 4:17 am |
| > Regards -- Markus (Who think's that some of the participants in
> this slug fest should better their logic by reading e.g. here:
> http://www.nizkor.org/features/fallacies)
Markus, I've already KF'd you, because I find your posts misleading
and argumentative. But since you went so far as to cite logical
fallacies, I'll describe the fallacies that you've been commiting.
Your main problem seems to be an inability to address comments
without distorting them, which is classic trolling behavior.
Markus E.L. wrote:[color=darkred]
> Oh I see. How bad.
Straw man.
http://www.nizkor.org/features/fallacies/straw-man.html
I never said advertising was bad. I only suggested that your
statement was inaccurate, because Jon hypes OCaml and advertises
his book.
[color=darkred]
> And pulling them to himself just by alienating them to Lisp.
> Don't be ridiculous. Jon is not the only OCaml developer around.
Red herring.
http://www.nizkor.org/features/fall...ed-herring.html
The question is not whether other OCaml developers post to the usenet,
but whether Jon has been trolling. He has been the only developer
regularly making comparisons that are unfairly biased against Lisp.
[color=darkred]
> I think expresses very well, why Jon distains pattern matching
> libraries in Lisp and thinks that pattern matching belongs into
> the core language. So indeed the hint 'Greenspun' does communicate
> the argument very concisly.
Red herring.
The question is not whether the term expresses a sentiment, but
whether the sentiment is warranted. I don't think a simple library
counts as "Greenspunning".
[color=darkred]
> Unfortunately I'm programming in ML languages rather than Lisp,
> preferrably in OCaml. So ... -- I'm certainly biased. Regarding
> pattern matching -- Yes, I think ML (and Haskell pattern matching is
> more concise than anything of that kind I have seen in Lisp so far,
> and certainly more than nesting of conditional statements.
Red herring.
We're not talking about the conciseness of pattern matching alone.
We're talking about the overall conciseness of each language,
based on pattern matching, macros, and all other features.
> I wonder what you think "greenspunning" actually is?
Regardless of its exact definition, it's a derogatory term that
suggests an inefficient, unmaintainable, unnecessary implementation
of features built into another language. Macros make Lisp pattern-
matching libraries both efficient and maintainable, and ML's lack
of macros makes these libraries necessary if one wants both macros
and pattern matching.
[color=darkred]
> You believe that. Other people believe differently. How can you reach
> agreement? Certainly not by ad hominem attacks and attacking straw men
> (what, at the end of the day, the argument "he sells book" actually
> is.
Straw man.
No-one objects to selling books. Only to trolling.
> And if I consider further, trying to contradict my lack of
> understanding of this argument
I don't contradict your lack of understanding at all, Markus.
I totally agree that you lack a basic understanding of Jon's
trolling and what other people have been saying to you.
> by constructing a case against JH by some other route
> ("Greenspunning", "It's wrong than ML is more concise")
> is also a strawman, because it makes the "he sells books"
> argument not any more valid, not one iota).
Obvious straw man, made even worse by appealing to the straw-man
fallacy yourself. It's Jon who's making the Greenspunning arguments,
and no-one objects to selling books. I think you're another troll.
--
Dan
www.prairienet.org/~dsb/
| |
| Joachim Durchholz 2007-07-27, 8:05 am |
| André Thieme schrieb:
> That Lisp has all these parens has mainly two reasons.
> First: they organize code itself in trees, making it trivially
> transformable.
> Translation into a syntax tree is not important anymore, because code
> already is one. Having so easy accessible macros comes from representing
> code inside one of the most flexible datastructures.
This argument applies to any kind of regular syntax.
Lisp could thrive with predefined operator precedence plus
indentation-is-parentheses (plus parentheses for those cases where you
still need them), have 90% less parentheses, 30% more code per page, and
*still* be simple to process macrologically.
> But even if we ignore that there is another design descision:
> having functions that can take any number of arguments.
> To make that possible you need two tokens.
You can make that possible without the need for additional tokens.
Simply use currying.
> One might think: hey, why not making the first argument to a function
> call always the number of arguments that will follow?
> Then no parens are needed. Instead of (+ 1 2 3) we would say:
> + 3 1 2 3
Not a good idea anyway. You'd end up chasing number-of-arguments bugs.
> With the descision of allowing functions that take any number of
> arguments Lisp has the nice feature that packing data into a list before
> making it an argument is done by the compiler.
> (+ 1 2 3) instead of (+ (list 1 2 3))
OK, currying cannot handle that case; the Haskell equivalent of the
above would be
plus [1 2 3]
However, such lists are needed only in a few places in a program. I
don't think that this case warrants special attention to make it easy -
not if it constrains the design space elsewhere.
>
> You can do the same in Lisp by making things lazy.
Ah, but laziness cannot be efficiently implemented in Lisp.
Nor would that be very desirable in a language with mutation.
> In Lisp it would be
> uglier than in Haskell because you would explicitily say
> (delay (+ 1 2 3)) and (force xyz).
The main difference is that modern non-Lisp FPLs leave out the outermost
pair of parentheses :-)
(... and the parentheses at the outermost level between operators)
> And yes, I think with lazy evaluation Haskell comes much closer to what
> macros can do in a usable way than most other languages.
Then we agree here.
>
> Lisp could also do it. But it does not have to rely on lazyness.
You don't need laziness to get rid of most parentheses.
It's completely orthogonal to semantics.
> In Lisp you get very nice syntactical abstractions.
> All without lazyness...
Regards,
Jo
| |
| Joachim Durchholz 2007-07-27, 8:05 am |
| Dan Bensen schrieb:
>
>
>
> Markus E Leypold wrote:
>
> First of all, Marcus, Jon's signature does advertise his book, so
> he has directly advertised his book in this thread simply by posting
> to it.
Now you're exaggerating.
I actually had to look at Jon's last post to even notice that he had a
URL to his book in the sig.
> As for "hyping", it's not necessary to promote the book
> directly. It may be enough to draw programmers toward OCaml by making
> comparisons that are unfairly biased against Lisp, which Jon has been
> doing repeatedly.
I think both sides are guilty of presenting things in a favorable light.
In fact this is a long-standing gripe that I have been having about the
Lisp community. Di vantages are discussed far more openly in other
communities (e.g. the Haskell community is quite open about the
advantages and di vantages of laziness).
Not that I don't understand that. If you keep taking unfair flak for
decades (literally!), such a stance can easily evolve and solidify into
common consensus.
Oh, and there's another big difference. Most discussions about relative
advantages and di vantages evolve into matter-of-belief statements.
Jon is far more down to facts than that: He's giving benchmarks, making
himself open to critique; he's adapting the benchmarks in response to
the critique; he's counting lines, characters, or tokens and arguing his
choice of criteria rationally.
You can agree or disagree with his findings, but he never asks you to
believe.
Few Lispers typically argue on that level. I'm not in any Lisp
community, but those Lispers that I have come across elsewhere have a
noticeable affinity to belief-based arguments (and are generally taken
less seriously as a consequence).
If these observations are true and relevant, then Jon must indeed come
across as a troll, since he doesn't accept the typical Lisper's code of
conduct. However, I think it's the code of conduct that's more to blame.
(OK, I'll also admit that Jon can be rather rude and tends to generalize
his findings a bit more than I'm inclined to follow. I'm not sure
whether that's his normal tone or was provoked by stubborn disbelief
reactions from the Lisp community.)
>
> Markus, do you consider it "true and useful" to say that pattern-
> matching libraries are "Greenspunning"? Do you think ML languages
> are "much more concise" than Lisp? I don't think those statements
> are either true or useful.
From what I know, at least the second statement is true.
I don't know what "Greenspunning" is, but those pattern-matching
libraries that I have seen weren't very well-designed; also, I doubt
that a library can reap all the benefits that built-in pattern-matching
can, though I'm unsure how much of that doubt is well-founded. In other
words, I tend to the position that lack of pattern matching might be a
reasonable criticism of Lisp.
> I don't think libraries and simple macros
> are Greenspunning, and I don't think the ML family is "much" more
> concise than Lisp when you take macros into account.
I have seen some of the things that can be made concise in Haskell, and
it was outright amazing.
(If Haskell could marshall thunks, I'd be programming in the language
right now.)
My ability to assess the usefulness of macros is slightly limited.
However, I'm having trouble with limiting what a macro can do. In
principle, a macro can cause its parameters to be evaluated once, not at
all, or an arbitrary number of times; it could do the evaluation at
expansion time or at evaluation time.
If Lisp were pure, it wouldn't matter when exactly what is evaluated,
but then Lisp wouldn't need macros anyway :-)
Oh, and with standard macros from the standard libraries, these problems
usually don't happen - I'd assume that every macro has a clear
description when it evaluates what parameter, or it's easy to look that
up. The problems start to arise when people write their own macros. (And
with standard macros where you just *think* you had understood its
behavior, and overlooked some special case which comes back to bite you,
possibly years after you learned to use that macro. Or when different
vendors use slightly different interpretations of the standard and the
code starts to break.)
Just an outsider's view, possibly totally irrelevant and off the mark.
Regards,
Jo
| |
| Joachim Durchholz 2007-07-27, 8:05 am |
| Chris Smith schrieb:
> Interestingly, one thing that IS true is that eager-evaluation pure
> functional programs are actually asymptotically worse than alternatives
> for some problems.
Any background information where I can read up on that?
Regards,
Jo
| |
| Cesar Rabak 2007-07-27, 8:05 am |
| Markus E.L. escreveu:
> Dan,
[snipped]
> Regards -- Markus
>
> (Who think's that some of the participants in this slug fest should
> better their logic by reading e.g. here:
> http://www.nizkor.org/features/fallacies)
>
Markus,
It interesting yourself sent this link. It seems that bored people could
easily maje a table for each of your recent post agains one of the
fallacies described in your reference.
| |
| Cesar Rabak 2007-07-27, 8:05 am |
| Markus E.L. escreveu:
[snipped]
[color=darkred]
>
> Behaviour? Perhaps just write to his teacher ... :-/. People, grow
> up. This is usenet: The only way to enforce is not to respond. Since
> c.l.l. obviously can't ignore JH's posts the problem AND there are
> people who don't want them, this is a c.l.l. problem. And you will
> have to live with it. And perhaps better not attack other people too,
> who happen to defend Jon. And, last, to go back to the beginning of
> these threads: No reason to bring your venom to c.l.f.
Hey man! How inconsistent are willing to go? Your argument: "People,
grow up. This is usenet:" _But_ if people respond to Jon's crossposted
posts you childly complain: "No reason to bring your venom to c.l.f."
What's the e-address of the teacher of yours?
>
>
> Maybe. On the other side (without researching what Jon actaully
> posted), I find it somehow doubtful that discussion of limits and
Which, brings to the kernel of reason people starts to find evidence
your trolling as well. . .
[snipped]
> Call me a troll. :-) You wouldn't be the first one.
So your behaviour is recurrent...
>
>
> My impression is, that there are two parties that don't want to
> understand. I have seen enough instances of JH listening to arguements
> that I wonder why the "problem" is so prevalent in c.l.l.
JH interest in 'listening' arguments to c.l.l is another very loaded
assertion of yours. He's fishing here all the rebuttals c.l.l
gratuitously offer him. What uses he makes of them is OT in this discussion.
| |
| Dan Bensen 2007-07-27, 7:06 pm |
| > Dan Bensen schrieb:
Joachim Durchholz wrote:[color=darkred]
> Now you're exaggerating.
A little bit, but it's hard to be both exact and concise.
[color=darkred]
> I think both sides are guilty of presenting things in a
> favorable light.
Yes, I agree with you. The only defense I can offer is that
Lispers usually stay in their own back yard.
> Oh, and there's another big difference. Most discussions about
> relative advantages and di vantages evolve into matter-of-belief
> statements. Jon is far more down to facts than that: He's giving
> benchmarks, making himself open to critique; he's adapting the
> benchmarks in response to the critique; he's counting lines,
> characters, or tokens and arguing his choice of criteria rationally.
I'm getting tired of this thread, Joachim, so I'm not going to answer
in depth, but benchmarks don't address RAD, hot-loading code, and other
dynamic issues. It's not fair to obsess over runtime performance in a
Lisp forum, because Lisp trades runtime optimization for many other
things. Also, comments like
>I really hope they teach you some good languages as well...
are insults, not facts.
[color=darkred]
> From what I know, at least the second statement is true.
> I don't know what "Greenspunning" is, but those pattern-matching
> libraries that I have seen weren't very well-designed;
I don't know how good they are, but they can be fixed or replaced
if necessary. Lisp already has excellent iteration and object systems
implemented as libraries.
> My ability to assess the usefulness of macros is slightly limited.
> However, I'm having trouble with limiting what a macro can do.
> In principle, a macro can cause its parameters to be evaluated once,
> not at all, or an arbitrary number of times; it could do the
> evaluation at expansion time or at evaluation time.
No, macros are always called at expansion time, and they never evaluate
their arguments. The only thing that evaluates expressions at eval time
is the code returned by the macro.
> The problems start to arise when people write their own macros.
That depends on the individual. Macros are very powerful, and in
experienced hands, they're plenty safe.
> Just an outsider's view, possibly totally irrelevant and off the mark.
Always welcome. :)
--
Dan
www.prairienet.org/~dsb/
| |
| Pascal Costanza 2007-07-27, 7:06 pm |
| Jon Harrop wrote:
> A Lisper once wrote a paper on Lisp, comparing it only to Java:
>
> http://p-cos.net/documents/dynatype.pdf
....which would be me.
> The author can say "Lisp is better than Java", which is fine.
I don't say that in that paper. More specifically, I am not advocating
Lisp or Scheme in that paper at all.
> But he can't say:
>
> "However, statically typed languages require programmers to deal with all
> methods of an interface at once..." -- page 3.
>
> Just a simple mistake I thought. So I wrote to him, clarifying the mistake,
> giving a counter example written in OCaml and explaining that inference
> solved that problem many years ago.
Quoting that sentence out of context is a misrepresentation of the
paper. I state the following very clearly in the introduction:
"This paper mainly focuses on shortcomings in Java (again, because of
the workshop theme) which is only one example of a statically typed
programming language. There are others that may have different and
actually better solutions by default. But I hope this serves as a good
starting point for a more objective analysis of an otherwise usually
very heatedly discussed topic."
> I expected the paper to be altered but,
> instead, it was published and I received the response:
>
> "Thanks for your interest in improving that paper, but at the moment I
> have no intention to make any changes to it."
>
> Take from that what you will.
The main reason is lack of time. Since the paper is very clearly
presented as experimental work, and is in no way misleading about its
actual merits, I see no reason to change or withdraw it. It has indeed a
provocative tone, but that's because the workshop to which I submitted
it asked for provocative position statements.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Joachim Durchholz 2007-07-27, 7:06 pm |
| Tamas Papp schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
>
>
> It has been done -- would you claim that Dylan is thriving?
If Dylan doesn't thrive, that might have any number of reasons.
(Including unavailability of editors that can't properly block-indent,
NIY syndrome, and a couple of others.)
>
> Whether you use them in a few places or a lot depends on your
> programming style, which is shaped by the languages you have used in
> the past. I would be more careful with making claims like this one.
Well, what I have seen here and elsewhere surely had a *lot* of parentheses.
>
> Why? What is "efficient" enough for you? Lazyness for part of your
> program is easy to implement, and is pretty efficient. Of course it
> will not be as efficient as Haskell, where lazyness is integrated into
> the whole language.
Exactly.
> However, lazyness is not the holy grail,
Nor do I think it is.
I was just responding to the claim that "you can do the same in Lisp by
making things lazy". I don't think that would be practical due to the
overhead.
Hey, it's even difficult to get it efficient enough for day-to-day use
in Haskell. Haskell run-time systems are specifically geared towards
lazy evaluation (Google for "tagless spineless machine"), and Haskell
compilers do a *lot* of strictness analysis to get rid of lazy
evaluation wherever possible, which is massively aided by static typing.
Nothing of this is possible in Lisp (some of it not even desirable to
keep the language useful for other goals).
So I conclude that "making things lazy to get it to work" isn't really
an option - unless that laziness is controlled tightly and applied
sparingly, that is, but that's not exactly how you'd do an embedded
domain-specific language.
Note that this all is beside the point anyway. You don't need lazy
evaluation to chain up HOFs, that's possible in a strict language as
well (and hence in Lisp, too).
Sorry for not noticing the bigger context when reading the "by making
things lazy" sentence.
> it makes
> a lot of sense if you can write your algorithm more simply and a lot
> of the stuff doesn't get evaluated, but it can be a curse if you know
> that 99% of operations you code need to be evaluated anyway. Most of
> the time, it doesn't make a whole lot of difference in performance.
> And I have seen Haskellers fight the language to get non-lazy
> evaluation.
I have seen people in other languages fight strictness (but, of course,
attributing the problems to other things because everybody accepts
strictness as a given). For example, everybody is accepting tons of
contortions when all that you want to write down is "forall natural
numbers, do so-and-so until condition this-and-that arises". Easy with
laziness, contortious with strictness because you can't map the "forall
natural numbers" part to a language construct directly - but people
don't see it as a contortion, they just see it as how things are (if
they think about it at all).
To do a real comparison, you'd probably need to train nonprogrammers
both approaches in parallel.
Regards,
Jo
| |
|
| Tamas Papp wrote:
> Joachim Durchholz <jo@durchholz.org> writes:
>
>
> It has been done -- would you claim that Dylan is thriving?
>
>
> Whether you use them in a few places or a lot depends on your
> programming style, which is shaped by the languages you have used in
> the past. I would be more careful with making claims like this one.
>
>
> Why? What is "efficient" enough for you? Lazyness for part of your
> program is easy to implement, and is pretty efficient. Of course it
> will not be as efficient as Haskell, where lazyness is integrated into
> the whole language. However, lazyness is not the holy grail, it makes
> a lot of sense if you can write your algorithm more simply and a lot
> of the stuff doesn't get evaluated, but it can be a curse if you know
> that 99% of operations you code need to be evaluated anyway. Most of
> the time, it doesn't make a whole lot of difference in performance.
> And I have seen Haskellers fight the language to get non-lazy
> evaluation.
>
> Tamas
Lazyness is also useful for separation of concerns.
read a file as if it was slurped entirely, process it as if it was fully
available in memory, write the result as if they were all processed...
But do it in constant space. And no need for complex interleaving code.
I think that's pretty nice !
Sacha
| |
|
| Jon Harrop wrote:
> Joachim Durchholz wrote:
>
> I disagree. The problems with Lisp run far deeper than syntactic issues.
> Having such an archaic syntax forced upon you is one of the main reasons
> people never bother starting with Lisp (poor performance is the other). But
> Lisp lacks so many features that people take forgranted now. It just isn't
> going anywhere.
>
There you go again =)
>
> As Haskell has shown, laziness cannot be implemented efficient at all.
>
As ruby and python have shown, programmers are only motivated by efficiency.
Sacha
| |
| Joachim Durchholz 2007-07-27, 7:06 pm |
| Dan Bensen schrieb:
>
> I'm getting tired of this thread, Joachim, so I'm not going to answer
> in depth, but benchmarks don't address RAD, hot-loading code, and other
> dynamic issues. It's not fair to obsess over runtime performance in a
> Lisp forum, because Lisp trades runtime optimization for many other
> things.
Fully agreed that there are trade-offs involved, and that picking on
just performance isn't exactly fair.
I also agree that Lisp was unsurpassed for RAD, hotloading, and a few
other things, and for quite a long while.
Today, however, I'd say that Lisp isn't the only language it its various
niches anymore.
>
> No, macros are always called at expansion time, and they never evaluate
> their arguments. The only thing that evaluates expressions at eval time
> is the code returned by the macro.
Hmm... that sounds definitely un-Lispish to me. Surely you can combine
macros, or pass parameters that are evaluated by the macro (or when
calling the macro) to control what the macro does?
Regards,
Jo
| |
|
|
|
| Jon Harrop wrote:
> Sacha wrote:
>
> Theoretically good but practically bad performance is only suitable for
> academics.
>
I guess those guys at google are desperately theoretical.
Sacha
| |
|
| Jon Harrop wrote:
> Sacha wrote:
>
> Is someone at Google using a lazy language?
>
I never said that.
>
>Theoretically good but practically bad performance is only suitable for
>academics
I hear these guys at google use a fair bit of python. I might be
mistaken, but my understanding was that this language is not very fast
and would perform poorly in your ray-tracer benchmark. And yet, this
rather successful company uses it. The services they provide are
responsive enough in my opinion.
So it would seem raw language efficiency doesn't matter as much as you
think when its about real life programming.
Abstraction is key, lazyness helps in this regard and comes at a price.
Of course it does.
The whole functional programming style is about abstraction over
efficiency.
Sacha
| |
| Joachim Durchholz 2007-07-27, 7:06 pm |
| George Neuner schrieb:
>
> Actually Dylan had many supporters back when it used s-exprs. Support
> began to fall away when the operator precedence syntax was introduced.
> At first programmers could use either syntax, but most users preferred
> s-exprs and nearly everyone stopped using it when the s-expr syntax
> was dropped (a move pushed by salespeople who didn't understand their
> importance to Dylan's acceptance).
Strange, strange, strange.
Not that salespeople did dumb things (that's normal).
I'm a bit surprised that people have preferred the S-expressions. Did
anybody give reasons? Was the drop in support due to changes to the
syntax, or was it just a correlation?
Regards,
Jo
| |
| Joachim Durchholz 2007-07-27, 7:06 pm |
| Larry Clapp schrieb:
> On 2007-07-27, Joachim Durchholz <jo@durchholz.org> wrote:
>
> You guys are talking past each other. Dan's talking about macros from
> a strict technical sense and Joachim is talking not only about that,
> but also about the code a macro generates.
>
> (defmacro example (a b c d)
> `(progn
> ,b
> ,c
> ,c
> (eval (progn ,@d))))
>
> This (generates code that) ignores A, evaluates B once, C twice, and D
> at runtime.
Ah, thanks.
Then my original assumptions do indeed hold.
Regards,
Jo
| |
| Pascal Costanza 2007-07-27, 7:06 pm |
| Joachim Durchholz wrote:
> George Neuner schrieb:
>
> Strange, strange, strange.
> Not that salespeople did dumb things (that's normal).
> I'm a bit surprised that people have preferred the S-expressions. Did
> anybody give reasons? Was the drop in support due to changes to the
> syntax, or was it just a correlation?
I am not surprised at all. Apparently, the main target audience
effectively were Lispers, and Lispers who have considerably experience
with s-expressions typically prefer them over more mainstream syntaxes.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Joachim Durchholz 2007-07-28, 4:16 am |
| George Neuner schrieb:
> The difficulty lies in choosing the set of preconditions to allow
> reasonable speculative evaluation along relevant program paths while
> limiting it along irrelevant ones. Just performing the equivalent of
> a breadth-first search among the ready paths is relatively easy, but
> it wastes cycles and doesn't buy much in terms of enhanced
> performance. I've been noodling the precondition issue for a while
> and I don't yet have a satisfactory answer. It seems to be a hard
> problem.
My approach would have been "if there are two subexpressions in an
expression, fork each expression off in a separate thread". On a
uniprocessor machine, this will indeed give you just the normal
evaluation order with an additional overhead for threading, but on a
multiprocessor machine, this should put any unused CPU to immediate use.
This seems to be exactly what Haskell is doing anyway, so I'm not sure
what the problem actually is. Surely people don't expect their code to
go magically faster on a uniprocessor machine by making it
multithreaded, do they?
Or am I missing something?
Regards,
Jo
| |
| André Thieme 2007-07-28, 7:06 pm |
| Jon Harrop schrieb:
> However, functional programming doesn't require you to sacrifice run-time
> performance (much) as, I think, OCaml and Stalin-compiled Scheme have
> shown.
In the long run it is only about productivity.
With compilers that nearly match human intelligence all programs would
result in the end in the same, highly optimized machine language output.
Those compilers are not available now, but I think many of us will see
them within their livetime.
Until then Lisp is for most things the best bet. It performs fast enough,
for most tasks close to C or faster (simply because it would be too
complicated to write a complex program in C).
It is not fixed into a specific paradigm, like functional programming
or logic programming. It is the only truly multiparadigm programming
language and one can create domain specific languages easier than any
other language. This means of course unbeatable productivity, as no
general purpose language could compete with a domain specific one.
André
--
| |
| André Thieme 2007-07-28, 7:06 pm |
| Dan Bensen schrieb:
> Markus, do you consider it "true and useful" to say that pattern-
> matching libraries are "Greenspunning"? Do you think ML languages
> are "much more concise" than Lisp? I don't think those statements
> are either true or useful. I don't think libraries and simple macros
> are Greenspunning, and I don't think the ML family is "much" more
> concise than Lisp when you take macros into account.
Dan, can you tell me in what language the first ML was programmed in?
And in what language the first OCaml was programmed in?
And in what language the first Haskell was programmed in?
And in what language the first Pattern Matchers were used?
André
--
| |
| André Thieme 2007-07-28, 7:06 pm |
| Joachim Durchholz schrieb:
> Now you're exaggerating.
> I actually had to look at Jon's last post to even notice that he had a
> URL to his book in the sig.
Right, I also think that this is very visible.
One Lisper who published his book in April 2005 made also lot's of
postings, of which some were very explicit, and he wasn't considered
a spammer. His book actually is very good (it is a Lisp book).
> Oh, and there's another big difference. Most discussions about relative
> advantages and di vantages evolve into matter-of-belief statements.
> Jon is far more down to facts than that: He's giving benchmarks, making
> himself open to critique; he's adapting the benchmarks in response to
> the critique; he's counting lines, characters, or tokens and arguing his
> choice of criteria rationally.
I don't see Jon as a spammer or troll.
But on this point you are not completely correct.
He himself is caught at least sometimes in these believes.
I explained to him like eleven times (also in private mails) that this
counting lets Lisp in many cases of trivial programs appear in a bad
light, and that some other mechanism could make more sense.
For example counting "tokens" or however we want to call it.
If we do that then suddenly Lisp code is not much longer than an OCaml
or Haskell equivalent, but suddenly in the same league.
For me the most important quote that was ever made about Lisp:
"Lisp isn't a language, it's a building material."
(Dr. Alan Kay)
Lisp is a more general programming language in some sense than most of
the others that exist. It is more a building material out of which you
construct very nice solutions to problems. It only does not always work
out for simple code. When I do simple code and introduce a macro its
definition lengthens the code file. That it would be used 48 times in
a "real project" was pointed out to Jon. Each use of it reduces the
token count and therewith code complexity, for example in opposit to
his code. But well, altough I explained it (and others explained
different things as too) he continues to not implement these new facts
into his arguments.
About speed:
OCaml was specifically designed to make very runtime efficient programs.
That came at some costs, check: http://www.podval.org/~sds/ocaml-sucks.html
Anyway, Lisp can in fact compete with OCaml, although Jon does not
admit it. His idea that OCaml usually runs 2-10 times faster is not
always so true as he believes. In an email I said:
when I look at
http://www.ffconsultancy.com/free/r...f_all_amd64.gif
I see...
....for white color:
ocamlopt is ca at 0.86 speedwise
the fastest sbcl at 0.61 speedwise
So the Lisp code runs 29,06% slower.
....for red color:
ocamlopt is at 0.6
sbcl is at 0.43
Here too Lisp runs with 43/0,6 = 71,6% of OCamls speed, making it
therewith 28,3% slower.
On 64-Bit system a Lisp (language family) system, Stalin, outperformed
his OCaml code.
And yes: these Lisp programs have a higher LOC. This however is not
very meaningful. In bigger programs, where some techniques are reused
the macros (that brought speed optimizations) would also reduce the
code complexity. OCaml is simply too optimized to beat it in its domain.
Short programs will in most cases be faster in OCaml (compared to Lisp
or Haskell). If Lisp wants to compete it needs some extra techniques.
If the program itself is short code reuse can't begin to help, so the
line count gets worse. Altough not always the token count has to be
worse.
Others pointed out that his benchmark mostly measured the Garbage
Collectors. The one in OCaml is better designed as the one of the
Lisps implementation that went into the comparison, at least for this
task.
But pointing out things does not always work, as Jon ly continues
to state things although he was corrected.
This does not make him a troll. But he surely is doing sometimes, what
you criticized: living in a world of matter-of-belief statements.
> I don't know what "Greenspunning" is, but those pattern-matching
> libraries that I have seen weren't very well-designed;
Which were the ones you have seen?
> I have seen some of the things that can be made concise in Haskell, and
> it was outright amazing.
I totally agree. When Haskell is working in its domain it is more or
less impossible for other languages to compete.
> My ability to assess the usefulness of macros is slightly limited.
Increase your knowlegde about Macros.
Read the first 9 chapters of this book:
http://www.gigamonkeys.com/book/
And your understanding will improve. You can do it in two days.
> However, I'm having trouble with limiting what a macro can do. In
> principle, a macro can cause its parameters to be evaluated once, not at
> all, or an arbitrary number of times; it could do the evaluation at
> expansion time or at evaluation time.
A macro is more or less a compiler. It is doing source code transformation.
It is a function: it takes Lisp code and produces Lisp code.
The resulting code gets compiled. When a Lisp program is running there
are no macros anymore.. in some sense, because a Lisp program is always
running.
> If Lisp were pure, it wouldn't matter when exactly what is evaluated,
> but then Lisp wouldn't need macros anyway :-)
I don't think this is true.
But: Lisp does not need macros to be turing complete.
It needs them to be able to do all what Haskell can do and additionally
create a well integrated syntax for domain specific languages.
Also it can do speed optimizations.
> Oh, and with standard macros from the standard libraries, these problems
> usually don't happen - I'd assume that every macro has a clear
> description when it evaluates what parameter, or it's easy to look that
> up. The problems start to arise when people write their own macros. (And
> with standard macros where you just *think* you had understood its
> behavior, and overlooked some special case which comes back to bite you,
> possibly years after you learned to use that macro. Or when different
> vendors use slightly different interpretations of the standard and the
> code starts to break.)
>
> Just an outsider's view, possibly totally irrelevant and off the mark.
Well, you are coming closer. But macros are still not completely
dis-mystified for you. So your views on them might not always be how they
really work.
André
--
| |
| Cesar Rabak 2007-07-28, 7:06 pm |
| Pascal Costanza escreveu:
> Joachim Durchholz wrote:
>
> I am not surprised at all. Apparently, the main target audience
> effectively were Lispers, and Lispers who have considerably experience
> with s-expressions typically prefer them over more mainstream syntaxes.
>
>
Pascal,
I think you got the point that's being treated as fuzzy: people that
learnt Lisp enough don't see the s-exps (or they physical consequence,
the parentesis) as a problem at all.
Attempts to 'fix' this 'issue' bring too many disavantages to the new
dialect that only in a very few cases it survives (as niche language,
perhaps).
my .0199999...
--
Cesar Rabak
| |
| André Thieme 2007-07-28, 7:06 pm |
| Jon Harrop schrieb:
> André Thieme wrote:
>
> You may also be interested in what people are using these days...
Well... Java, C, C++, C#, Visual Basic and PHP.
I think this is a point where most of us sit in one boat.
Probably a good number of readers of cll and clf prefer to not
code in these langs, if the don't have to.
André
--
| |
| Cesar Rabak 2007-07-28, 7:06 pm |
| Jon Harrop escreveu:
> Joachim Durchholz wrote:
>
> Indeed, and this is precisely what concerns me. The Lisp community have
> evolved a variety of stock responses designed to make Lisp look good that
> are flawed in subtle ways. It takes quite some effort to figure out why
Jon, you seem to be building quite quickly an assorted bag of stock
responses as well. . .
> they are wrong and I think it is a real shame that so many people new to
> functional programming end up wasting their time with Lisp when they could
> be so much more productive using one of the modern FPLs.
and this is the point others are trying to explain you: discussing the
advantages of a designed for FPL for _functional_ _programming_ in
c.l.l is not a point, given Lisp is a general purpose language.
>
> This is exactly the same situation that scientific creationists have wiggled
> into, particularly in the US. They say "evolution is a myth" and cite an
> enormous number of pseudo-scientific reasons trying to undermine the theory
> of evolution. That is actually a more interesting debate because the
> responses of the scientific creationists has actually evolved over time.
> Anyway, I digress.
No. This is worse than a digression, this another fallacy called
"ignoratio elenchi".
>
> First, you'll notice that Lispers only ever compare Lisp to Java. Comparing
> to OCaml, Haskell or even C# is strictly prohibited on c.l.l. My ray tracer
> elucidates why:
>
> http://www.ffconsultancy.com/langua...er/results.html
>
Again, another fallacy: Lisp is more than a language to implement a Ray
Tracer.
> Java is the only mainstream language that is as slow and verbose as Lisp.
Again a loaded argument. Java and Lisp are touted as general purpose
languages.
>
> When arguing with C programmers they used to quote Greenspun's Tenth Rule:
>
> "Any sufficiently complicated C program contains an ad-hoc, ill-
> specified, slow, bug-ridden reimplementation of half of Common Lisp."
>
> particularly with regard to the reimplementation of the list data structure
> in C programs. Yet they disregard pattern matching (a core feature of all
> modern FPLs) as something that they can trivially lash together (ad-hoc)
> without saying exactly what it will do (ill-specified), disregarding the
> overwhelming quantitative evidence of bad performance (slow) or having
> studied the static verification of patterns (bug-ridden) or even caring
> that it is not usefully encompassing (only half of ML).
Another very fallacious paragraph, filled with a lot of emotional
content and very little essence. . .
Let's for a moment just see this affirmation: "pattern matching (a core
feature of allmodern FPLs)"
Do you understand that production programms, instead of your toy
benchmark problems posed for the amusement of lispers, do not expend
100% of their time _just_ doing pattern matching, and so Lisp has an
approach where its performance is acceptable?
Do you understand that in the case a system would require a even better
performance (be it on parttern matching or whatever) Lisp has a FFI to
cope with that?
| |
| Joachim Durchholz 2007-07-28, 7:06 pm |
| Jon Harrop schrieb:
> Markus E.L. wrote:
>
> Surely it is much easier to remove a static type system than to add one.
But you'll get a worse language than when you had started with a
dynamically typed language. Static typing, like any other feature,
limits design trade-offs, and you won't lose the bad sides of these
trade-offs just by dropping the type system.
You'd also have to rewrite portions of the standard libraries to deal
with the new situation.
It's very similar when going from dynamic to static typing.
I think as soon as you start to study such a transformation in detail,
the difference in easiness quickly dwarves compared to the size of all
the things that should be done!
Regards,
Jo
| |
| Joachim Durchholz 2007-07-28, 7:06 pm |
| NNTP-Posting-Host: p57b618d7.dip0.t-ipconnect.de
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Trace: online.de 1185662968 17856 87.182.24.215 (28 Jul 2007 22:49:28 GMT)
X-Complaints-To: abuse@einsundeins.com
NNTP-Posting-Date: Sat, 28 Jul 2007 22:49:28 +0000 (UTC)
User-Agent: Thunderbird 1.5.0.12 (Windows/20070509)
In-Reply-To: <f8gdus$175$1@aioe.org>
Bytes: 2731
Xref: number1.nntp.dca.giganews.com comp.lang.lisp:234161 comp.lang.functional:62541
Cesar Rabak schrieb:
> Let's for a moment just see this affirmation: "pattern matching (a core
> feature of allmodern FPLs)"
>
> Do you understand that production programms, instead of your toy
> benchmark problems posed for the amusement of lispers, do not expend
> 100% of their time _just_ doing pattern matching, and so Lisp has an
> approach where its performance is acceptable?
Pattern matching isn't just a tool for efficiency.
It's also a tool for quickly and safely deconstructing tagged unions of
structures, something that's quite common in any language (including
Lisp, C, and anything else that I have seen). I think it's roughly at
the same abstraction and usefulness level as arrays - not a silver
bullet, not quite an abstract data type, but still a very useful and
trusty tool that every craftsman should have in his toolset.
I'd say that the second use far outweighs the first use. In Lisp, it
would be something of a design pattern, supported by some library code,
possibly with the help of some compiler or macro magic to get things
really fast - but that's secondary, pattern matching is really more
about programming style.
Regards,
Jo
| |
| Joachim Durchholz 2007-07-28, 7:06 pm |
| André Thieme schrieb:
> Joachim Durchholz schrieb:
>
> I don't see Jon as a spammer or troll.
> But on this point you are not completely correct.
> He himself is caught at least sometimes in these believes.
Possibly.
Nobody is perfect.
I actually found him guilty of launching quite nasty ad hominem attacks
today. "Spammer" is still wrong (that's plain ridiculous), but there's a
strong streak of trolldom in his dealing in c.l.l. It's probably more a
temper grown out of hand rather than trolldom, so he's not a troll by
intention, but his behaviour seems troll-like enough to make people foam
at the mouth.
Well, enough analysis.
> Lisp is a more general programming language in some sense than most of
> the others that exist. It is more a building material out of which you
> construct very nice solutions to problems. It only does not always work
> out for simple code. When I do simple code and introduce a macro its
> definition lengthens the code file. That it would be used 48 times in
> a "real project" was pointed out to Jon. Each use of it reduces the
> token count and therewith code complexity, for example in opposit to
> his code. But well, altough I explained it (and others explained
> different things as too) he continues to not implement these new facts
> into his arguments.
The problem with macros is that they do not do information hiding.
That's why I said that Lisp is more a programming language laboratory
rather than a language suited for production programming. (That doesn't
make it entirely unsuitable for the task, of course, and you can whip up
pretty amazing things with it anyway. I know that this statement is too
strong to stand up.)
> On 64-Bit system a Lisp (language family) system, Stalin, outperformed
> his OCaml code.
Stuff like Stalin works only if you drop major parts of what makes Lisp
strong, of course. I don't think you can do much run-time loading in a
Stalin-compiled Lisp program, can you? (Even if you could, the linkage
would not have the optimization of Stalin.)
I.e. the problem with Lisp (as with most dynamica | | |