Categories
Posts in this category
- Introduction
- Strings, Arrays, Hashes;
- Types
- Basic Control Structures
- Subroutines and Signatures
- Objects and Classes
- Contexts
- Regexes (also called "rules")
- Junctions
- Comparing and Matching
- Containers and Values
- Where we are now - an update
- Changes to Perl 5 Operators
- Laziness
- Custom Operators
- The MAIN sub
- Twigils
- Enums
- Unicode
- Scoping
- Regexes strike back
- A grammar for (pseudo) XML
- Subset Types
- The State of the implementations
- Quoting and Parsing
- The Reduction Meta Operator
- The Cross Meta Operator
- Exceptions and control exceptions
- Common Perl 6 data processing idioms
- Currying
Sun, 25 Jul 2010
Currying
Permanent link
NAME
"Perl 5 to 6" Lesson 28 - Currying
SYNOPSIS
use v6;
my &f := &substr.assuming('Hello, World');
say f(0, 2); # He
say f(3, 2); # lo
say f(7); # World
say <a b c>.map: * x 2; # aabbcc
say <a b c>.map: *.uc; # ABC
for ^10 {
print <R G B>.[$_ % *]; # RGBRGBRGBR
}
DESCRIPTION
Currying or partial application is the process of generating a function from another function or method by providing only some of the arguments. This is useful for saving typing, and when you want to pass a callback to another function.
Suppose you want a function that lets you extract substrings from "Hello, World" easily. The classical way of doing that is writing your own function:
sub f(*@a) {
substr('Hello, World', |@a)
}
Currying with assuming
Perl 6 provides a method assuming on code objects, which applies the arguments passed to it to the invocant, and returns the partially applied function.
my &f := &substr.assuming('Hello, World');
Now f(1, 2) is the same as substr('Hello, World', 1, 2).
assuming also works on operators, because operators are just subroutines with weird names. To get a subroutine that adds 2 to whatever number gets passed to it, you could write
my &add_two := &infix:<+>.assuming(2);
But that's tedious to write, so there's another option.
Currying with the Whatever-Star
my &add_two := * + 2; say add_two(4); # 6
The asterisk, called Whatever, is a placeholder for an argument, so the whole expression returns a closure. Multiple Whatevers are allowed in a single expression, and create a closure that expects more arguments, by replacing each term * by a formal parameter. So * * 5 + * is equivalent to -> $a, $b { $a * 5 + $b }.
my $c = * * 5 + *; say $c(10, 2); # 52
Note that the second * is an infix operator, not a term, so it is not subject to Whatever-currying.
The process of lifting an expression with Whatever stars into a closure is driven by syntax, and done at compile time. This means that
my $star = *; my $code = $star + 2
does not construct a closure, but instead dies with a message like
Can't take numeric value for object of type Whatever
Whatever currying is more versatile than .assuming, because it allows to curry something else than the first argument very easily:
say ~(1, 3).map: 'hi' x * # hi hihihi
This curries the second argument of the string repetition operator infix x, so it returns a closure that, when called with a numeric argument, produces the string hi as often as that argument specifies.
The invocant of a method call can also be Whatever star, so
say <a b c>.map: *.uc; # ABC
involves a closure that calls the uc method on its argument.
MOTIVATION
Perl 5 could be used for functional programming, which has been demonstrated in Mark Jason Dominus' book Higher Order Perl.
Perl 6 strives to make it even easier, and thus provides tools to make typical constructs in functional programming easily available. Currying and easy construction of closures is a key to functional programming, and makes it very easy to write transformation for your data, for example together with map or grep.