Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

Syntax Sugar for Lambdas

The standard form of a lambda expression is a,b -> f a b or () -> c for a nullary function. This syntax is syntactic sugar for the declaration of a child feature of Function and creation of one instance at the point the lambda expression is used.

Nevertheless, there are many cases where this syntax is still somewhat awkward and could be shortened further.

Inline functions in other languages

Haskell

Since Haskell uses lazy evaluation by default every expression is a lambda expression. There is syntax sugar such as (+) for addition of numerical values.

TBD: check Haskell syntax sugar

Haskell syntax sugar verbose comment
do { file <- open "name"
   ; bytes <- readFully file
   ; process bytes }
              
open "name"
  >>=
    (\ file -> readFully file
      >>=
         (\ bytes -> process bytes ))

The do notation is a way to format the code of calls to bind on monads in a way that appears like procedural code.

(+) a b
              
a + b
        

Operators in Haskell can be used as prefix functions if put in parentheses.

(+a)
              
(\ x -> x + a)
        

Operator in parentheses with one argument to one side is interpreted as a unary function with the argument added to the other side.

(-) a b
              
a - b
        

Functions with non-alphanumerical names are operators. Placed in parentheses, they can be used like normal function names.

a `f` b
              
f a b
        

Functions with alphanumerical names can be turned into operators using back ticks.

F#

F# provides forward and backward pipes to apply values provided in tuples as missing arguments in partially applied functions.

F# syntax sugar verbose comment
a |> f x y
        
f x y a
        

The pipe-operation does not help with lambdas, but with chaining calls.

The pipe-operator is very similar to chaining calls with dots in object-oriented languages (a.f(x,y)), but with the difference that the value is passed as an argument, not as the target object.

g |||> f x y
        
let (a, b, c) = g
f x y a b c
        

A pipe can deconstruct a tuple into several arguments that are passed to a function that is called.

Java

Java's lambda expressions are for Java's standards already very heavy syntax sugar. The additional syntax sugar is limited:

Java syntax sugar verbose comment
(a,b) -> { f(a,b); }
(Type1 a, Type2 b) -> { return f(a,b); }

Java performs type inference for the arguments of a lambda.

(a,b) -> f(a,b)
(a, b) -> { f(a,b); }

{ } and return can be omitted for simple lambdas.

a -> f(a)
(a) -> f(a)

( ) can be omitted if there is only a single argument.

Groovy

Groovy has an implicit argument it which is used for unary lambdas.

Groovy syntax sugar verbose comment
{ println it }
        
{ it -> println it }
        

Special handling using it available for unary lambdas only.

Lambda Syntax Sugar in Fuzion

Here are some suggestions for possible syntax sugar in Fuzion:

Fuzion syntax sugar verbose comment
a,b -> f a b
        
(a,b) -> f a b
        

parentheses are optional

(+)
        
a, b -> a + b
        

An infix operator could be abbreviated by just putting it into parentheses. The fact that this has to be an infix operator becomes clear from the type of the field the lambda is assigned to. A function with two arguments means the lambda has to be an infix operator.

Note that the parentheses are required such that the parser can distinguish the case a + b, which is an infix operator + applied to two values a and b from a (+) b, which is a call to a with two arguments (+) and b.

(-)
        
a -> -a
        
or
a -> a-
        

A unary operator could be abbreviated by just putting it into parentheses. The fact that this has to be an infix operator becomes clear from the type of the field the lambda is assigned to: A function with one argument means the lambda has to be a unary operator.

The problem is that we do not know at this point if it is a prefix or a postfix operator. The code to lookup the actual feature called must take both, prefix and postfix into account. If one is found, we can take it. If both exist, the code is ambiguous and we must flag an error.

+expr
        
a -> a + expr
        

A prefix operator applied to an expression used as a lambda with one argument can be treated as partial application of an infix operator where the argument is the left hand side.

This should also work for numeric literals of the form +3.14 or -1.

expr-
        
a -> expr - a
        

An postfix operator applied to an expression used as a lambda with one argument can be treated as partial application of an infix operator where the argument is the right hand side.

(.f x y)
        
a -> a.f x y
        

Applying a dot-call to the single argument of a lambda could be abbreviated using this syntax.

f x y
        
a,b,c -> f x y a b c
        

Partial application: A call used as a lambda could be considered a partially applied call.

arbitrary expression
        
() -> arbitrary expression
        

Automatic lazy evaluation for expressions that are not assignment compatible to an argument of function type, but assignment compatible to the result of that function type.

x >>= (.f x y)
        
x.bind (a -> a.f x y)
        

This would allow chains of the form (io.file.open name) >>= (.readFully) >>= (x -> process x). TBD: Do we need better syntax sugar for this? What operators do other language use for bind?

last changed: 2024-06-28