lambda
lambda copied to clipboard
Implement operators for objects
The default behavior should be to apply the same operator to each member, but it needs to be defined in detail for binary operators that receive two objects (they may have different fields) and for native objects (they may be cyclic).
Operator overloading should be allowed due to important use cases (e.g. it is good to define partial order and equivalence relationships on elements of arrays, so that those relationships need not be specified to array methods such as contains
, sort
, unique
, union
, etc.
Proposed syntax for operator overloading:
let operator = fn x: type, y: type -> expr in rest
Where:
-
operator
is the operator that is being overloaded, such as<=
; -
type
are the types for which the operator is being overloaded; -
expr
is whatever Lambda expression; -
rest
is the rest of the program.
Example:
let <= = fn x: complex, y: complex ->
and (<= x.real y.real) (<= x.imaginary y.imaginary) in
...
Notes:
- An operator can be referred to and invoked inside the
expr
that defines the operator itself, and the name may actually refer to the same overload. But, as usual, the initialization expression of alet
statement is evaluated before adding the new name to the context, which means that the operator would not refer to itself but rather to its previous definition. If there is no previous definition with that prototype a runtime error must be thrown (a type error will be thrown when the type system is available). - An error must be thrown if the developer tries to assign a polymorphic lambda to an operator or a lambda whose arity is different than one for unary operators and different than two for binary ones.
Hint: why not also try to assess the properties of the new definitions? We could issue warnings if the user tries to define partial order operators to something different than partial order relationships or define equivalence operators to something different than equivalence relationships.
We should also disallow the overloading of the following operators: <
, >=
, >
, !=
, because their definition should be automatic and always consistent with <=
and =
.
Overloading <=
should automatically define the following for the same types:
-
let >= = fn x, y -> <= y x in
-
let < = fn x, y -> and (<= x y) (not (<= y x)) in
-
let > = fn x, y -> and (<= y x) (not (<= x y)) in
Overloading =
should automatically define the following for the same types:
-
let != = fn x, y -> not (= x y) in