Partial function application

From Rosetta Code
Revision as of 00:56, 15 June 2011 by Util (talk | contribs) (→‎{{header|Perl 6}}: Added Perl 6 solution)
Task
Partial function application
You are encouraged to solve this task according to the task description, using any language you may know.

Partial function application is the ability to take a function of many parameters and apply arguments to some of the parameters to create a new function that needs only the application of the remaining arguments to produce the equivalent of applying all arguments to the original function.

E.g:

Given values v1, v2
Given f(param1, param2)
Then partial(f, param1=v1) returns f'(param2)
And f(param1=v1, param2=v2) == f'(param2=v2) (for any value v2)

Note that in the partial application of a parameter, (in the above case param1), other parameters are not explicitly mentioned. This is a recurring feature of partial function application.

Task
  • Create a function fs( f, s ) that takes a function, f( n ), of one value and a sequence of values s.
    Function fs should return an ordered sequence of the result of applying function f to every value of s in turn.
  • Create function f1 that takes a value and returns it multiplied by 2.
  • Create function f2 that takes a value and returns it squared.
  • Partially apply f1 to fs to form function fsf1( s )
  • Partially apply f2 to fs to form function fsf2( s )
  • Test fsf1 and fsf2 by evaluating them with s being the sequence of integers from 0 to 3 inclusive and then the sequence of even integers from 2 to 8 inclusive.
Notes
  • In partially applying the functions f1 or f2 to fs, there should be no explicit mention of any other parameters to fs, although introspection of fs within the partial applicator to find its parameters is allowed.
  • This task is more about how results are generated rather than just getting results.

ALGOL 68

Translation of: Python
Works with: ALGOL 68 version Revision 1 - Requires Currying extensions to language.
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny.

<lang algol68>MODE SET = FLEX[0]INT;

MODE F = PROC(INT)INT,

    FS = PROC(SET)SET;

PROC fs = (F f, SET set)SET: (

 [LWB set:UPB set]INT out;
 FOR i FROM LWB set TO UPB set DO out[i]:=f(set[i]) OD;
 out

);

PROC f1 = (INT value)INT: value * 2,

    f2 = (INT value)INT: value ** 2;

FS fsf1 = fs(f1,),

  fsf2 = fs(f2,);

[4]INT set; FORMAT set fmt = $"("n(UPB set-LWB set)(g(0)", ")g(0)")"l$;

set := (0, 1, 2, 3);

 printf((set fmt, fsf1((0, 1, 2, 3)))); # prints (0, 2, 4, 6) #
 printf((set fmt, fsf2((0, 1, 2, 3)))); # prints (0, 1, 4, 9) #

set := (2, 4, 6, 8);

 printf((set fmt, fsf1((2, 4, 6, 8)))); # prints (4, 8, 12, 16) #
 printf((set fmt, fsf2((2, 4, 6, 8))))  # prints (4, 16, 36, 64) #

</lang> Output:

(0, 2, 4, 6)
(0, 1, 4, 9)
(4, 8, 12, 16)
(4, 16, 36, 64)

Clojure

<lang Clojure>(defn fs [f s] (map f s))

(defn f1 [x] (* 2 x))

(defn f2 [x] (* x x))

(def fsf1 (partial fs f1))

(def fsf2 (partial fs f2))

(doseq [s [(range 4) (range 2 9 2)]]

 (println "seq: " s)
 (println "  fsf1: " (fsf1 s))
 (println "  fsf2: " (fsf2 s)))</lang>

Output:

seq:  (0 1 2 3)
  fsf1:  (0 2 4 6)
  fsf2:  (0 1 4 9)
seq:  (2 4 6 8)
  fsf1:  (4 8 12 16)
  fsf2:  (4 16 36 64)

Common Lisp

<lang lisp>(defun fs (f s) (mapcar f s)) (defun f1 (i) (* i 2)) (defun f2 (i) (expt i 2))

(defun partial (func &rest args1)

 (lambda (&rest args2) (apply func (append args1 args2))))

(defvar fsf1 (partial #'fs #'f1)) (defvar fsf2 (partial #'fs #'f2))

(dolist (seq '((0 1 2 3) (2 4 6 8)))

 (format t "~%seq: ~A~%  fsf1 seq: ~A~%  fsf2 seq: ~A"

seq (funcall fsf1 seq) (funcall fsf2 seq)))</lang>

Output:

seq: (0 1 2 3)
  fsf1 seq: (0 2 4 6)
  fsf2 seq: (0 1 4 9)
seq: (2 4 6 8)
  fsf1 seq: (4 8 12 16)
  fsf2 seq: (4 16 36 64)

D

fs has a static template argument f and the runtime argument s. The template constraints of fs statically require f to be a callable with just one argument, as requested by the task. <lang d>import std.stdio, std.algorithm, std.traits;

auto fs(alias f)(int[] s) if (isCallable!f && ParameterTypeTuple!f.length == 1) {

   return map!f(s);

}

int f1(int x) { return x * 2; } int f2(int x) { return x * x; }

alias fs!f1 fsf1; alias fs!f2 fsf2;

void main() {

   auto d1 = [0, 1, 2, 3];
   writeln(fsf1(d1));
   writeln(fsf2(d1));
   auto d2 = [2, 4, 6, 8];
   writeln(fsf1(d2));
   writeln(fsf2(d2));

}</lang> Output:

[0, 2, 4, 6]
[0, 1, 4, 9]
[4, 8, 12, 16]
[4, 16, 36, 64]

E

<lang e>def pa(f, args1) {

 return def partial {
   match [`run`, args2] {
     E.call(f, "run", args1 + args2)
   }
 }

}

def fs(f, s) {

 var r := []
 for n in s {
   r with= f(n)
 }
 return r

}

def f1(n) { return n * 2 } def f2(n) { return n ** 2 }

def fsf1 := pa(fs, [f1]) def fsf2 := pa(fs, [f2]) for s in [0..3, [2, 4, 6, 8]] {

 for f in [fsf1, fsf2] {
   println(f(s))
 }

}</lang>

Haskell

Haskell functions are curried. i.e. All functions actually take exactly one argument. Functions of multiple arguments are simply functions that take the first argument, which returns another function to take the remaining arguments, etc. Therefore, partial function application is trivial. Not giving a multi-argument function will simply return a function that takes the remaining arguments. <lang haskell>fs f s = map f s f1 value = value * 2 f2 value = value ^ 2

fsf1 = fs f1 fsf2 = fs f2

main :: IO () main = do

 print $ fsf1 [0, 1, 2, 3] -- prints [0, 2, 4, 6]
 print $ fsf2 [0, 1, 2, 3] -- prints [0, 1, 4, 9]
 print $ fsf1 [2, 4, 6, 8] -- prints [4, 8, 12, 16]
 print $ fsf2 [2, 4, 6, 8] -- prints [4, 16, 36, 64]</lang>

J

Given:

<lang j>fs=:1 :'u"0 y' f1=:*&2 f2=:^&2 fsf1=:f1 fs fsf2=:f2 fs</lang>

The required examples might look like this:

<lang j> fsf1 i.4 0 2 4 6

  fsf2 i.4

0 1 4 9

  fsf1 fsf1 1+i.4

4 8 12 16

  fsf2 fsf1 1+i.4

4 16 36 64</lang>

That said, note that much of this is unnecessary, since f1 and f2 already work the same way on list arguments.

<lang j> f1 i.4 0 2 4 6

  f2 i.4

0 1 4 9

  f1 1+i.4

2 4 6 8

  f2 f1 1+i.4

4 16 36 64</lang>

That said, note that if we complicated the definitions of f1 and f2, so that they would not work on lists, the fs approach would still work:

In other words, given:

<lang j>crippled=:1 :0

 assert.1=#y
 u y

)

F1=: f1 crippled F2=: f2 crippled fsF1=: F1 fs fsF2=: F2 fs</lang>

the system behaves like this:

<lang j> F1 i.4 |assertion failure: F1 | 1=#y

  fsF1 i.4

0 2 4 6 NB. and so on...</lang>

Java

To solve this task, I wrote fs() as a curried method. I changed the syntax from fs(arg1, arg2) to fs(arg1).call(arg2). Now I can use fs(arg1) as partial application.

<lang java>import java.util.Arrays;

public class PartialApplication { interface IntegerFunction { int call(int arg); }

// Original method fs(f, s). static int[] fs(IntegerFunction f, int[] s) { int[] r = new int[s.length]; for (int i = 0; i < s.length; i++) r[i] = f.call(s[i]); return r; }

interface SequenceFunction { int[] call(int[] arg); }

// Curried method fs(f).call(s), // necessary for partial application. static SequenceFunction fs(final IntegerFunction f) { return new SequenceFunction() { public int[] call(int[] s) { // Call original method. return fs(f, s); } }; }

static IntegerFunction f1 = new IntegerFunction() { public int call(int i) { return i * 2; } };

static IntegerFunction f2 = new IntegerFunction() { public int call(int i) { return i * i; } };

static SequenceFunction fsf1 = fs(f1); // Partial application.

static SequenceFunction fsf2 = fs(f2);

public static void main(String[] args) { int[][] sequences = { { 0, 1, 2, 3 }, { 2, 4, 6, 8 }, };

for (int[] array : sequences) { System.out.printf( "array: %s\n" + " fsf1(array): %s\n" + " fsf2(array): %s\n", Arrays.toString(array), Arrays.toString(fsf1.call(array)), Arrays.toString(fsf2.call(array))); } } }</lang>

Compilation and output:

$ javac PartialApplication.java  
$ java PartialApplication                                                      
array: [0, 1, 2, 3]
  fsf1(array): [0, 2, 4, 6]
  fsf2(array): [0, 1, 4, 9]
array: [2, 4, 6, 8]
  fsf1(array): [4, 8, 12, 16]
  fsf2(array): [4, 16, 36, 64]

OCaml

OCaml functions are curried. i.e. All functions actually take exactly one argument. Functions of multiple arguments are simply functions that take the first argument, which returns another function to take the remaining arguments, etc. Therefore, partial function application is trivial. Not giving a multi-argument function will simply return a function that takes the remaining arguments. <lang ocaml># let fs f s = List.map f s let f1 value = value * 2 let f2 value = value * value

let fsf1 = fs f1 let fsf2 = fs f2

val fs : ('a -> 'b) -> 'a list -> 'b list = <fun> val f1 : int -> int = <fun> val f2 : int -> int = <fun> val fsf1 : int list -> int list = <fun> val fsf2 : int list -> int list = <fun>

  1. fsf1 [0; 1; 2; 3];;

- : int list = [0; 2; 4; 6]

  1. fsf2 [0; 1; 2; 3];;

- : int list = [0; 1; 4; 9]

  1. fsf1 [2; 4; 6; 8];;

- : int list = [4; 8; 12; 16]

  1. fsf2 [2; 4; 6; 8];;

- : int list = [4; 16; 36; 64]</lang>

Perl

Note: this is written according to my understanding of the task spec and the discussion page; it doesn't seem a concensus was reached regarding what counts as a "partial" yet. <lang Perl>sub fs(&) {

       my $func = shift;
       sub { map $func->($_), @_ }

}

sub double($) { shift() * 2 } sub square($) { shift() ** 2 }

my $fs_double = fs(\&double); my $fs_square = fs(\&square);

my @s = 0 .. 3; print "fs_double(@s): @{[ $fs_double->(@s) ]}\n"; print "fs_square(@s): @{[ $fs_square->(@s) ]}\n";

@s = (2, 4, 6, 8); print "fs_double(@s): @{[ $fs_double->(@s) ]}\n"; print "fs_square(@s): @{[ $fs_square->(@s) ]}\n";</lang>

Output:

fs_double(0 1 2 3): 0 2 4 6
fs_square(0 1 2 3): 0 1 4 9
fs_double(2 4 6 8): 4 8 12 16
fs_square(2 4 6 8): 4 16 36 64

Perl 6

All Code objects have the .assuming method, which curries its arguments. <lang perl6>sub fs ( Code $f, @s ) { @s.map: { .$f } }

sub f1 ( $n ) { $n * 2 } sub f2 ( $n ) { $n ** 2 }

my &fsf1 := &fs.assuming: f => &f1; my &fsf2 := &fs.assuming: f => &f2;

for [1..3], [2, *+2 ... 8] X &fsf1, &fsf2 -> $s, $f {

   say ~ $f.($s);

}</lang>

Output:

2 4 6
1 4 9
4 8 12 16
4 16 36 64

PicoLisp

<lang PicoLisp>(def 'fs mapcar) (de f1 (N) (* 2 N)) (de f2 (N) (* N N))

(de partial (F1 F2)

  (curry (F1 F2) @
     (pass F1 F2) ) )

(def 'fsf1 (partial fs f1)) (def 'fsf2 (partial fs f2))

(for S '((0 1 2 3) (2 4 6 8))

  (println (fsf1 S))
  (println (fsf2 S)) )</lang>

Output:

(0 2 4 6)
(0 1 4 9)
(4 8 12 16)
(4 16 36 64)

Prolog

Works with SWI-Prolog. <lang Prolog>fs(P, S, S1) :- maplist(P, S, S1).

f1(X, Y) :- Y is 2 * X.

f2(X, Y) :- Y is X * X.

create_partial(P, fs(P)).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fs :- % partial functions create_partial(f1, FSF1), create_partial(f2, FSF2),

S1 = [0,1,2,3], call(FSF1,S1, S11), format('~w : ~w ==> ~w~n',[FSF1, S1, S11]), call(FSF1,S1, S12), format('~w : ~w ==> ~w~n',[FSF2, S1, S12]),

S2 = [2,4,6,8], call(FSF1,S2, S21), format('~w : ~w ==> ~w~n',[FSF2, S2, S21]), call(FSF2,S2, S22), format('~w : ~w ==> ~w~n',[FSF1, S2, S22]). </lang> Output :

?- fs.
fs(f1) : [0,1,2,3] ==> [0,2,4,6]
fs(f2) : [0,1,2,3] ==> [0,1,4,9]
fs(f1) : [2,4,6,8] ==> [4,8,12,16]
fs(f2) : [2,4,6,8] ==> [4,16,36,64]
true.

Python

<lang python>from functools import partial

def fs(f, s): return [f(value) for value in s]

def f1(value): return value * 2

def f2(value): return value ** 2

fsf1 = partial(fs, f1) fsf2 = partial(fs, f2)

s = [0, 1, 2, 3] assert fs(f1, s) == fsf1(s) # == [0, 2, 4, 6] assert fs(f2, s) == fsf2(s) # == [0, 1, 4, 9]

s = [2, 4, 6, 8] assert fs(f1, s) == fsf1(s) # == [4, 8, 12, 16] assert fs(f2, s) == fsf2(s) # == [4, 16, 36, 64]</lang>

The program runs without triggering the assertions.

R

<lang R>partially.apply <- function(f, ...) {

 capture <- list(...)
 function(...) {
   do.call(f, c(capture, list(...)))
 }

}

fs <- function(f, ...) sapply(list(...), f) f1 <- function(x) 2*x f2 <- function(x) x^2

fsf1 <- partially.apply(fs, f1) fsf2 <- partially.apply(fs, f2)

fsf1(0:3) fsf2(0:3) fsf1(seq(2,8,2)) fsf2(seq(2,8,2))</lang>

Ruby

Proc#curry is a new method from Ruby 1.9 to curry a proc. A curried proc applies its arguments to the original proc. With enough arguments, the curried proc calls the original proc. With fewer arguments, the curried proc returns another curried proc that expects the rest of the arguments.

If fs is a proc, then fs.curry is a curried fs, and fs.curry[f1] is a proc that applies f1 as the first argument to fs.

Works with: Ruby version 1.9

<lang ruby>fs = proc { |f, s| Enumerator.new { |y| s.each { |n| y << f[n] }}} f1 = proc { |n| n * 2 } f2 = proc { |n| n ** 2 } fsf1 = fs.curry[f1] fsf2 = fs.curry[f2]

[0..3, (2..8).step(2)].each do |e|

 p fsf1[e].to_a
 p fsf2[e].to_a

end</lang>

This program outputs [0, 2, 4, 6], [0, 1, 4, 9], [4, 8, 12, 16], [4, 16, 36, 64].



Ruby programs often use methods which take a block parameter. One might write fs as such a method. (This would deviate from the original task, because such a method would be fs(s, &f), not fs(f, s).) Proc#curry would not work with such a method. The next example shows how fs, f1, f2, fsf1 and fsf2 can be all methods.

Works with: Ruby version 1.9

<lang ruby># Partially apply _block_ to _callable_. def with_block(callable, &block)

 proc { |*args| callable.call(*args, &block) }

end

def fs(s)

 Enumerator.new { |y| s.each { |n| y << (yield n) }}

end

def f1(n); n * 2; end def f2(n); n ** 2; end

class Object

 define_method :fsf1, &with_block(method(:fs), &method(:f1))
 define_method :fsf2, &with_block(method(:fs), &method(:f2))
 private :fsf1, :fsf2

end

[0..3, (2..8).step(2)].each do |e|

 p fsf1(e).to_a
 p fsf2(e).to_a

end</lang>

Scala

Scala does not have partial function application as defined, but comes close if we ignore the restriction that others parameters not be explicitely referred to. <lang scala>def fs(f:Int=>Int, s:List[Int])=s map f def f1(x:Int)=x*2 def f2(x:Int)=x*x

def fsf1=fs(f1,_:List[Int]) def fsf2=fs(f2,_:List[Int])

println(fsf1(List(0,1,2,3))) println(fsf1(List(2,4,6,8))) println(fsf2(List(0,1,2,3))) println(fsf2(List(2,4,6,8)))</lang>

Tcl

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6 proc partial {f1 f2} {

   variable ctr
   coroutine __curry[incr ctr] apply {{f1 f2} {

for {set x [info coroutine]} 1 {} { set x [{*}$f1 $f2 [yield $x]] }

   }} $f1 $f2

}</lang> Demonstration: <lang tcl>proc fs {f s} {

   set r {}
   foreach n $s {

lappend r [{*}$f $n]

   }
   return $r

} proc f1 x {expr {$x * 2}} proc f2 x {expr {$x ** 2}} set fsf1 [partial fs f1] set fsf2 [partial fs f2] foreach s {{0 1 2 3} {2 4 6 8}} {

   puts "$s ==f1==> [$fsf1 $s]"
   puts "$s ==f2==> [$fsf2 $s]"

}</lang> Output:

0 1 2 3 ==f1==> 0 2 4 6
0 1 2 3 ==f2==> 0 1 4 9
2 4 6 8 ==f1==> 4 8 12 16
2 4 6 8 ==f2==> 4 16 36 64