Reputation: 10709
Is there a programming language (may be a concept or research paper), which allows a polymorphism over function/method arguments values? Kind of:
function factorial(int value > 0){ /* code here */}
function factorial(int value == 0){ /* code here */}
function factorial(int value < 0){ /* code here */}
And, what is the official name, if any, for this kind of polymorphism?
Upvotes: 4
Views: 129
Reputation: 29090
Pattern matching and guards is one way of doing this; OCaml, Haskell, and Scala all provide them as well.
Prolog has a similar feature: you can define relations that depend on specific values. For example:
factorial(X, 0) :- X =< 0, !.
factorial(1, 1).
factorial(X, Y) :- X2 is X - 1, factorial(X2, Z), Y is X * Z.
In this code, we define a factorial
relation such that factorial(X,Y)
is satisfied when Y=X!; to do so, we specialize it over three cases, one involving a specific value and another involving a range test.
Yep, Prolog is really weird. Programming consists of writing down true statements; you then query the system for the truth of a particular statement or a variable assignment which makes a statement true. For example, if the above code is saved in factorial.pl
:
?- consult(factorial).
% factorial compiled 0.00 sec, 2,072 bytes
true.
?- factorial(3, 6).
true .
?- factorial(5, X).
X = 120 .
?- factorial(4, 25).
false.
Upvotes: 1
Reputation: 522081
I guess what you're looking for is pattern matching and/or guards. Erlang for instance allows this:
foo(X) when X > 0 -> bar(X);
foo(X) when X == 0 -> baz(X);
foo(X) -> X.
foo("bar", X) -> bar(X);
foo(42, X) -> baz(X);
foo(_, X) -> X.
The former demonstrates the use of guards, the latter is a simple pattern match, where the first argument is either "bar"
, 42
or anything else. Both techniques can be found in many functional languages.
Just in case you're not familiar with the syntax, that's equivalent to (as much as it can be compared):
function foo("bar", x) {
return bar(x);
}
function foo(42, x) {
return baz(x);
}
...
Upvotes: 8
Reputation: 10653
There's a 2006 paper by Matthias Blume called "Extensible Programming with First-Class Cases" that talks about such a system (based on ML, IIRC).
You might be able to do the same sort of thing with some aspect-oriented languages like AspectJ, but I haven't tried it.
Also, in languages like Scheme that support both first-class functions and mutation of names bound to functions, you can extend a function by wrapping the old version:
(define (factorial n)
1)
(factorial 0) ;; => 1
(factorial 5) ;; => 1
(set! factorial
(let ([old-factorial factorial])
(lambda (n)
(cond [(> n 1)
(+ (factorial (- n 1)) (factorial (- n 2)))]
[else
(old-factorial n)]))))
(factorial 0) ;; => 1
(factorial 5) ;; => 8
(factorial 6) ;; => 13
Redefining a function is accepted for debugging but frowned upon for "real code", and some module systems don't allow mutation of module exports. In that case, an alternative is to have a private mutable variable containing the list of cases; the main function explicitly goes through the cases, and there is a separate function for adding cases.
Upvotes: 2