#32 Functional Programming

brian Sun 15 Jan 2006

The next high risk feature I want to tackle is functional programming and closures. I want this style of programming to be highly integrated into the language and the core library (like collections). I suspect how we design functional programming features will force us to rethink other aspects of the language (like parameterized types - I already have some new ideas). I think there are three major components to the functional design:

  • Method References: how to specify a strongly typed functional signature which may be called on demand. Method references are needed to define the parameters for methods like Int.times() or List.each()
  • Method Binding: how to bind existing instance and static methods to method references to use where method references are needed potentially with this or other arguments predefined)
  • Closures: the ability to define an "anonymous method" to use where a method reference is expected. Closures provide access to the lexical space including local variables.

All three aspects need to be nailed down regarding terminology, syntax, and implementation.

Method Reference

A method reference is a method signature to "type a function pointer". I want to avoid having to define Java-like interfaces for the common case of a single method call - rather I want the signature defined inlined just like any other variable such as Int or Str[]. We need a term to use in discussions, and possibly a class name (or maybe just use Method itself). Possible terms to use:

  • MethodRef
  • Func/Function
  • Method
  • Delegate
  • Hook
  • Handler
  • Callback
  • Op/Operation

I dislike the C function pointer syntax (C# delegates use similar syntax) because the name is sandwiched between the return and param types, which goes against normal "Type name" declarations. I've been kind of thinking of using Ruby-like {|x| ...} as the closure syntax, which leads me to propose a syntax such as:

|Type1 arg1, Type2 arg2 -> ReturnType|
|Int x, Int y -> Str|  // Str f(Int x, Int y)
|Obj x|                // Void f(Obj) - implicit void
|-> Obj|               // Obj f()
||                     // Void f() - seems rare

Some examples in Fan code:

// Sys::Int.times
Void times(|Int i| func)
{
  for (Int i=0; i<this; ++i) func(i)
}

// Sys::List.collect
List collect(|Obj item, Int index -> Obj| func)
{
  List result = List.make(size);
  for (Int i=0; i<size; ++i)
    result.add( func(get(i), i) )
  return result;
}

Method Binding (Currying)

I want it to be really easy to specify a method as a first class object ("curried" methods). My current thinking is to use the C style address-of "&" operator with a normal method call. Instead of executing the method, it would turn it into a method reference (MethodRef, Method, Function, whatever). You could prebind zero or more parameters to the method. If the method was an instance method you could bind it to a target or use a static like signature so that target was unbound:

Method m = &"hello".upper;  m() -> "HELLO"
Method m = &Str.upper; m("hello") -> "HELLO"
Method m = &Sys.type; m("sys::Int") -> sys::Int
Method m = &Sys.type("foo::Bar"); m() -> foo::Bar

In the first example we bind m to Str.upper with an explicit target - the string "hello". So we call m without any arguments. However in the second example we bind the same Str.upper method without specifying a target. So the target must be explicitly passed as the first argument. In the last two examples we bind a static method - without any arguments, and with an argument. Given a static method with n parameters, we can bind 0 to n arguments. Given an instance method we can bind 0 to n+1 arguments (with the first argument being the implicit this).

To use our examples above:

x.times(&echo("hello"))   
  // print "hello" three times on the console

["a", "b"].collect(&Str.upper) -> ["A", "B"]  
  // we ignore collect's 2nd arg - see below

Closures

Of course what we really want to enable is an elegant syntax for closures so that we can build functional style libraries for working with collections and resources like files/streams. I haven't really seen anything I like better than the Ruby-style syntax: {|arg1, arg2, ...| ...}.

The arguments may be explicitly typed such as {|Str s| ...} or may be implied such as {|s| ...}. In the case of the an implied type, the type is defined by the method ref it is bound to (not sure about this - we will need to see how it works). A closure with n arguments may be bound to a callback that provides n or more parameters (the extra parameters are ignored). For example I can bind a closure to List.each with 0, 1, or 2 arguments. But I cannot bind a closure with 3 or more arguments to List.each (since I only have 2 parameters). I think the same rules apply to method binding.

Like Ruby, a closure may be used inline as an expression or if a method's last parameter is a closure, it may be specified outside the method call:

Let's repeat the examples above using a closure:

// inside the method call
x.times( { echo("hello") } )
strings.collect( {|Str s| return s.upper} )

// outside the method call
x.times { echo("hello") }
strings.collect {|s| return s.upper}

// multi-line convention
x.times
{
  echo("hello")
}

strings.collect
{
  |Str s, Int i|
  return s.upper
}

Anyways, these are just my initial thoughts. We have a really long way to go before we can turn this into a coherent design.

Login or Signup to reply.