Grok Functionals - vilinski/nemerle GitHub Wiki

This page is a part of the Grokking Nemerle tutorial.

Functional values

In Nemerle you can pass functions as arguments of other functions, as well as return them as results. This way functions are not worse than any other data types (think about Equal Rights for Functions movement :-)

In C# there are delegates. This concept is quite similar to functional values. However, functional values are far more efficient and their types need not be declared before use.

As a first example consider:

// C#
delegate int IntFun(int);

class Delegates
{
  static int f(int x)
  {
    return x * 2;
  }

  static int run_delegate_twice(IntFun f, int v)
  {
    return f(f(v));
  }
  
  static void Main()
  {
    System.Console.WriteLine("{0}", run_delegate_twice(new IntFun(f), 3));
  }
}
 //  Nemerle
 class Functions
 {
   static f(x : int) : int
   {
     x * 2
   }

   static run_funval_twice(f : int -> int, v : int) : int
   {
     f(f(v))
   }

   public static Run() : void
   {
     System.Console.WriteLine("{0}", run_funval_twice (f, 3))
   }
 }

In this example delegates seem just like function pointers in C. Functional values do not appear any better, except maybe for the shorter syntax. However, the real power of delegates comes from the fact that methods can be used as delegates (thus effectively embedding the this pointer in the delegate). This is much like "functional objects" design pattern in C++. We will not show it here, please refer to the C# manual for details.

Using methods as delegates does not demonstrate their full power. In the following example, we will use a nested functional:

 class MoreFunctions
{
   static run_twice (f : int -> int, v : int) : int
   {
     f(f(v))
   }

   static run_adder (x : int) : void
   {
     def f(y : int) : int { x + y };
     System.Console.WriteLine("{0}", run_twice(f, 1))
   }

   public static Run() : void
   {
     run_adder(1);
     run_adder(2);
   }
 }

This example prints 3 and 5. Note how x is captured in the local function f.

Types of functions taking more than one argument are represented as tuples. For example, the following function:

 some_function(_arg1 : int, _arg2 : string, _arg3 : Foo) : float
 {
    //  ...
    System.Convert.ToSingle(_arg1)
 }

has the type int * string * Foo -> float. Functions that take no arguments pretend to take one argument of the type void. Thus the function:

 other_function() : string { "kaboo" }

possesses the type void -> string.

Lambda expressions

Lambda expressions are just a syntactic sugar to defined unnamed local functions. Unnamed local functions are useful when you need to pass some function to the iterator, so you use it just once.

Lambda expressions are defined using the fun keyword, followed by formal parameters, an optional return type and the function body.

 def x = Nemerle.Collections.List.Map ([1, 2, 3], fun (x) { 2 * x });
 def y = Nemerle.Collections.List.FoldLeft (x, 0, fun (val : int, acc) { acc + val });
 assert (y == 12);

In general:

fun (parms) { exprs }

is equivalent to:

{ 
  def tmp (parms) { exprs };
  tmp
}

This feature is similar to anonymous methods in C# 2.0 and lambda expressions in C# 3.0.

Also, you can use syntax of C# 3.0 lambda expressions:

parm => parm * parm
(parm1, parm2) => parm1 * parm2

It syntax provide by "=>" macro. Yuo can see it implementation here: https://github.com/rsdn/nemerle/tree/master/macros/operators.n (search "@=>"... in this file)

Exercises

2.1. Write a function

string_pow : int * (string -> string) * string -> string;

The call string_pow (3, f, "foo") should result in calling f three times, i.e. returning result of f (f (f ("foo"))). When you are done, write a second version of string_pow using recursion (if you used imperative loop) or imperative loop (otherwise).

Test it by passing function that replaces "42" with "42ans". You can try passing the functional argument to string_pow as a lambda expression. This method might be useful.

⚠️ **GitHub.com Fallback** ⚠️