4 ms·
I really hope this doesn't happen. I've never understood the infatuation for this Haskell type syntax where you need to repeat the name of the function for eac
by hota_mazi 7y ago
I really hope this doesn't happen.
I've never understood the infatuation for this Haskell type syntax where you need to repeat the name of the function for each and every single match case. It's so needlessly verbose.
- macintux 7y agoI find it dramatically cleaner. Each clause is categorically isolated, unlike a case statement (the alternative in Erlang, with which I’m most familiar) where code can precede the case statement and thus introduce bindings that can muck up the logic.
- hota_mazi 7y agoYes but why repeat the name of the function every time? It might make more sense if such clauses are scattered through the source, but they are pretty much all the time grouped together, so the name of the function doesn't need to be repeated all the time. For example, instead of factorial 0 => 1; factorial n => n* factorial(n-1); Something like factorial { 0 => 1 n => n* factorial(n-1); }
- zamalek 7y agoIt's probably for double dispatch, which Rust doesn't have outside of traits anyway.
- AaronFriel 7y agoRepeating the name allows some optimizations but you'd be unlikely to use or benefit from them unless you were writing functions that returns functions and you could benefit from inlining some patterns and not others. I think I've seen the pattern in some web framework code, byte libraries, etc. Although semantically equivalent, the optimizer treats the following differently: f a = \b -> ... f a b = ...
- macintux 7y agoAs much as I like short functions, not all function clauses are just one line. I don’t see your alternative as helpful for longer clauses.
- TazeTSchnitzel 7y agoBoth are possible in Haskell: factorial 0 = 1 factorial n = n * factorial (n - 1) // or: factorial n = case n of 0 -> 1 n -> n * factorial (n - 1)
- OskarS 7y agoA lot of this has its origin in Prolog, and there having multiple full definitions is much more natural, given the nature of the language: each predicate can have any number of definitions and then you have back-track to find the right one. A trivial example: parent(alice, brad). parent(alice, cecilia). parent(cecilia, david). parent(david, emily). parent(brad, felix). parent(felix, ginny). ancestor(A, B) :- parent(A, B). ancestor(A, B) :- parent(A, M), ancestor(M, B). The first section defines a small family: alice is the parent of brad and cecilia, cecilia is the parent of david, etc. (identifiers beginning with lower-case letters are atoms, the ones beginning with upper-case are variables). Note that for these first definitions without a body (called "facts" in prolog), it's perfectly natural to have multiple "definitions": you can have as many parent-child relations as you want. The second predicate ("ancestor") is more interesting: it has two definitions: if A and B are people, then A is the ancestor of B if A is the parent of B, or if A is the parent of M, and M is the ancestor of B. Notice that there are is no pattern matching happening (Prolog of course has pattern matching, it more or less invented the concept, but I'm not using it here). When you use "ancestor", Prolog has no idea which definiton you want, the patterns are identical. It has to try the first one, and if it fails, it backtracks and tries the second one. Some examples of using this in the repl. First, "who are alice's children": ?- parent(alice, Child). Child = brad ; Child = cecilia. The semi-colon means "or", so this means "Child is equal to brad, or Child is equal to cecilia". Second, "who are ginny's ancestors": ?- ancestor(Ancestor, ginny). Ancestor = felix ; Ancestor = alice ; Ancestor = brad. The central idea here is that there is no "one definition" of a predicate or fact, you can have as many as you want, and prolog will search through them. Similarly, any query can have multiple values for the variables that make them true. Repeating the predicate name is the most natural way of expressing this idea. You don't have to, you could rewrite these so that they had only one definition, but that just makes what's going on less clear.
- malkia 7y agoMight be wrong here, but if this is to work, will it work across different compilation units? E.g. what if there is a "rogue" version that matches some literal - in way it'll serve as AOP (aspect oriented programming), but it'll be more like monkey patching. It may be useful, but spooky. (Very basic rust/haskell knowledge, just familiar with the core concepts).
- steveklabnik 7y agoThe proposal stated: > Every function clause must be together. It is an error to put another item between two function clauses. So, it would not. Then again, the proposal wasn't accepted so it's kind of a moot point. But you're totally right that without this it would be very tricky. Given that match arms have an ordering, I'm not sure you could come up with a semantic where it would work across compilation units.
- fnord123 7y agoNo way is it clearer. Moving a pattern match to the top level removes the obvious intent that two (or more) functions overload each other and remove the debug/trace point for figuring out why one body was chosen over another.
- macintux 7y agoI would argue that depends on the language. Neither issue you describe is a problem in Erlang.
- herodotus 7y agoI suspect that Rod Burstall was more interested in conceptual clarity than compactness. I often heard him say "Efficiency is the enemy of clarity". Of course he was probably referring to code, but he might have applied the same thought to language syntax.
- rdtsc 7y agoMost languages which allow for function head clauses also have case or switch statements. So you can use both. I like the pattern when there is a corner case that needs quite a bit of logic but it's not very important for how the code usually works, and you won't want an indent level on it. For example: function(SpecialCase ...) -> ... handle_odd_special_case; function(DefaultWhatever ...) -> ... main_business_logic. This is more cleaner _sometimes_ than say function(...) -> case Arg of SpecialCase -> ... handle_odd_special_case; Default -> ... main_business_logic end Now imagine another level of case statements and all of the sudden the main path of the algorithm is squashed to the right with only a 40 columns left.
- sullyj3 7y agoIt seems to me that the things people like about the haskell style syntax are 1. Don't have to name the parameter 2. less nesting. You can get the best of all worlds with lambdacase style constructs. You don't need to write out the name of the function a bunch of times. function = \case SpecialCase -> ... handle_odd_special_case; Default -> ... main_business_logic;