Polymorphism by the values ​​of arguments (not types)?

Is there a programming language (can be a conceptual or research document) that allows polymorphism according to the values ​​of the arguments of the function / method? View:

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?

+4
source share
3 answers

I assume that you are looking for matching patterns and / or guards. For example, Erlang allows you to:

 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 combination of patterns, where the first argument is "bar" , 42 or something else. Both methods can be found in many functional languages.

Just in case, you are not familiar with the equivalent syntax (as far as you can compare):

 function foo("bar", x) { return bar(x); } function foo(42, x) { return baz(x); } ... 
+8
source

In 2006, Matthias Blum called “Extensible Programming with First-class Cases”, which talks about such a system (based on ML, IIRC).

You may be able to do the same with some aspect-oriented languages ​​such as AspectJ, but I have not tried this.

In addition, in languages ​​like Scheme, which support both first-class functions and mutation of names associated with functions, you can extend the 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 

Function overrides are accepted for debugging, but frowned for "real code", and some modules do not allow mutations to export modules. In this case, the alternative is to have a private mutable variable containing a list of cases; the main function explicitly goes through cases, and there is a separate function to add cases.

+2
source

Template compatibility and protection is one way to do this; OCaml, Haskell, and Scala also provide them.

The prolog has a similar function: you can define relationships that depend on specific values. For instance:

 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 executed when Y = X !; To do this, we specialize in three cases: one of which contains a certain value, and the other - a range test.

Yes, the prologue is really strange. Programming consists of recording true statements; you then query the system for the truth of a particular statement or assignment to a variable, which makes the 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. 
+1
source

Source: https://habr.com/ru/post/1393558/


All Articles