Partial function application: Difference between revisions

From Rosetta Code
Content added Content deleted
(added ocaml)
Line 44: Line 44:
fsf2 fsf1 1+i.4
fsf2 fsf1 1+i.4
4 16 36 64</lang>
4 16 36 64</lang>

=={{header|OCaml}}==
<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>

# fsf1 [0; 1; 2; 3];;
- : int list = [0; 2; 4; 6]
# fsf2 [0; 1; 2; 3];;
- : int list = [0; 1; 4; 9]
# fsf1 [2; 4; 6; 8];;
- : int list = [4; 8; 12; 16]
# fsf2 [2; 4; 6; 8];;
- : int list = [4; 16; 36; 64]</lang>


=={{header|Prolog}}==
=={{header|Prolog}}==

Revision as of 08:58, 1 April 2011

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.

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

<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