[Haskell-cafe] Re: FW: Haskell
cdsmith at twu.net
Tue Apr 1 11:37:57 EDT 2008
Just random thoughts here.
Andrew Bagdanov wrote:
> Well, if I don't have side effects (and don't mind extra, unneeded
> evaluations), I can write my conditionals as functions in Scheme too.
> Heck, now that I think of it I can even avoid those extra evaluations
> and side-effect woes if i require promises for each branch of the
> conditional. No macros required...
This is essentially doing lazy evaluation in Scheme. It's certainly
possible; just clumsy. You must explicitly say where to force
evaluation; but if you think about it, the run-time system already knows
when it needs a value. This is very analogous to having type inference
instead of explicitly declaring a bunch of types as in Java or C++.
> Again, I think this is highly problem
> dependent, though I think you win more with lazy evaluation in the long
> run. Do more experienced Haskellers than me have the opposite
> experience? I mean, do you ever find yourself forcing strict evaluation
> so frequently that you just wish you could switch on strict evaluation
> as a default for a while?
The first thing I'd say is that Haskell, as a purely functional language
that's close enough to the pure lambda calculus, has unique normal
forms. Furthermore, normal order (and therefore lazy) evaluation is
guaranteed to be an effective evaluation order for reaching those normal
forms. Therefore, forcing strictness can never be needed to get a
correct answer from a program. (Applicative order evaluation does not
have this property.)
Therefore, strictness is merely an optimization. In some cases, it can
improve execution time (by a constant factor) and memory usage (by a
lot). In other cases, it can hurt performance by doing calculations that
are not needed. In still more cases, it is an incorrect optimization and
can actually break the code by causing certain expressions that should
have an actual value to become undefined (evaluate to bottom). I've
certainly seen all three cases.
There are certainly situations where Haskell uses a lot of strictness
annotations. For example, see most of the shootout entries. In
practice, though, code isn't written like that. I have rarely used any
strictness annotations at all. Compiling with optimization in GHC is
usually good enough. The occasional bang pattern (often when you intend
to run something in the interpreter) works well enough.
(As an aside, this situation is quite consistent with the general
worldview of the Haskell language and community. Given that strictness
is merely an optimization of laziness, the language itself naturally opts
for the elegant answer, which is lazy evaluation; and then Simon and
friends work a hundred times as hard to make up for it in GHC!)
> I think this is possibly the weakest reason to choose Haskell over
> Scheme. Lispers like the regularity of the syntax of S-expressions, the
> fact that there is just one syntactic form to learn, understand, teach,
> and use.
I am strongly convinced, by the collective experience of a number of
fields of human endeavor, that noisy syntax gets in the way of
understanding. Many people would also say that mathematical notation is
a bit impenetrable -- capital sigmas in particular seem to scare people
-- but I honestly think we'd be a good ways back in the advancement of
mathematical thought if we didn't have such a brief and non-obstructive
syntax for these things. Mathematicians are quite irregular. Sometimes
they denote that y depends on x by writing y(x); sometimes by writing y_x
(a subscript); and sometimes by writing y and suppressing x entirely in
the notation. These are not arbitrary choices; they are part of how
human beings communicate with each other, by emphasizing some things, and
suppressing others. If one is to truly believe that computer programs
are for human consumption, then striving for regularity in syntax doesn't
Initially, syntax appears to be on a completely different level from all
the deep "semantic" differences; but they are in reality deeply
interconnected. The earlier comment I made about it being clumsy to do
lazy programming in Scheme was precisely that the syntax is too noisy.
Other places where lazy evaluation helps, in particular compositionality,
could all be simulated in Scheme, but you'd have to introduce excessive
syntax. The result of type inference is also a quieter expression of
code. So if concise syntax is not desirable, then one may as well throw
out laziness and type inference as well. Also, sections and currying.
Also, do notation. And so on.
> In short, I think the orginal question must be asked in context. For
> some problems, types are just a natural way to start thinking about
> them. For others dynamic typing, with _judicious_ use of macros to
> model key aspects, is the most natural approach.
I wouldn't completely rule out, though, the impact of the person solving
the problem on whether type-based problem solving is a natural and useful
way to solve problems. Indeed, I would guess this probably ends up being
a greater factor, in the end, than the problem. Unfortunately, we (as a
general programming community) have caged ourselves into a box with the
mantra "use the right tool for the job" such that we find it far too easy
to dismiss something as the wrong tool merely because it is unfamiliar.
My not being able to use a tool well may be a good reason for me, but
it's a lousy reason for me to advise someone else.
More information about the Haskell-Cafe