[eeps] EEP XXX: Pattern-test operator
Richard O'Keefe
ok@REDACTED
Wed Apr 18 09:08:44 CEST 2012
On 17/04/2012, at 9:23 AM, Michael Truog wrote:
>> When you consider a side-effect as defined with the simplest possible explanation ("a side-effect is where state in context A impacts state in context B"), it should be easy to see that a variable created within a guard that is then used within a function body is a side-effect.
A side effect has to involve a CHANGE in state.
But we are not talking about changing any state, simply letting a
variable BINDING occur in the guard half of a pattern/guard as
as well as the pattern part. If you are frightened of this kind
of "side effect", you should be terrified of "side effects"
caused by variable bindings in function heads, because it is
*exactly* the same thing.
For example, in a Prolog system,
append([H|T], L, [H|R]) :- append(T, L, R).
and
append(A, B, AB) :- A = [H|T], AB = [H|R], append(T, L, R).
could well result in *IDENTICAL* object code. In the same way,
I would expect that a mature compiler for Erlang, extended with
pattern matches in guards, would compile
append([H|T], L) -> [H | append(T, L)]
and
append(A, L) when A ?= [H|T] -> [H | append(T, L)]
to result in *identical* object code. The one kind of binding
is in no way any more a side effect than the other.
>> > I never heard of any negative consequences of _that_.
>> My concern is that you never heard of negative consequences because no one cared.
Wrong. People cared *passionately* about variable bindings in the logic
programming languages; they were the main method of synchronisation between
processes.
>> You are arguing with examples from Haskell and Parlog which both found no wide-spread use outside of academia.
"Wide spread", maybe not, but Haskell has failed to avoid success. There's a growing
use of Haskell. Pattern guards are available as an optional extension for O'CAML, which
has seen an astonishing amount of industrial use for such an ugly language. And F#,
a descendant of O'CAML that sits on top of .Net, both has rapidly growing industrial
adoption and something called 'active patterns' that is not entirely unlike abstract
patterns.
There's a company (Eaton) building engine control software for trucks using Haskell;
they have a nice picture of "real Haskell garbage collection" -- it's a great big
rubbish collection truck.
I find it rather puzzling that anyone would (a) panic over non-existent side effects
and (b) diss other languages on the grounds of not being in wide-spread use, when
wide-spread languages like Java are practically nothing *but* side effects.
> I understand that the research community would care about the abstract implications of the feature. My concern is instead about sacrificing efficiency for no reason.
There is absolutely NO sacrifice of efficiency at issue here.
NONE.
This "problem" is entirely imaginary having no warrant in fact.
Code that does not use the new feature (whether as described in EEP 14 or as described
in Erik Søe Sørensen's proposal would not change in any way, until the point where the
compiler processes pattern and guard as a single construct, at which point the code
*ought* to get *better*.
> Haskell and Parlog development is not forced to consider performance implications as a research language.
The idea that Haskell implementors and users don't care about performance is
farcical. See for example
http://blog.johantibell.com/2010/07/high-performance-haskell-tutorial-at.html
> I understand that the financial sector often uses functional languages. However, with production code, I have only been aware of things like MUMPS or ML. When Haskell is used at a company, it seems to always just be one, or at most two Phds that are most familiar with Haskell, so they would rather stick with that language than risk the implementation in a language they haven't used as often. However, the Haskell code never seems to find its way into production, unless it is a batch algorithm for analysis which they personally run.
Galois? Bluespec? In any case, this really is not relevant to the question
"what, if anything, is bad about allowing bindings in the guard half of
pattern/guard constructs?"
>> I agree that both can be written with the changes mentioned in the proposal to add variable bindings to guards. That is part of the reason it appears to be an unnecessary addition that is just meant to complicate Erlang code and the Erlang VM.
Whether as EEP 14, abstract patterns, 'assignment attempt', or whatever,
the aim is to *simplify* the *writing* of Erlang code. The impact on the
Erlang VM should be somewhere between "none" and "very very little".
Clause selection involves two activities:
- DISCRIMINATION : what have I been given?
- EXTRACTION : what parts of that do I need to refer to?
Discrimination can be based on
- SHAPE : what are the constructors / constants *exactly*
- RANGE : is this literal some possibly large range?
- TYPE : is this term of a particular kind.
In some programming languages, all of these aspects are interwoven into
a single syntax. Using ad hoc syntax, we might write
{A, B, C} -- a tuple with 3 arguments
_&range(1,10) -- an integer 1..10
_&is_tuple() -- any tuple
Interlisp certainly did this, and I believe IBM PROLOG FOR VM did it too.
There've been several proposals for it in other Prologs, and the main
argument against was "we don't need it because head matching can ALWAYS
be moved into the body", which isn't true in Erlang. Erlang separates
shape (pattern) from range and type (guard), and for that to happen, you
have to name things in the pattern that would otherwise go anonymous,
e.g.,
X .... when is_integer(X), X >= 1, X =< 10
X ... when is_tuple(X)
What you can't do is introduce a binding in a guard to be used later in
the guard. And this is an entirely arbitrary restriction. None of the
arguments for distinguishing guards from expressions (which distinction
I am very fond of) appplies to _this_ restriction.
We can even move pattern tests into a guard: *everything* about a pattern
*except* 'extraction' can be done in a guard. So why the "except"?
Is it necessary to point out that allowing pattern matching in a guard
can make a guard at least quadratically shorter and faster?
>> My argument is that if patterns already provide us variable bindings, why weaken Erlang guards to also bind variables.
That's not *weakening* them; it's *strengthening* them.
>> I would rather have a stronger guarantee that state from a guard will not affect the context it controls.
WHAT state? All that changes is that variable bindings in a pattern/guard construct
will be able to come from the guard half as well as the pattern half, and they will
pose *NO* risks for 'the context they control' that variables bound in a pattern don't.
> I respect the Haskell language. However, I also respect the Erlang language. I don't see a requirement that the two languages share features, and pursuing Haskell features in Erlang blindly seems like a mistake.
This is a straw man argument. The feature in question is one from Prolog, Parlog, GHC, FCP, Strand,
Mercury, Haskell, O'CAML, F#, and almost _every_ "declarative" language with pattern matching around.
The argument is not "they have it, so we should".
It is "we want this; they have had it for a long time, so we know from their
experience that it's implementable and safe".
Erik and I want this feature *in* Erlang *for* Erlang and would do so even if
no other programming language existed.
More information about the eeps
mailing list