| Dirk Thierbach 2005-11-07, 10:03 pm |
| Andre <andre@het.brown.edu> wrote:
> Dirk Thierbach wrote:
[color=darkred]
[color=darkred]
> I just meant that there are many ways of implementing a do-until
> construct,
If you keep it purely functional, then I don't think so. I'd say
there's is really just one canonical way to do an until-loop. The
only thing that changes is presentation and syntax.
> many of which do not require the thunks needed by the one HOF
> example (which imply the use of side effects, as you observe),
Maybe there's a misunderstanding here. It's the *idea* of an
until-loop which implies the use of side effects. HOFs and
side-effects are orthogonal concepts, they don't imply each other.
(The trick one has to use in a strict language like Lisp to defer
evaluation doesn't really count as "HOF" in my book. In a lazy
language, the situation is different in the first place.)
> or the monadic types used in the other HOF example.
I chose the Haskell example with monads because if you want
side-effects, then in Haskell you have no other choice but to use
monads. So, in Haskell, there is *no* other way, even with macros,
to implement an until-loop with side effects, but to use monads.
So the question to use monads or not depends in the first place on how
your language handles side effects, and not if you want to use macros
or HOFs.
Which is why I said that this is maybe not a particularly good example
to discuss the whole issue.
> A macro can be used to hide this detail, and can be justified by the
> same arguments used for any other kind of abstraction.
In Lisp, yes. In many other functional languages, no.
And in the end, as other people have observed, I'd argue it is actually
*better* to use one universal way to parametrize abstractions.
One thing that I really hate about many macros I have seen is the
unsystematical, ad-hoc way in which they treat they arguments. This
may all be very nice for a quick hack, but in the long run, I have
to remember all of those tricks and exceptions, I have to figure them
out in other people's code, and so on. If there is just one simple,
generally accepted way to do this, the burden on my poor brain is much
less :-) And I gladly pay a few nanoseconds execution time penalty
for all the time it costs me to look up the details again when
programming, or the mistakes I make by misunderstand them.
Additionally, being able to cleanly type the HOF makes debugging it
so much easier.
> These include:
> - Modularity: being able to change the implementation
> from e.g., thunks to monads without having to change all the use sites.
As I said, that's something you just cannot do. It's a very
fundamental decision whether you handle side-effects implicitely by
pretending that one understands the order of evaluation (which can be
wrong sometimes even in strict languages; I have been surprised by
that once), or whether you have to make that order explicit by using
monads. If you want to change one way to the other, you have to make
that change everywhere, regardless whether you use macros, or not.
(If it's not obvious to you why monads imply an ordering on
side effects, someone in this NG has written a nice introduction of
monads for Lispers some time ago. Google should be able to find it.)
> - Optimization: The macro might construct thunks behind the
> scenes, but does not have to. A syntax that is agnostic with
> respect to this detail is arguably better than a HOF that isn't,
> for a looping construct where performance might be important.
Yes, one of the things that macros give you is *control* over
run-time vs. compile-time evaluation. Sometimes that is important.
But that doesn't expose internal implementation. Additionally, it
doesn't affect the original argument, because it's "only" an
optimazation issue. And it's not so bad if you have a compiler
(like GHC) which automatically does compile-time evaluation. (In this
case, it would very probably inline the calls, anyway, so the result
is not different from using macros).
The initial argument did say something like "Macros are the best
things since sliced bread, they make a language sooo powerful, no
language without them is as good" (again, I am exaggerating :-)
And that's just not true (in the exaggerated form). Macros are
sometimes nice to have, but you can go a long way without them. And
while there's a number of reasons why it's more conveninient to use
macros in Lisp, I have the impression that this tends to make
people a bit unnecessarily "preachy" about them, while at the same
side blinding them to alternatives. But maybe that's just my
impression :-)
- Dirk
|