|
Hi,
After we've discussed the topic (mainly in the "erlang *****" thread), I've made the eep-document. I send it to the list for further discussion. I haven't received any comments on the proposed pattern-match-test construct, which is sad as I am not satisfied with what I'm about to recommend. There are 3 possibilities: 1, Only _ (underbar) names are allowed. + sounds logical, because no variables will be bound anyways. - Patterns with syntactic restrictions is a new concept in Erlang 2, Only _ and names beginning with _ are allowed. + giving meaningful names instead of _-s is a documentation of the code + multiple occurences of the same variable in a pattern are meaningful and useful - Later use of a variables that occured in a pattern-match-test is confusing, because they are totally independent - Patterns with syntactic restrictions is a new concept in Erlang 3, No restrictions. - Variables not beginning with _ are bad, because * not using it later results in compiler warning * using it later is confusing (see above) I don't really like any of the above, but I still think that a pattern-match-test operator is very useful, so I'm eager to listen to every constructive opinion. Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
I feel that this proposal is a step in the wrong direction,
and has "hack" written all over it. Let's start with the pattern-match operator, pattern ~= expression I already feel slightly queasy at the fact that pattern matching is associated with guards everywhere EXCEPT pattern = expression; adding another construction that will work some but only some of the time does not appeal to me. Right now, I can do 1 = f() but I cannot do (X when X > 1) = f() Right now, any instance of case E1 of P1 -> B1 end % just one clause! can be rewritten as (P1 = E1, B1). Why not extend this to allow case E1 of P1 when G1 -> B1 end to be written as ((P1 when G1) = E1, B1) I'm not pushing _hard_ for this, you understand, just noting that there is a nasty and apparently unmotivated gap in the language, and suggesting that something should be done about it. Abstract patterns are, of course, a far better solution to the same issue. Of course the same idea can be extended to ~=, and if ~= were to be extended, it should be. The draft EEP notes that the ~= construction adds no real power (and, if we consider macros, no extra power at all) in ordinary expressions. It is ONLY useful in guards. But WHY is it useful? ~= is only useful because = is not allowed in guards. Between a pattern match test that doesn't bind any variables and a pattern match test that only binds variables that happen not to be used anywhere else there is no real difference. ~= is a special case of = . So if we are willing to consider ~= in guards, why not consider = in guards? Indeed, why not? If I can write f(L) when hd(L) > 0, hd(L) < 10 -> why can't I write f(L) when N = hd(L), N > 0, N < 10 -> In the past I have strongly defended the distinction between guards and expressions, and I have not changed my mind. But allowing = in guards does not destroy any of the properties of guards that have ever concerned me. So instead of adding a new "crippled-bind" called ~=, I suggest that it would be better to allow Pattern = Expression as a guard. What about the intended uses of ~= where the fact that it does not bind variables is important? Why then, just restrict the corresponding = to not bind variables. {foo,_,27} = hd(X) would have the same effect in a guard as {foo,_,27} ~= hd(X) would have, so if we allowed =, there would be no point in having ~= as well, while if we had ~= we would still be left lamenting the inexplicable prohibition on =. Do I need to mention that the similarity between = and ~= would lead to errors when one was used but the other intended? No, I thought not. ~= is something we are better off without. But its use in guards _is_ something we could do with, only the existing = would be far better. That's enough for one message, I think. Maybe not. I don't like vague suggestions that "It is rather common to check the value of an expression with a case expression and do the same actions in some of the cases." I want to see *actual cases*. Oh, and did I point out that abstract patterns can solve the "multiple patterns" problem neatly and clearly? _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
+1
On Thu, May 15, 2008 at 3:27 AM, Richard A. O'Keefe <[hidden email]> wrote: I feel that this proposal is a step in the wrong direction, -- --Hynek (Pichi) Vychodil _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Richard O'Keefe
On Thu, May 15, 2008 at 01:27:55PM +1200, Richard A. O'Keefe wrote:
> I feel that this proposal is a step in the wrong direction, > and has "hack" written all over it. > : > > So instead of adding a new "crippled-bind" called ~=, > I suggest that it would be better to allow > Pattern = Expression as a guard. > > What about the intended uses of ~= where the fact that > it does not bind variables is important? Why then, > just restrict the corresponding = to not bind variables. > {foo,_,27} = hd(X) would have the same effect in a guard > as {foo,_,27} ~= hd(X) would have, so if we allowed =, > there would be no point in having ~= as well, while if > we had ~= we would still be left lamenting the > inexplicable prohibition on =. > > Do I need to mention that the similarity between = and > ~= would lead to errors when one was used but the other > intended? No, I thought not. ~= is something we are > better off without. But its use in guards _is_ something > we could do with, only the existing = would be far better. > > That's enough for one message, I think. > So far I agree. > Maybe not. > > I don't like vague suggestions that > "It is rather common to check the value of an expression with a > case expression and do the same actions in some of the cases." > I want to see *actual cases*. But on this one I have experienced so many *actual cases* myself to accept it as an inconveniance. A solution to the multiple patterns to one branch problem would be convenient, indeed. > > Oh, and did I point out that abstract patterns can solve the > "multiple patterns" problem neatly and clearly? > > _______________________________________________ > erlang-questions mailing list > [hidden email] > http://www.erlang.org/mailman/listinfo/erlang-questions -- / Raimo Niskanen, Erlang/OTP, Ericsson AB _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Richard O'Keefe
Hi,
> I feel that this proposal is a step in the wrong direction, > and has "hack" written all over it. I agree with some of what you've written, but you completely missed one very important detail. > Let's start with the pattern-match operator, It seems to me you also finished with the pattern-match operator. The other part of the eep (multiple patterns) is OK? > 1 = f() > but I cannot do > (X when X > 1) = f() I completely agree. Whe should be able to do the latter, however, I don't consider it important. > ~= is only useful because = is not allowed in guards. > > So instead of adding a new "crippled-bind" called ~=, > I suggest that it would be better to allow > Pattern = Expression as a guard. You can't negate it! I've also written, I think the most important use of the ~= operator was to express negated patterns, i.e. the ability to write a guard that fails if (some part of) the matched value matches a pattern. It seems you completely missed this point. > What about the intended uses of ~= where the fact that > it does not bind variables is important? If it doesn't match, it naturally can't bind variables. That's it. Please propose a different construct that expresses negated patterns, and is easy to implement, understand and use. I told you I am dissatisfied with what I'm about to propose, I just can't find a better solution. > I don't like vague suggestions that > "It is rather common to check the value of an expression with a > case expression and do the same actions in some of the cases." > I want to see *actual cases*. I think I am not allowed to copy-paste code pieces from AXD301 here. Beleive me, I could. Do you want me to obfuscate and send a few? > Oh, and did I point out that abstract patterns can solve the > "multiple patterns" problem neatly and clearly? I accept your abstract patterns as useful and nice, but is quite a big change in the language. My proposal is a small change. Easy to learn, easy to implement, easy to document, no compatibility issues. Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Raimo Niskanen-2
Raimo Niskanen wrote:
> On Thu, May 15, 2008 at 01:27:55PM +1200, Richard A. O'Keefe wrote: > >> I don't like vague suggestions that >> "It is rather common to check the value of an expression with a >> case expression and do the same actions in some of the cases." >> I want to see *actual cases*. >> > > But on this one I have experienced so many *actual cases* > myself to accept it as an inconveniance. A solution > to the multiple patterns to one branch problem would > be convenient, indeed. > i don't know where ro'k gets his code examples from, but i for one have seen tons and tons of code where many patterns winds up in the same branch. i find virding's suggestion [1] much nicer though; foo(Pat11, ...) when Guard1 ; foo(Pat12, ...) when Guard2 ; foo(Pat13, ...) when Guard3 -> ...; case ... of Pat1 when Guard1 ; Pat2 when Guard2 -> ...; ... end as for the "~=" operator; i guess i don't see the point. mats [1] http://www.erlang.org/pipermail/erlang-questions/2008-March/033784.html) _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
> i find virding's suggestion [1] much nicer though;
Well, what I suggest differs only in a ; <=> | change.
> > foo(Pat11, ...) when Guard1 ; > foo(Pat12, ...) when Guard2 ; > foo(Pat13, ...) when Guard3 -> > ...; > > case ... of > Pat1 when Guard1 ; > Pat2 when Guard2 -> ...; > ... > end I think ; is more confusing, because it already has a use. > as for the "~=" operator; i guess i don't see the point. Few examples: ================================================== Negated patterns: --------------------------- case Expression of {X,Pattern} when not (X~=Pattern2) -> action1(X,Variables_in_Pattern); _ -> action2() %think lots of code here end --------------------------- The same Without ~= : --------------------------- case Expression of {Pattern2,Pattern} -> action2(); %think lots of duplicated code here {X,Pattern} -> action1(X,Variables_in_Pattern); _ -> action2() %think lots of duplicated code here end ================================================== Conditional exception throwing: --------------------------- (Pattern ~= Expression) andalso throw(Exception) --------------------------- OR: --------------------------- not (Pattern ~= Expression) andalso throw(Exception) --------------------------- ================================================== Pattern-testing in short-circuit logic expressions: --------------------------- case (Pattern1~=f1()) andalso (Pattern2~=f2()) of true -> action1(); false -> action2() end --------------------------- Without ~= : --------------------------- case f1() of Pattern1 -> case f2() of Pattern2 -> action1(); _ -> action2() end; _ -> action2() end --------------------------- Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Raimo Niskanen-2
On 15 May 2008, at 9:00 pm, Raimo Niskanen wrote:
>> I don't like vague suggestions that >> "It is rather common to check the value of an expression with a >> case expression and do the same actions in some of the cases." >> I want to see *actual cases*. > > But on this one I have experienced so many *actual cases* > myself to accept it as an inconveniance. A solution > to the multiple patterns to one branch problem would > be convenient, indeed. I may have expressed myself badly. You may have noticed that my message criticised the ~= part, but did not criticise the idea or even the method of allowing multiple patterns. I did not say that no actual cases EXIST, only that I would like to SEE them. Actual cases can be enormously helpful, not only in evaluating the utility of a proposal, but in suggesting alternatives. For example, had there been some real cases shown, I could have responded by showing how abstract patterns handle them, and we could then have debated whether *anonymous* multiple patterns are a good idea. >> >> Oh, and did I point out that abstract patterns can solve the >> "multiple patterns" problem neatly and clearly? THIS Richard DOES want to discuss evidence! -- "I don't want to discuss evidence." -- Richard Dawkins, in an interview with Rupert Sheldrake. (Fortean times 232, p55.) _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Bugzilla from bekesa@sch.bme.hu
On 15 May 2008, at 11:07 pm, Andras Georgy Bekes wrote:
>> Let's start with the pattern-match operator, > It seems to me you also finished with the pattern-match operator. > The other part of the eep (multiple patterns) is OK? As I said later in that message, I decided that I had enough for one message. There are a number of unpleasant aspects to the details of the multiple pattern proposal. Amongst them, the fact that "|" is already a very important symbol in Erlang with about as different a meaning as you could imagine, and the fact that it not merely perpetuates but expands a nasty hole in Erlang. Let me briefly explain that point. If a language allows a complex construction, it should let you *name* an abstraction of that construction and uses instances of it. To give an example where this isn't done, consider Java 1.5. You can have types like Map<String,Map<String,Vector<Long> > > but you cannot *name* any of these; only classes can have names. So when you see Vector<Long> x; Map<String,Vector<Long> > y; Map<String,Map<String,Vector<Long> > > z; there is no immediately visible connection between these types. It's enough to make you reach for dear old M4 so you can write define(Features, `Vector< Long >') define(Product_Name, `String') define(Catalogue, `Map< Product_Name, Features >') define(Company_Name, `String') define(Meta_Catalogue, `Map< Company_Name, Catalogue >') Features x; Catalogue y; Meta_Catalogue z; In the same way, in Erlang at present we can write complicated expressions, and we have abstractions of expressions, called functions. We have complicated patterns, BUT we have no named abstractions of patterns. The multiple pattern proposal makes patterns even MORE complicated, without naming them, so a human being reading one has to do an immense amount of decoding to figure out what the pattern *means*. If there are several places where you need (basically) the same complex pattern, too bad: you have to write the thing out in full each time because you can't NAME it and use it more than once. This is a disaster for maintenance, because it is far too easy to change *some* of the occurrences of the pattern and not others. Abstract patterns let you name patterns (simple, complex, or already in the first proposal, MULTIPLE) and use them whenever you want. While the multiple patterns proposal is not _technically_ flawed, or at least, not obviously so, it is not good software engineering. >> So instead of adding a new "crippled-bind" called ~=, >> I suggest that it would be better to allow >> Pattern = Expression as a guard. > You can't negate it! Who says? According to the current on-line Erlang reference manual, you can't negate *anything* in a guard, so this is nothing new. If you want to extend the syntax so that you *can* negate things in a guard, then why shouldn't = be as negatable as anything else? As long as we stick with the idea that guards are *NOT* things that evaluate to true or evaluate false, but rather things that succeed or fail, it is clear that Pat=GdExp can succeed or fail, so it makes just as much sense to negate *that* as anything else in a guard. > > I've also written, I think the most important use of the ~= operator > was > to express negated patterns, i.e. the ability to write a guard that > fails if (some part of) the matched value matches a pattern. It seems > you completely missed this point. Not *addressing* a point isn't the same as *missing* it. Here's what the proposal actually says: ... the most important use of the operator would be to extend pattern matching with negated patterns as in the following example pattern: PATTERN1 when not (PATTERN2 ~= Variable_bound_by_PATTERN1) I'm sorry to have to point this out, but this is not an example. It's a *schematic* example, that illustrates but does not exemplify. Once again I want ACTUAL examples from real programs. By the way, the syntactic operator '~=' includes a character that is used for negation in many languages, not least including C, C++, C#, and Java. I'm used to reading "~=" as "not equals", so to me "when not (Pat ~= GdExp)" looks like a double negation, and I find myself wanting to simplify it to "when Pat = GdExp". If you want to appeal to UNIX tradition for pattern matching operators, the traditional UNIX symbol for this is a simple "~" as in the AWK expression "$1 ~ /^fred/". > Please propose a different construct that expresses negated patterns, > and is easy to implement, understand and use. I am very far from being convinced that negation in patterns is at all a good idea. In fact, I think it has the potential to be very confusing indeed. However, I have now explained that - allowing = in guards is *always* more powerful than adding ~= - there is no reason why = in a guard cannot be negated, if there is anything in a guard that can be negated. Now I add - my proposal has no new construct, it just removes a restriction on the use of an existing construct, so it is at least as easy to use and understand as ~= - the implementation of ~= would be very nearly identical to the implementation of =; there seems to be no reason to believe that = is any harder to implement in guards than ~= I also repeat what I've been saying all along, which is that the abstract pattern proposal has been around for a long time, and keeps on turning out to be just right for new problems. Let's suppose you want to express when not {foo,_,27} = X OK, so write #foo_response(ping) -> {foo,_,27}); #foo_response(pong) -> {foo,_,42}); #foo_response(pang) -> bar. ... when #foo_response(Pung) = X, Pung /= ping We really cannot discuss this much further without *concrete cases* so that we can judge what might *actually* be written. > > I think I am not allowed to copy-paste code pieces from AXD301 here. > Beleive me, I could. > Do you want me to obfuscate and send a few? Yes please. > > >> Oh, and did I point out that abstract patterns can solve the >> "multiple patterns" problem neatly and clearly? > I accept your abstract patterns as useful and nice, but is quite a big > change in the language. My proposal is a small change. Your proposal adds TWO changes to the language: "|" in clause heads, and "~=" in guards. > > Easy to learn, Just because something is small does not mean it is easy to learn. As I've argued above, both "|" and "~=" are as confusing as heck. ("|" otherwise means "cons", "~" can mean "not" in other languages.) "~=" is riddled with special restrictions. > > easy to implement, > easy to document, no compatibility issues. Yes, but if one is changing a language, one may as well make ONE change that solves LOTS of problems, rather than cluttering it up with dozens of special-purpose kluges. -- "I don't want to discuss evidence." -- Richard Dawkins, in an interview with Rupert Sheldrake. (Fortean times 232, p55.) _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Mats Cronqvist-4
On 15 May 2008, at 11:40 pm, Mats Cronqvist wrote:
> i don't know where ro'k gets his code examples from, but i for one > have seen tons and tons of code where many patterns winds up in the > same > branch. It's not a question of where I get them but of where I *don't* get them. Now that you've told me that you've seen "tons and tons", please let me get them from you! Please post some actual examples, sanitised if necessary. This will improve the relevance/reality/usefulness of this thread enormously. -- "I don't want to discuss evidence." -- Richard Dawkins, in an interview with Rupert Sheldrake. (Fortean times 232, p55.) _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Richard O'Keefe
Hi,
I am trying to end this discussion with some usable result. First let me state that - I am now convinced that ~= is not a good idea, therefore I am not going to submit it in an eep. - I am convinced that multiple patterns is a good idea (many of you stated that you like it). I am about to send it as an eep, we just have to agree on the right notation. > Yes, but Virding's proposal uses ";" for the *SAME* meaning > ("or") that it normally has. My problem with ; is that it's ambiguous. I can write at least one pattern that could be parsed into two different ASTs. Pattern when Guard; true -> now is this a single pattern: Pattern when (Guard; true) ? or is it multiple patterns: (Pattern when Guard); true ? Both of them are syntactically correct and meaningful as well. You can convince me that this is no problem, the new use of ; will not introduce any confusion, but I am aware. I think using a new operator is better. > that "|" is already a very important symbol in Erlang with about > as different a meaning I think "|" in this context is not confusable with [_|_], but maybe yes. Can anyone suggest another operator? Now I'll answer to a few other thoughts. I am trying to reply to only those where I hope my answer might take Erlang forward. > The multiple pattern proposal makes patterns even MORE complicated, > without naming them, so a human being reading one has to do an > immense amount of decoding to figure out what the pattern *means*. > If there are several places where you need (basically) the same > complex pattern, too bad: you have to write the thing out in full > each time because you can't NAME it and use it more than once. > This is a disaster for maintenance, because it is far too easy to > change *some* of the occurrences of the pattern and not others. I have seen pieces of code when multiple patterns (as in my proposal) could have been used, but have not seen a single case when the same multiple pattern occured in several places. > Abstract patterns let you name patterns (simple, complex, or already > in the first proposal, MULTIPLE) and use them whenever you want. I think the use of abstract patterns for what I suggest multiple patterns for leads to lengthy extra code that is unnecessary. However, abstract patterns are great for other uses, but not for this very simple thing. > > You can't negate it! > Who says? According to the current on-line Erlang reference > manual, you can't negate *anything* in a guard, >From the Reference Manual: "The set of valid guard expressions... ... arithmetic expressions...". Example: 1> case a of X when not is_pid(X) -> not_pid end. not_pid > - allowing = in guards is *always* more powerful than adding ~= > - there is no reason why = in a guard cannot be negated, > if there is anything in a guard that can be negated. I agree. If you can negate it, it is clearly better than what I suggested with ~=. What would be the syntax and semantics? It would stink because of the same problem of not binding variables (if negated)! > I also repeat what I've been saying all along, which is that > the abstract pattern proposal has been around for a long time, and > keeps on turning out to be just right for new problems. OK, as I said before, I am convinced that your abstract patterns are great, but when will the eep be ready? Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
Andras Georgy Bekes wrote:
> Hi, > > I am trying to end this discussion with some usable result. > > First let me state that > - I am now convinced that ~= is not a good idea, therefore I am not > going to submit it in an eep. > - I am convinced that multiple patterns is a good idea (many of you > stated that you like it). I am about to send it as an eep, we just have > to agree on the right notation. > > >> Yes, but Virding's proposal uses ";" for the *SAME* meaning >> ("or") that it normally has. >> > > My problem with ; is that it's ambiguous. > I can write at least one pattern that could be parsed into two different > ASTs. > > Pattern when Guard; true -> > now is this a single pattern: Pattern when (Guard; true) ? > or is it multiple patterns: (Pattern when Guard); true ? case bla of Pat when true ->; Pat when false->; Pat -> code() end. but that's not what he wrote... in that case i propose the above. currently gives syntax error. mats _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
Sorry for taking so long to comment this, but I have been thinking. :-) Comments follow. 2008/5/16 Mats Cronqvist <[hidden email]>:
Here I disagree, sort of. While I also think the ~= is not a good idea, I agree with Richard O'Keefe that having = as a legal guard test is a Good Thing. I also don't see any logical problems with it. If you have the semantics:
- if match succeeds it returns true and binds any unbound variables - if match fails, it returns false, i.e. it does generate an error Then you modify all boolean operations so that if they succeed, return true, then any new variables which are bound in them are exported, while if they fail, return false, no variables are exported.
- This will work for the whole guard as if the guard fails then no variables are exported but the clause is not chosen anyway. - No problems with not(...) as it will never export variables.
- Same with other boolean operators, success implies export. This makes checking for variable bindings in and after guards relatively easy. As far as I can see there are no problems with this.
Then as we allow = as a boolean test in guards we can extend it to be a valid *test* in list/binary comprehensions as well. It the match succeeds the test succeeds and exports the any new variable bindings. Someone asked for this earlier and while just having it in lc/bc might be a bit off having it as a valid *guard* test means it becomes acceptable as lc/bc test. It also easy to implement. I have the this feature already in LFE.
I don't have a problem with this, but I don't really see the need. The only time I have had repeated bodies they have been very simple no repeating just them has been very straight forward. While using ->; as syntax would be easy and cause no inconsistencies it has the downside that you would fail to capture the case where you have forgotten to give a body.
Actually thinking about it a bit more if you allow = in guards you really don't *need* this multiple pattern feature as you can express it as alternate guards. The problem would be that it would be more difficult to implement this pattern matching as efficiently as when it occurs the the head.
So maybe this solves the syntax question automatically. Robert _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
Robert Virding wrote:
> Sorry for taking so long to comment this, but I have been thinking. > :-) Comments follow. > > 2008/5/16 Mats Cronqvist <[hidden email] > <mailto:[hidden email]>>: [...] > > i was reading virding's proposal as; > > case bla of > Pat when true ->; > Pat when false->; > Pat -> > code() > end. > > but that's not what he wrote... > > in that case i propose the above. currently gives syntax error. > > > I don't have a problem with this, but I don't really see the need. The > only time I have had repeated bodies they have been very simple no > repeating just them has been very straight forward. i read the above as "i've never needed this myself, so it must be unnecessary." let me assure you that there are major telecom equipment vendors whose code bases would benefit greatly from this syntax. although i (no longer) has access to that code, the pattern appears quite often in event-driven programming. here's a very small example from a simple GUI application; loop(St) -> receive %% user deleted top window {?MODULE,{signal,{window1,_}}} -> quit(); %% user selected quit menu item {?MODULE,{signal,{quit1,_}}} -> quit(); %% user selected connect menu item {?MODULE,{signal,{connect,_}}} -> loop(conn(St)); %% user selected disconnect menu item {?MODULE,{signal,{disconnect,_}}} -> loop(disc(St)); %% user selected about menu item {?MODULE,{signal,{about1,_}}} -> loop(show_about(St)); %% user clicked ok in about dialog {?MODULE,{signal,{dialogb,_}}} -> loop(hide_about(St)); %% user deleted about dialog {?MODULE,{signal,{dialog1,_}}} -> loop(hide_about(St)); %% we got data from the top_top process {data,Data} -> loop(update(St,Data)); %% quit from the erlang shell quit -> quit(); %% log other signals X -> io:fwrite("got ~p~n",[X]),loop(St) end. _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
2008/5/23 Mats Cronqvist <[hidden email]>:
Robert Virding wrote: No, I meant my comment literally. It is not a problem that *I* have had so *I* don't see the need. If others have trouble with this then *they* see the need. So be it.
I accept the suggestion. But allowing = in guards really makes it unnecessary. In your example it could actually only be used in 1 place. Robert _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Mats Cronqvist-4
On 23 May 2008, at 11:05 pm, Mats Cronqvist wrote: Hooray! Evidence! > let me assure you that there are major telecom equipment vendors > whose > code bases would benefit greatly from this syntax. > although i (no longer) has access to that code, the pattern appears > quite often in event-driven programming. here's a very small example > from a simple GUI application; > > loop(St) -> > receive > %% user deleted top window > {?MODULE,{signal,{window1,_}}} -> quit(); > %% user selected quit menu item > {?MODULE,{signal,{quit1,_}}} -> quit(); > %% user selected connect menu item > {?MODULE,{signal,{connect,_}}} -> loop(conn(St)); > %% user selected disconnect menu item > {?MODULE,{signal,{disconnect,_}}} -> loop(disc(St)); > %% user selected about menu item > {?MODULE,{signal,{about1,_}}} -> loop(show_about(St)); > %% user clicked ok in about dialog > {?MODULE,{signal,{dialogb,_}}} -> loop(hide_about(St)); > %% user deleted about dialog > {?MODULE,{signal,{dialog1,_}}} -> loop(hide_about(St)); > %% we got data from the top_top process > {data,Data} -> loop(update(St,Data)); > %% quit from the erlang shell > quit -> quit(); > %% log other signals > X -> io:fwrite("got ~p~n", > [X]),loop(St) > end. > Let me start by making two changes to that code. The first is to indent it, so that I can read it. The second is to group together things with the same body. loop(St) -> receive quit -> %% quit from the Erlang shell quit() ; {?MODULE,{signal,{window1,_}}} -> %% User deleted top window. quit() ; {?MODULE,{signal,{quit1,_}}} -> %% User selected 'Quit' menu item. quit() ; {?MODULE,{signal,{connect,_}}} -> %% User selected 'Connect' menu item. loop(conn(St)) ; {?MODULE,{signal,{disconnect,_}}} -> %% User selected 'Disconnect' menu item. loop(disc(St)) ; {?MODULE,{signal,{about1,_}}} -> %% User selected 'About' menu item. loop(show_about(St)) ; {?MODULE,{signal,{dialogb,_}}} -> %% User clicked 'OK' in "about" dialogue. loop(hide_about(St)) ; {?MODULE,{signal,{dialog1,_}}} -> %% User deleted "about" dialogue. ; {data,Data} -> %% We got data from the top_top process. loop(update(St, Data)) ; X -> %% Log other signals. io:fwrite("got ~p~n", [X]), loop(St) end. In this case, it matters that *every* message is to be received and acted on. That means that we can once again use the factorisation technique. loop(State) -> receive Message -> loop(State, classify(Message)) end. classify(quit) -> quit; classify({?MODULE,{signal,{window1,_}}}) -> quit; classify({?MODULE,{signal,{quit1,_}}}) -> quit; classify({?MODULE,{signal,{connect,_}}}) -> connect; classify({?MODULE,{signal,{disconnect,_}}}) -> disconnect; classify({?MODULE,{signal,{about1,_}}}) -> show_about; classify({?MODULE,{signal,{dialog1,_}}}) -> hide_about; classify({?MODULE,{signal,{dialogb,_}}}) -> hide_about; classify({data,Data}) -> {data,Data}; classify(X) -> {error,X}. loop(_, quit) -> quit(); loop(State, connect) -> loop(conn(State)); loop(State, disconnect) -> loop(disc(State)); loop(State, show_about) -> loop(show_about(State)); loop(State, hide_about) -> loop(hide_about(State)); loop(State, {data,Data}) -> loop(update(State, Data)); loop(State, {error,X}) -> io:fwrite("got ~p~n", [X]), loop(State). I like this because it makes a clean separation between "what are the actions" and "what are the names for the actions". Of course you can in-line this. Just as we can have case/case, we can have case/receive, getting loop(State) -> case receive quit -> quit ; {?MODULE,{signal,{window1,_}}} -> quit ; {?MODULE,{signal,{quit1,_}}} -> quit ; {?MODULE,{signal,{connect,_}}} -> connect ; {?MODULE,{signal,{disconnect,_}}} -> disconnect ; {?MODULE,{signal,{about1,_}}} -> show_about ; {?MODULE,{signal,{dialog1,_}}} -> hide_about ; {?MODULE,{signal,{dialogb,_}}} -> hide_about ; {data,Data} -> {data,Data} ; X -> {error,X} end of quit -> quit() ; connect -> loop(conn(State)) ; disconnect -> loop(disc(State)) ; show_about -> loop(show_about(State)) ; hide_about -> loop(hide_about(State)) ; {data,D} -> loop(update(State, D)) ; {error,X} -> io:fwrite("got ~p~n", [X]), loop(State) end. Now my first reaction on seeing a whole raft of {?MODULE,{signal, {Foo,_}}} patterns was "this is too hard for me to read". I would be trying to simplify the protocol. Separating the receive protocol from the action selection makes this kind of maintenance easier. Inlining means that the versions with separate functions and with nested case/receive are operationally equivalent. A few hacks in the compiler could produce essentially the same code as the original version, although I doubt that it would be worth bothering. Tastes vary. To me, what we can write now in Erlang as it stands, separating "what are the actions" from "what are the names for the actions", is easier to read and understand than anything using multiple patterns would be, not because multiple patterns are a bad idea as such, but because combining multiple *complex* patterns into a single match makes the code harder to read. Multiple *simple* patterns might make for a more interesting example. -- "I don't want to discuss evidence." -- Richard Dawkins, in an interview with Rupert Sheldrake. (Fortean times 232, p55.) _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
Thanks for very nice example.
On Mon, May 26, 2008 at 4:54 AM, Richard A. O'Keefe <[hidden email]> wrote:
-- --Hynek (Pichi) Vychodil _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Richard O'Keefe
Hi,
> To me, what we can write now in Erlang as it stands, > separating "what are the actions" from "what are the names for the > actions", is easier to read and understand than anything using > multiple patterns would be, OK, you showed us (again?) that a possible use of multiple patterns can be substituted with something else. It always can be done, and everybody knew that. Following your way of thinking, we'd conclude that the 'case' construct is not needed because it can be substituted with auxiliary functions. Still we have the 'case' construct and like it. > not because multiple patterns are a bad idea as > such, but because combining multiple *complex* patterns into a single > match makes the code harder to read. That's subjective. To me, the multiple patterns version reads better. > Multiple *simple* patterns might make for a more interesting example. OK, you asked for real-life examples. OK, simple pattern. Here it is, straight from AXD301. I've replaced the "interesting" parts with foo, bar and baz. Everything else is original. ---------------------------------------- case classify_Foo(Foo) of undefined_Foo -> bar(); % lots of code here {meaningful_Foo, Bar, Baz} -> baz(Bar,Baz) % lots of code here end, ... classify_Foo(undefined) -> undefined_Foo; classify_Foo({undefined, _, _}) -> undefined_Foo; classify_Foo({Bar, Baz}) -> {meaningful_Foo, Bar, Baz}; classify_Foo({Bar, Baz, _}) -> {meaningful_Foo, Bar, Baz}. ---------------------------------------- How do you like it? I prefer the multiple patterns version. (Don't tell me the problem is with the data structures. We all know AXD301 is garbage :-) but still, our users like it. Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Mats Cronqvist-4
> case bla of
> Pat when true ->; > Pat when false->; > Pat -> > code() > end. > > but that's not what he wrote... > in that case i propose the above. currently gives syntax error. What about: case bla of Pat when true \/ Pat when false \/ Pat -> Never seen similar notation in other languages, but it should not be a problem :-) Georgy _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Robert Virding
Hi,
> I agree with Richard O'Keefe that having = as a legal guard > test is a Good Thing. > > - if match succeeds it returns true and binds any unbound variables > - if match fails, it returns false, i.e. it does generate an error > > Then you modify all boolean operations so that if they succeed, > return true, then any new variables which are bound in them are > exported, while if they fail, return false, no variables are > exported. > > - This will work for the whole guard as if the guard fails then no > variables are exported but the clause is not chosen anyway. > - No problems with not(...) as it will never export variables. > - Same with other boolean operators, success implies export. This > makes checking for variable bindings in and after guards relatively > easy. > > As far as I can see there are no problems with this. I think there is a problem. I think I can express a pattern that's matching must involve backtracking: F(A1,A2...) when ({X,_}=A1 or {_,X}=A1) and ({X,_}=A2 ... So this proposal leads to a language that's too powerful :-( Just like my very original proposal [1]. The problem with it is discussed [2] through [3]. > Actually thinking about it a bit more if you allow = in guards you > really don't *need* this multiple pattern feature as you can express > it as alternate guards. The "problem" is that this not only makes multiple patterns unnecessary, but also the whole "Pattern when Guards" stuff (i.e. the part before the 'when' keyword). Georgy References: [1]: http://www.erlang.org/pipermail/erlang-questions/2008-March/033718.html [2]: http://www.erlang.org/pipermail/erlang-questions/2008-March/033755.html [3]: http://www.erlang.org/pipermail/erlang-questions/2008-March/033799.html _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
| Powered by Nabble | Edit this page |
