docs/types/function-types.md
As a functional programming language, the type of functions in Enso (->) is
key. There are a few things that should be noted about functions in Enso.
<!-- MarkdownTOC levels="2,3" autolink="true" --> <!-- /MarkdownTOC -->[!NOTE] The actionables for this section:
- Work out a full specification for function typing and behaviour.
- Calling a function with an upper-case letter instantiates all of its type arguments to free type variables.
Enso's scoping rules should be fairly familiar to most other programming languages, as it uses standard lexical scoping with shadowing. However, there are a few unique points to keep in mind:
Scope lookup proceeds from the function body outwards, as is standard for lexical scoping. For a detailed discussion of scoping, please see the scoping documentation.
[!WARNING]
PLEASE NOTE. THIS IS OUT OF DATE.
Structural Type Shorthand
In Enso, we want to be able to write a type-signature that represents types in terms of the operations that take place on the input values. A classical example is
add:rubyadd : a -> b -> b + a add = a -> b -> b + aThere are a few things to note about this signature from a design standpoint:
aandbare not the same type. This may, at first glance, seem like a signature that can't work, but the return type, in combination with our integratedConvertiblemechanism gives us the tools to make it work.- The return type is
a + b. This is a shorthand expression for a detailed desugaring. The desugaring provided below is what the typechecker would infer based on such a signature.rubyadd : forall a b c d. ({+ : Convertible b c => a -> c -> d} <: a) => a -> b -> dThis may look fairly strange at first, but we can work through the process as follows:
- The expression
b + ais syntactic sugar for a method call on a:a.+ b.- This means that there must be a
+method on a that takes both anaand ab, with return-type unspecified as of yet:+ : a -> b -> ?- However, as
Convertibleis built into the language, we have to consider that fora.+ bto work, the+method can actually take any type to whichbconverts. This introduces the constraintConvertible b c, and we get+ : a -> c -> ?- The return type from a function need not be determined by its arguments, so hence in the general case we have to default to an unrestricted type variable giving
+ a -> c -> d.- This method must exist on the type
a, resulting in the constraint that the row{+ : a -> c -> d} <: amust conform to that interface.- We now know the return type of
a + b, and can rewrite it in the signature asd.Please note that
a <: b(which can be flipped as:>) means thatais a row that is a sub-row contained within the rowb. The containment relation allows for the possibility thata == b.The inferred type for any function should, in general, match the given type signature. Cases where this break down should only exist where the type signature acts to constrain the function type further than would be inferred.
The actionables for this section are:
- Clean it up and work out how it applies in light of the new developments of typesets.
Enso introduces a function composition operator which composes functions after
all arguments have been applied. This operator is >> (and its backwards cousin
<<). It takes a function f with n arguments, and a function g with m
arguments, and the result consumes n arguments, applies them to f, and then
applies the result of that plus any additional arguments to g.
[!WARNING] Enso does support
>>as well as<<operators, butrubycomputeCoeff = (+) >> (*5) doThing = (+) >> (*) main = computeCoeff 7 3 Execution finished with an error: Method `*` of comp.computeCoeff.f[comp.enso:11-12] a=7 b=_ could not be found. at <enso> comp.computeCoeff.g(comp.enso:14:9-11) at <enso> Function.>>(Function.enso:66:7-12) at <enso> comp.main(comp.enso:17:8-20)
In addition, we have the operator ., which acts as standard forward function
chaining in Enso, and its backwards chaining cousin <|.
[!NOTE] The actionables from this section are:
- Examples for the more advanced use-cases of
>>to decide if the type complexity is worth it.- Otherwise, standardise on using
>>and<<for standard function composition:
<< : (b -> c) -> (a -> b) -> a -> c- backwards composition (standard)>> : (a -> b) -> (b -> c) -> a -> c- forwards composition