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)returnsf'(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.
Contents |
[edit] Ada
Ada allows to define generic functions with generic parameters, which are partially applicable.
with Ada.Text_IO;
procedure Partial_Function_Application is
type Sequence is array(Positive range <>) of Integer;
-- declare a function FS with a generic parameter F and a normal parameter S
generic
with function F(I: Integer) return Integer; -- generic parameter
function FS (S: Sequence) return Sequence;
-- define FS
function FS (S: Sequence) return Sequence is
Result: Sequence(S'First .. S'Last);
begin
for Idx in S'Range loop
Result(Idx) := F(S(Idx));
end loop;
return Result;
end FS;
-- define functions F1 and F2
function F1(I: Integer) return Integer is
begin
return 2*I;
end F1;
function F2(I: Integer) return Integer is
begin
return I**2;
end F2;
-- instantiate the function FS by F1 and F2 (partially apply F1 and F2 to FS)
function FSF1 is new FS(F1);
function FSF2 is new FS(F2);
procedure Print(S: Sequence) is
begin
for Idx in S'Range loop
Ada.Text_IO.Put(Integer'Image(S(Idx)));
end loop;
Ada.Text_IO.New_Line;
end Print;
begin
Print(FSF1((0,1,2,3)));
Print(FSF2((0,1,2,3)));
Print(FSF1((2,4,6,8)));
Print(FSF2((2,4,6,8)));
end Partial_Function_Application;
Output:
0 2 4 6 0 1 4 9 4 8 12 16 4 16 36 64
[edit] ALGOL 68
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) #
Output:
(0, 2, 4, 6) (0, 1, 4, 9) (4, 8, 12, 16) (4, 16, 36, 64)
[edit] BBC BASIC
fsf1 = FNpartial(PROCfs(), FNf1())
fsf2 = FNpartial(PROCfs(), FNf2())
DIM seq(3)
PRINT "Calling function fsf1 with sequence 1:"
seq() = 0, 1, 2, 3 : PROC(fsf1)(seq())
FOR i% = 0 TO 3 : PRINT seq(i%); : NEXT : PRINT
PRINT "Calling function fsf1 with sequence 2:"
seq() = 2, 4, 6, 8 : PROC(fsf1)(seq())
FOR i% = 0 TO 3 : PRINT seq(i%); : NEXT : PRINT
PRINT "Calling function fsf2 with sequence 1:"
seq() = 0, 1, 2, 3 : PROC(fsf2)(seq())
FOR i% = 0 TO 3 : PRINT seq(i%); : NEXT : PRINT
PRINT "Calling function fsf2 with sequence 2:"
seq() = 2, 4, 6, 8 : PROC(fsf2)(seq())
FOR i% = 0 TO 3 : PRINT seq(i%); : NEXT : PRINT
END
REM Create a partial function:
DEF FNpartial(RETURN f1%, RETURN f2%)
LOCAL f$, p%
DIM p% 7 : p%!0 = f1% : p%!4 = f2%
f$ = "(s())" + CHR$&F2 + "(&" + STR$~p% + ")(" + \
\ CHR$&A4 + "(&" + STR$~(p%+4) + ")(),s()):" + CHR$&E1
DIM p% LEN(f$) + 4
$(p%+4) = f$ : !p% = p%+4
= p%
REM Replaces the input sequence with the output sequence:
DEF PROCfs(RETURN f%, seq())
LOCAL i%
FOR i% = 0 TO DIM(seq(),1)
seq(i%) = FN(^f%)(seq(i%))
NEXT
ENDPROC
DEF FNf1(n) = n * 2
DEF FNf2(n) = n ^ 2
Output:
Calling function fsf1 with sequence 1:
0 2 4 6
Calling function fsf1 with sequence 2:
4 8 12 16
Calling function fsf2 with sequence 1:
0 1 4 9
Calling function fsf2 with sequence 2:
4 16 36 64
[edit] 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)))
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)
[edit] Common Lisp
(defun fs (f s) (mapcar f s))Output:
(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)))
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)
[edit] C
Nasty hack, but the partial does return a true C function pointer, which is otherwise hard to achieve. (In case you are wondering, no, this is not a good or serious solution.) Compiled with gcc -Wall -ldl.
#include <stdio.h>output
#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/wait.h>
#include <err.h>
typedef int (*intfunc)(int);
typedef void (*pfunc)(int*, int);
pfunc partial(intfunc fin)
{
pfunc f;
static int idx = 0;
char cc[256], lib[256];
FILE *fp;
sprintf(lib, "/tmp/stuff%d.so", ++idx);
sprintf(cc, "cc -pipe -x c -shared -o %s -", lib);
fp = popen(cc, "w");
fprintf(fp, "#define t typedef\xat int _i,*i;t _i(*__)(_i);__ p =(__)%p;"
"void _(i _1, _i l){while(--l>-1)l[_1]=p(l[_1]);}", fin);
fclose(fp);
*(void **)(&f) = dlsym(dlopen(lib, RTLD_LAZY), "_");
unlink(lib);
return f;
}
int square(int a)
{
return a * a;
}
int dbl(int a)
{
return a + a;
}
int main()
{
int x[] = { 1, 2, 3, 4 };
int y[] = { 1, 2, 3, 4 };
int i;
pfunc f = partial(square);
pfunc g = partial(dbl);
printf("partial square:\n");
f(x, 4);
for (i = 0; i < 4; i++) printf("%d\n", x[i]);
printf("partial double:\n");
g(y, 4);
for (i = 0; i < 4; i++) printf("%d\n", y[i]);
return 0;
}
partial square:
1
4
9
16
partial double:
2
4
6
8
[edit] C++
#include <utility> // For declval.
#include <algorithm>
#include <array>
#include <iterator>
#include <iostream>
/* Partial application helper. */
template< class F, class Arg >
struct PApply
{
F f;
Arg arg;
tempalte< class F_, class Arg_ >
PApply( F_&& f, Arg_&& arg )
: f(std::forward<F_>(f)), arg(std::forward<Arg_>(arg))
{
}
/*
* The return type of F only gets deduced based on the number of arguments
* supplied. PApply otherwise has no idea whether f takes 1 or 10 args.
*/
template< class ... Args >
auto operator() ( Args&& ...args )
-> decltype( f(arg,std::declval<Args>()...) )
{
return f( arg, std::forward<Args>(args)... );
}
};
template< class F, class Arg >
PApply<F,Arg> papply( F&& f, Arg&& arg )
{
return PApply<F,Arg>( std::forward<F>(f), std::forward<Arg>(arg) );
}
/* Apply f to cont. */
template< class F >
std::array<int,4> fs( F&& f, std::array<int,4> cont )
{
std::transform( std::begin(cont), std::end(cont), std::begin(cont),
std::forward<F>(f) );
return cont;
}
std::ostream& operator << ( std::ostream& out, const std::array<int,4>& c )
{
std::copy( std::begin(c), std::end(c),
std::ostream_iterator<int>(out, ", ") );
return out;
}
int f1( int x ) { return x * 2; }
int f2( int x ) { return x * x; }
int main()
{
std::array<int,4> xs = {{ 0, 1, 2, 3 }};
std::array<int,4> ys = {{ 2, 4, 6, 8 }};
auto fsf1 = papply( fs<decltype(f1)>, f1 );
auto fsf2 = papply( fs<decltype(f2)>, f2 );
std::cout << "xs:\n"
<< "\tfsf1: " << fsf1(xs) << '\n'
<< "\tfsf2: " << fsf2(xs) << "\n\n"
<< "ys:\n"
<< "\tfsf1: " << fsf1(ys) << '\n'
<< "\tfsf2: " << fsf2(ys) << '\n';
}
[edit] C#
using System;
using System.Collections.Generic;
using System.Linq;
class PartialFunctionApplication
{
static Func<T1, TResult> PartiallyApply<T1, T2, TResult>(Func<T1, T2, TResult> function, T2 argument2)
{
return argument1 => function(argument1, argument2);
}
static void Main()
{
var fs = (Func<IEnumerable<int>, Func<int, int>, IEnumerable<int>>)Enumerable.Select;
var f1 = (Func<int, int>)(n => n * 2);
var f2 = (Func<int, int>)(n => n * n);
var fsf1 = PartiallyApply(fs, f1);
var fsf2 = PartiallyApply(fs, f2);
var s = new[] { 0, 1, 2, 3 };
Console.WriteLine(string.Join(", ", fsf1(s)));
Console.WriteLine(string.Join(", ", fsf2(s)));
s = new[] { 2, 4, 6, 8 };
Console.WriteLine(string.Join(", ", fsf1(s)));
Console.WriteLine(string.Join(", ", fsf2(s)));
}
}
Output:
0, 2, 4, 6 0, 1, 4, 9 4, 8, 12, 16 4, 16, 36, 64
[edit] CoffeeScript
partial = (f, g) ->
(s) -> f(g, s)
fs = (f, s) -> (f(a) for a in s)
f1 = (a) -> a * 2
f2 = (a) -> a * a
fsf1 = partial(fs, f1)
fsf2 = partial(fs, f2)
do ->
for seq in [[0..3], [2,4,6,8]]
console.log fsf1 seq
console.log fsf2 seq
output
> coffee partials.coffee
[ 0, 2, 4, 6 ]
[ 0, 1, 4, 9 ]
[ 4, 8, 12, 16 ]
[ 4, 16, 36, 64 ]
[edit] 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.
import std.stdio, std.algorithm, std.traits;
auto fs(alias f)(in int[] s) /*pure nothrow*/
if (isCallable!f && ParameterTypeTuple!f.length == 1) {
return map!f(s);
}
int f1(in int x) pure nothrow { return x * 2; }
int f2(in int x) pure nothrow { return x ^^ 2; }
alias fs!f1 fsf1;
alias fs!f2 fsf2;
void main() {
foreach (d; [[0, 1, 2, 3], [2, 4, 6, 8]]) {
writeln(fsf1(d));
writeln(fsf2(d));
}
}
Output:
[0, 2, 4, 6] [0, 1, 4, 9] [4, 8, 12, 16] [4, 16, 36, 64]
[edit] 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))
}
}
[edit] 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 all of its arguments will simply return a function that takes the remaining arguments.
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]
[edit] Icon and Unicon
link printf
procedure main()
fsf1 := partial(fs,f1)
fsf2 := partial(fs,f2)
every s := [ 0, 1, 2, 3 ] |
[ 2, 4, 6, 8 ] do {
printf("\ns := %s\n",list2string(s))
printf("fsf1(s) := %s\n",list2string(fsf1(s)))
printf("fsf2(s) := %s\n",list2string(fsf2(s)))
}
end
procedure partial(f,g) #: partial application of f & g
@( p := create repeat {
s := (r@&source)[1] # return r / get argument s
r := f(g,s) # apply f(g,...)
}
) # create and activate procedure p
return p
end
procedure fs(f,s) #: return list where f is applied to each element of s
every put(r := [], f(!s))
return r
end
procedure f1(n) # double
return n * 2
end
procedure f2(n) #: square
return n ^ 2
end
procedure list2string(L) #: format list as a string
every (s := "[ ") ||:= !L || " "
return s || "]"
end
printf.icn provides formatting
Output:s := [ 0 1 2 3 ] fsf1(s) := [ 0 2 4 6 ] fsf2(s) := [ 0 1 4 9 ] s := [ 2 4 6 8 ] fsf1(s) := [ 4 8 12 16 ] fsf2(s) := [ 4 16 36 64 ]
[edit] J
Given:
fs=:1 :'u"0 y'
f1=:*&2
f2=:^&2
fsf1=:f1 fs
fsf2=:f2 fs
The required examples might look like this:
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
That said, note that much of this is unnecessary, since f1 and f2 already work the same way on list arguments.
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
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:
crippled=:1 :0
assert.1=#y
u y
)
F1=: f1 crippled
F2=: f2 crippled
fsF1=: F1 fs
fsF2=: F2 fs
the system behaves like this:
F1 i.4
|assertion failure: F1
| 1=#y
fsF1 i.4
0 2 4 6
NB. and so on...
[edit] 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.
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)));
}
}
}
The aforementioned code, lambda-ized in Java 8.
import java.util.Arrays;Compilation and output for both versions:
import java.util.function.Function;
public class PartialApplication {
// Original method fs(f, s).
static Integer[] fs(Function<Integer, Integer> f, Integer[] s) {
Integer[] r = new Integer[s.length];
for (int i = 0; i < s.length; i++)
r[i] = f.apply(s[i]);
return r;
}
// Curried method fs(f).apply(s),
// necessary for partial application.
static Function<Integer[], Integer[]> fs(Function<Integer, Integer> f) {
return s -> fs(f, s);
}
static Function<Integer, Integer> f1 = i -> i * 2;
static Function<Integer, Integer> f2 = i -> i * i;
static Function<Integer[], Integer[]> fsf1 = fs(f1); // Partial application.
static Function<Integer[], Integer[]> fsf2 = fs(f2);
public static void main(String[] args) {
Integer[][] sequences = {
{ 0, 1, 2, 3 },
{ 2, 4, 6, 8 },
};
for (Integer[] array : sequences) {
System.out.printf(
"array: %s\n" +
" fsf1(array): %s\n" +
" fsf2(array): %s\n",
Arrays.toString(array),
Arrays.toString(fsf1.apply(array)),
Arrays.toString(fsf2.apply(array)));
}
}
}
$ 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]
[edit] Mathematica
fs[f_, s_] := Map[f, s]
f1 [n_] := n*2
f2 [n_] := n^2
fsf1[s_] := fs[f1, s]
fsf2[s_] := fs[f2, s]
Example usage:
fsf1[{0, 1, 2, 3}]
->{0, 2, 4, 6}
fsf2[{0, 1, 2, 3}]
->{0, 1, 4, 9}
fsf1[{2, 4, 6, 8}]
->{4, 8, 12, 16}
fsf2[{2, 4, 6, 8}]
->{4, 16, 36, 64}
[edit] Mercury
:- module partial_function_application.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module int, list.
main(!IO) :-
io.write((fsf1)([0, 1, 2, 3]), !IO), io.nl(!IO),
io.write((fsf2)([0, 1, 2, 3]), !IO), io.nl(!IO),
io.write((fsf1)([2, 4, 6, 8]), !IO), io.nl(!IO),
io.write((fsf2)([2, 4, 6, 8]), !IO), io.nl(!IO).
:- func fs(func(V) = V, list(V)) = list(V).
fs(_, []) = [].
fs(F, [V | Vs]) = [F(V) | fs(F, Vs)].
:- func f1(int) = int.
f1(V) = V * 2.
:- func f2(int) = int.
f2(V) = V * V.
:- func fsf1 = (func(list(int)) = list(int)).
fsf1 = fs(f1).
:- func fsf2 = (func(list(int)) = list(int)).
fsf2 = fs(f2).
[edit] Nemerle
using System;
using System.Console;
module Partial
{
fs[T] (f : T -> T, s : list[T]) : list[T]
{
$[f(x)| x in s]
}
f1 (x : int) : int
{
x * 2
}
f2 (x : int) : int
{
x * x
}
curry[T, U, V] (f : T * U -> V, x : T) : U -> V
{
f(x, _)
}
// curryr() isn't actually used in this task, I just include it for symmetry
curryr[T, U, V] (f : T * U -> V, x : U) : T -> V
{
f(_, x)
}
Main() : void
{
def fsf1 = curry(fs, f1);
def fsf2 = curry(fs, f2);
def test1 = $[0 .. 3];
def test2 = $[x | x in [2 .. 8], x % 2 == 0];
WriteLine (fsf1(test1));
WriteLine (fsf1(test2));
WriteLine (fsf2(test1));
WriteLine (fsf2(test2));
}
}
[edit] 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 all of its arguments will simply return a function that takes the remaining arguments.
#
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]
[edit] Order
Much like Haskell and ML, not giving a multi-argument function all of its arguments returns a function that will accept the rest.
#include <order/interpreter.h>
#define ORDER_PP_DEF_8fs ORDER_PP_FN( 8fn(8F, 8S, 8seq_map(8F, 8S)) )
#define ORDER_PP_DEF_8f1 ORDER_PP_FN( 8fn(8V, 8times(8V, 2)) )
#define ORDER_PP_DEF_8f2 ORDER_PP_FN( 8fn(8V, 8times(8V, 8V)) )
ORDER_PP(
8let((8F, 8fs(8f1))
(8G, 8fs(8f2)),
8do(
8print(8ap(8F, 8seq(0, 1, 2, 3)) 8comma 8space),
8print(8ap(8G, 8seq(0, 1, 2, 3)) 8comma 8space),
8print(8ap(8F, 8seq(2, 4, 6, 8)) 8comma 8space),
8print(8ap(8G, 8seq(2, 4, 6, 8))))) )
- Output:
(0)(2)(4)(6), (0)(1)(4)(9), (4)(8)(12)(16), (4)(16)(36)(64)
This example highlights two related syntactic limitations: only a statically-defined function (using #define ORDER_PP_DEF_ etc.) can have a multi-character name, so variables - i.e. the result of expressions - are limited to 8A-8Z; and similarly only statically-defined functions can be applied using the C-like 8name(args) syntax: variables or expression results must be applied using the 8ap operator (which is semantically identical, but not quite as pretty).
[edit] 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.
sub fs(&) {Output:
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";
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
[edit] Perl 6
All Code objects have the .assuming method, which partially applies its arguments. For both type safety reasons and parsing sanity reasons we do not believe in implicit partial application by leaving out arguments. Also, people can understand "assuming" without being steeped in FP culture.
sub fs ( Code $f, @s ) { @s.map: { .$f } }Output:
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);
}
2 4 6 1 4 9 4 8 12 16 4 16 36 64
Here we partially apply the function using named arguments, but positional notation is also supported. (Named arguments are more general in the sense that they do not require you to curry your arguments from left-to-right.)
The *+2 is also a form of partial application in Perl 6. In this case we partially apply the infix:<+> function with a second argument of 2. That is, the star (known as the "whatever" star) indicates which argument not to apply. The explicit star allows us to avoid syntactic ambiguity in whether to expect a term or an infix operator; such self-clocking code contributes to better error messages when things go wrong.
[edit] 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)) )
Output:
(0 2 4 6) (0 1 4 9) (4 8 12 16) (4 16 36 64)
[edit] Prolog
Works with SWI-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]).
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.
[edit] 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]
The program runs without triggering the assertions.
Explicitly spelling out the partial function without hiding behind a library:def partial(f, g):
def fg(*x): return f(g, *x)
return fg
def fs(f, *x): return [ f(a) for a in x]
def f1(a): return a * 2
def f2(a): return a * a
fsf1 = partial(fs, f1)
fsf2 = partial(fs, f2)
print fsf1(1, 2, 3, 4)
print fsf2(1, 2, 3, 4)
[edit] 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))
[edit] Racket
#lang racket
(define (fs f s) (map f s))
(define (f1 n) (* n 2))
(define (f2 n) (* n n))
(define fsf1 (curry fs f1))
(define fsf2 (curry fs f2))
(fsf1 '(0 1 2 3))
(fsf1 '(2 4 6 8))
(fsf2 '(0 1 2 3))
(fsf2 '(2 4 6 8))
[edit] Ruby
Proc#curry is a new method from Ruby 1.9. A curried proc applies its arguments to the first parameters of the original proc. In this example, fs.curry[f1][e] is a call to fs[f1, e], so fs.curry[f1] is a partial application.
fs = proc { |f, s| s.map &f }
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]
p fsf2[e]
end
Output
[0, 2, 4, 6] [0, 1, 4, 9] [4, 8, 12, 16] [4, 16, 36, 64]
[edit] 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.
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)))
[edit] Smalltalk
| f1 f2 fs fsf1 fsf2 partial |
partial := [ :afs :af | [ :s | afs value: af value: s ] ].
fs := [ :f :s | s collect: [ :x | f value: x ]].
f1 := [ :x | x * 2 ].
f2:= [ :x | x * x ].
fsf1 := partial value: fs value: f1.
fsf2 := partial value: fs value: f2.
fsf1 value: (0 to: 3).
" #(0 2 4 6)"
fsf2 value: (0 to: 3).
" #(0 1 4 9)"
fsf1 value: #(2 4 6 8).
" #(4 8 12 16)"
fsf2 value: #(2 4 6 8).
" #(4 16 36 64)"
[edit] 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
}
Demonstration:
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]"
}
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