Skip to content

Functions LRM

Gaurang Sadekar edited this page Feb 27, 2016 · 8 revisions

Functions

All functions in JSJS are Lambda expressions. Since functions are treated as first class citizens, these lambda expressions can be assigned as values to identifiers, passed as arguments to other functions, and returned as values from other functions.
To make a named function declaration, a lambda expression is assigned to an identifier using the val keyword, just like any other type declaration.

Lambdas

Lambda expressions are denoted by the symbol /\, which resembles the upper case Greek letter Lambda. JSJS Lambda expressions have the following form:

/\(argument declarations if any) : return type => { 
  Block of expressions, the last of which  
  is the value that is returned
}

A shorthand syntax is also supported if the body of the Lambda is a single statement:

/\(argument declarations, if any) : return type => expression

The argument declarations must be annotated with their types, and a return type of the body of the /\ expression also must be specified.
For example, the following /\ expression takes a single number x as an argument and evaluates the square of x.

/\(x : num) : num => x * x

It is also possible to define Lambda expressions that don't take any arguments:

/\() : unit => println("नमस्ते")

or those that take multiple arguments:

/\(fname : string, lname : string) : string => "Hello " ^ " " ^ fname ^ " " ^ lname

The body of a Lambda can also be a block of expressions, where the last expression is the one that is implicitly evaluated and returned. The following /\ takes a single numeric argument x and adds the value y - assigned as 10 in the body - to x.

/\(x : num) : num => {
  val y = 10;
  x + y;
}

AST for /\ expressions:

type expr:
| FunLit of func_decl

func_decl = {
  formals     : (string * primitiveType) list;
  return_type : primitiveType;
  body        : expr;
}

Grammar:

literals:
| LAMBDA LPAREN formals_opt RPAREN COLON primitive FATARROW expr %prec ANON {
        FunLit({ 
            formals = $3; return_type = $6; body = Block([$8]); 
        })
    }
| LAMBDA LPAREN formals_opt RPAREN COLON primitive FATARROW block {
        FunLit({ 
            formals = $3; return_type = $6; body = Block($8);
        })
    }

Function Types

When an identifier is assigned to a /\ expression, it becomes a value of the function type. The type of a function is

fn : (A,B) -> C

Here, fn takes 2 arguments of type A and B respectively, and evaluates an expression or block of type C. In general, a function type is a list of input argument types (optional) and return type.

When assigning an identifier to a /\ expression using the val keyword, annotating the identifier with the function type is optional, just like type specifiers for all other expressions.

// function type explicitly specified
val cube : (num) -> num = /\(x : num) : num => x * x * x ;  

// function type of val not annotated
val whatDoYouKnow = /\(name : string) : string => {
  if name == "John Snow" 
  then "Nothing"
  else "Something" ;
} ;

AST:

type primitiveType = 
| TFun of funcType
and funcType = primitiveType list * primitiveType

Grammar:

primitive:
| LPAREN args RPAREN THINARROW primitive  { TFun($2, $5) }

args:
| args = separated_list(COMMA, primitive) { args }

Function Calls and Usage

Functions are called by invoking the name of the function and passing it actual arguments. These arguments can be any kind of expressions.
Every function call is itself an expression, and evaluates to a value which has a type (the return type of function).

// function called with a numeric literal
val sq5 = sq(5)

// function called with an expression
val x = 8;
val y : num = sq(x);
val z = cube(x + y);

// function called with a function as an argument
val addOne = /\(x : num) : num => x + 1;
val addOneSqr = /\(f: (num) -> num, g: (num) -> num, x : num) : num => f(g(x)); 
val result = addOneSqr(sq, addOne, 8);

AST:

type expr = 
| Call of string * expr list

Grammar:

expr:
| ID LPAREN actuals_opt RPAREN              { Call($1, $3) }
Clone this wiki locally