3 ms·
Yes 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
by hota_mazi 7y ago
Yes 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.