Partial function application

From Rosetta Code
Revision as of 02:50, 5 April 2011 by 80.180.220.94 (talk) (Added D version)
Partial function application is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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 explicitely 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 retuns 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.

D

This is just an approximation of the required task: <lang d>import std.stdio, std.algorithm, std.range;

template fs(alias f) {

   auto fs(Range)(Range s) {
       return map!f(s);
   }

}

auto f1(T)(T x) { return x * 2; } auto f2(T)(T x) { return x * x; }

void main() {

   alias fs!f1 fsf1;
   alias fs!f2 fsf2;
   auto d1 = iota(0, 4);
   writeln(fsf1(d1));
   writeln(fsf2(d1));
   auto d2 = iota(2, 9, 2);
   writeln(fsf1(d2));
   writeln(fsf2(d2));

}</lang> Output:

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

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>

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>

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.

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>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 def fsf1(s); fs(s, &method(:f1)); end def fsf2(s); fs(s, &method(:f2)); end

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

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

end</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