9.1 Application syntax
So far we've applied a function like in C.
fun sum : int * int -> int = '$1+$2'; fun neg : int -> int = '-$1'; println ( sum (1,neg (2)) );
-1
However, parens in Felix simply provide grouping: functional style application does not require them:
println ( sum (1,neg 2) );
-1
The parens around the sum
argument are required.
Hey, that's a typo you say! sum
has two arguments!
No it doesn't. sum
has a single argument which
is of the type of a cartesian product {int * int}.
The parens are only required because operator
whitespace, which is used for application, has
a higher precedence than operator comma, which
is used for tuple formation. Here's the proof:
var x = 1, neg 2; println ( sum x );
-1
There's another syntax for application, using operator dot:
println (1,2.neg).sum;
-1
As you can see, operator dot is reverse application and has a higher precedence than operator whitespace. This operator gives expressions and "OO" feel, and the left to right ordering of application is arguably more natural to programmers than mathematical notation.
Felix provides yet another application operator:
println$ sum$ 1, neg 2;
-1
Operator dollar is a forward infix operator like whitespace but it has very low precedence and is right associative. I commonly write the {$} hard up against the left hand function name if the LHS is an identifier, which gives the appearance of a command where the {$} is part of the name.
Operator dollar was stolen from Haskell.
In combination, these three operators make it possible to write many expressions without any parentheses. However there's one more which is useful for that:
fun zero : 1 -> int = "0"; println$ zero(); println$ #zero;
0 0
If the argument is () you can use the very high precedence operator hash. Operator hash is higher precedence than operator dot. It gives the feel of a specially named value, which makes sense because pure functions of unit argument must always return the same value, that is, they're constant functions.
9.2 Call syntax
Although we didn't tell you the proper syntax for a call is:
call println 1;
1
However the operator call
can be left out. Felix then sees
application syntax. However Felix does not allow you to discard
values the way C does. So if it sees a whitespace application which would
discard a value if the LHS term of the application were a function,
Felix assumes it is a procedure. This means you can do this:
proc hello : 1 = '::std::cout<<"hello"<<::std::endl;' requires header ' ' ; call hello (); hello (); hello; call hello;
hello hello hello hello
All these four calls are equivalent. Eliding the trailing () is inspired by Pascal.
There are some things resembling calls we will meet later.