Perl 6 - The Many Faces & Features of Functions

***Update: Carl Mäsak (@carlmasak) corrected some misunderstandings I had regarding the scoping of subroutines and the use of export.***

When I first announced the Functional Perl series on the STL-PM Bill Odom asked if I would be including Perl 6.  I declined at the time stating that there were sufficient difference between Perl 6 and Perl 5 to make the articles too busy.  There aren't a huge amount of differences, but I didn't want to clutter a Perl 5 article with things like method.assuming( x=> 11) or leave it out of a Perl 6 article.  This article isn't an article about functional programming, but it is a talk about functions in Perl 6 so that I can later do functional articles.

Named Functions

Perl 6 sports an incredible amount of power and flexibility without losing a bit of the flexibility one can find in Perl 5.  In fact, one could write a Perl 6 subroutine that looked like this:

Or like this, which gives us type checking:

But constraint checking can even move beyond basic type checking.  Perl 6 can can provide further constraint checking with a where clause on a parameter:

This version only allows us to give interest rates that will increase the future value.  

Perl 6 also allows for functions to be able to declare through traits:

  • if they are safe to automatically cache
  • the precedence (if it is for an operator)
  • tons of other stuff

Additionally, explicitly stating all the implicit traits on a method can make it very verbose, like AppleScript verbose.

Anonymous Functions

 

The Perl 5 way of creating anonymous functions is still valid in Perl6.  However, you now use the method invocation operator ('.') instead of the '->' available in Perl 5.  You can actually skip the method invocation operator since it can be implicit in this case.  So, for example, you can make and use an anonymous subroutine like this:

 

Perl 6 also provides for a lot of new approaches towards creating and using anonymous functions.  In fact, according to Synopsis 4, every block is a closure.  so, for example, you can now write an anonymous function simply by doing this:

If you wish to include a parameter list you can do so with a slightly modified version of that called the "pointy block":

Additionally, If you read my post on Perl 6's Whatever then you already know that you can use Whatever in a statement to close over that statement and create a function to evaluate it later.

A Bump in the Road: Scope

The move isn't completely roses for function happy developers though, there is one little hiccup you might encounter.  This code, which uses a hash as a cache that's closed over in the subroutine will be a little different than the Perl 5 version:

That is because subroutines are now also scoped and are implicitly given the same scope as provided by 'my'.  This is a simple matter though, we simply give the subroutine the 'our' scope.  Here is the equivalent example in Perl 6:

A Tangent: Control Structures

This is a bit of a tangent, but I find it interesting.  Do you remember when I said that any block is a closure?  That counts for things you probably didn't consider, things like the blocks on if, while, and for statements.  These are all now closures too.  In fact, Perl 6 allows us to iterate over lists n-at-a-time because of this.  The for loop will now pass us as many values as we provide as parameters in our block. Here is an example:

Of course, this example will complain when we reach 100, so we can do this:

The above example allows us to pass in 1-3 parameters, as many as are available.  In this case though Mu is assigned to values that aren't passed in, which stringifies to "Mu()".  We probably don't want that, so we'll just use defaults:

Summary

Perl 6 gives functions, named or otherwise, a wide variety of new syntactic features.  It also really promotes the role of closures and anonymous functions, which is a welcome addition.  Perl 6 is also bakes in new features, like memoization and currying.

Given all of that, I hope people understand why I'll be trying to keep Perl 5 and Perl 6 articles apart.

Further Reading

Week 1: The Lambda Function

***UPDATE:  I modified the final example with Naveed's (@ironcamel) suggestion, it looks much nicer now.***

***UPDATE: Christopher Bottom caught some vestigial lines of code in the final example, which I have removed.***

The Lambda Function is the building block of all functional programming.  It is also referred to as an anonymous function or sometimes in Perl as an anonymous subroutine.  Perl treats subroutines as first class data types.  Because of this it is incredibly simple to create, store, and invoke anonymous subroutines.  To create an anonymous subroutine you simply use the 'sub' keyword without putting a name between the keyword and the body.  For example:

Is an example of an anonymous subroutine.  Obviously it isn't very useful though.  To make this useful we need to store the reference of that anonymous subroutine in a variable:

Now that we have an anonymous subroutine referenced by the $hello variable we can access it by dereferencing and calling it like so:

Anonymous subroutines are just like normal subroutines.  Because of this you can pass parameters in to them.  Passed in parameters are provided in @_ just like in a normal subroutine.  If an anonymous subroutine exists within a larger subroutine then both will have their own @_ within their scope and you won't have to worry about them intermingling.



Without dereferencing and calling it you are simply referring to the variable itself, which you can pass around.  In fact, because these subroutine references are first class they can be treated the same as any other value.  This means that you can store subroutine references in arrays and in hashes (as both the key or the value), and that you can pass it along in subroutines.


This concludes this week's installment in Functional Perl.  Next week will cover the next building block, closures.