Partial function application: Difference between revisions

Content added Content deleted
No edit summary
(Undo revision 190799 by Hernan (talk) Please don't change the formatting of every other example)
Line 251: Line 251:
(dolist (seq '((0 1 2 3) (2 4 6 8)))
(dolist (seq '((0 1 2 3) (2 4 6 8)))
(format t "~%seq: ~A~% fsf1 seq: ~A~% fsf2 seq: ~A"
(format t "~%seq: ~A~% fsf1 seq: ~A~% fsf2 seq: ~A"
seq (funcall fsf1 seq) (funcall fsf2 seq)))</lang>
seq (funcall fsf1 seq) (funcall fsf2 seq)))</lang>


Output: <pre>seq: (0 1 2 3)
Output: <pre>seq: (0 1 2 3)
Line 274: Line 274:
pfunc partial(intfunc fin)
pfunc partial(intfunc fin)
{
{
pfunc f;
pfunc f;
static int idx = 0;
static int idx = 0;
char cc[256], lib[256];
char cc[256], lib[256];
FILE *fp;
FILE *fp;
sprintf(lib, "/tmp/stuff%d.so", ++idx);
sprintf(lib, "/tmp/stuff%d.so", ++idx);
sprintf(cc, "cc -pipe -x c -shared -o %s -", lib);
sprintf(cc, "cc -pipe -x c -shared -o %s -", lib);


fp = popen(cc, "w");
fp = popen(cc, "w");
fprintf(fp, "#define t typedef\xat int _i,*i;t _i(*__)(_i);__ p =(__)%p;"
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);
"void _(i _1, _i l){while(--l>-1)l[_1]=p(l[_1]);}", fin);
fclose(fp);
fclose(fp);


*(void **)(&f) = dlsym(dlopen(lib, RTLD_LAZY), "_");
*(void **)(&f) = dlsym(dlopen(lib, RTLD_LAZY), "_");
unlink(lib);
unlink(lib);
return f;
return f;
}
}


int square(int a)
int square(int a)
{
{
return a * a;
return a * a;
}
}


int dbl(int a)
int dbl(int a)
{
{
return a + a;
return a + a;
}
}


int main()
int main()
{
{
int x[] = { 1, 2, 3, 4 };
int x[] = { 1, 2, 3, 4 };
int y[] = { 1, 2, 3, 4 };
int y[] = { 1, 2, 3, 4 };
int i;
int i;


pfunc f = partial(square);
pfunc f = partial(square);
pfunc g = partial(dbl);
pfunc g = partial(dbl);


printf("partial square:\n");
printf("partial square:\n");
f(x, 4);
f(x, 4);
for (i = 0; i < 4; i++) printf("%d\n", x[i]);
for (i = 0; i < 4; i++) printf("%d\n", x[i]);


printf("partial double:\n");
printf("partial double:\n");
g(y, 4);
g(y, 4);
for (i = 0; i < 4; i++) printf("%d\n", y[i]);
for (i = 0; i < 4; i++) printf("%d\n", y[i]);


return 0;
return 0;
}</lang>output<lang>partial square:
}</lang>output<lang>partial square:
1
1
Line 542: Line 542:
{4 8 12 16}
{4 8 12 16}
{4 16 36 64}
{4 16 36 64}
</lang>

=={{header|Erlang}}==

Partial applications can be built using the Erlang Meta Interpreter.

<lang erlang>
-module(partial_application).

-export([run/0]).

partial(F, Args) ->
{arity, InitialArity} = erlang:fun_info(F, arity),
case length(Args) of
L when L < InitialArity ->
MissingArgs = [{var, 1, N} || N <- lists:seq(1, InitialArity - L)],
ArgList = [case is_function(A) of
false -> erl_parse:abstract(A);
true -> {var, 1, erlang:fun_to_list(A)}
end || A <- Args] ++ MissingArgs,
Parsed = [{'fun', 1,
{clauses, [{clause, 1, MissingArgs, [],
[{call, 1, {var, 1, 'F'}, ArgList}]}]}}],
{value, R, _} = erl_eval:exprs(Parsed, [{'F', F}] ++
[{erlang:fun_to_list(A), A} ||
A <- Args, is_function(A)]),
R
end.

run() ->
F = partial(fun lists:map/2, [fun(X) -> X + 1 end]),
F([0, 1, 2, 3, 4]).
</lang>
'''Output:'''
<lang erlang>
> partial_application:run().
[1,2,3,4,5]
</lang>
</lang>


Line 641: Line 604:
// fs applies fn to each argument returning all results.
// fs applies fn to each argument returning all results.
func (f fn) fs(s ...int) (r []int) {
func (f fn) fs(s ...int) (r []int) {
for _, i := range s {
for _, i := range s {
r = append(r, f(i))
r = append(r, f(i))
}
}
return r
return r
}
}


Line 655: Line 618:
// addn returns a function that adds n to a sequence of numbers
// addn returns a function that adds n to a sequence of numbers
func addn(n int) func(...int) []int {
func addn(n int) func(...int) []int {
return func(s ...int) []int {
return func(s ...int) []int {
var r []int
var r []int
for _, i := range s {
for _, i := range s {
r = append(r, n+i)
r = append(r, n+i)
}
}
return r
return r
}
}
}
}


func main() {
func main() {
// Turning a method into a function bound to it's reciever:
// Turning a method into a function bound to it's reciever:
fsf1 := fn(f1).fs
fsf1 := fn(f1).fs
fsf2 := fn(f2).fs
fsf2 := fn(f2).fs
// Or using a function that returns a function:
// Or using a function that returns a function:
fsf3 := addn(100)
fsf3 := addn(100)


s := []int{0, 1, 2, 3}
s := []int{0, 1, 2, 3}
fmt.Println("For s =", s)
fmt.Println("For s =", s)
fmt.Println(" fsf1:", fsf1(s...)) // Called with a slice
fmt.Println(" fsf1:", fsf1(s...)) // Called with a slice
fmt.Println(" fsf2:", fsf2(0, 1, 2, 3)) // ... or with individual arguments
fmt.Println(" fsf2:", fsf2(0, 1, 2, 3)) // ... or with individual arguments
fmt.Println(" fsf3:", fsf3(0, 1, 2, 3))
fmt.Println(" fsf3:", fsf3(0, 1, 2, 3))
fmt.Println(" fsf2(fsf1):", fsf2(fsf1(s...)...))
fmt.Println(" fsf2(fsf1):", fsf2(fsf1(s...)...))


s = []int{2, 4, 6, 8}
s = []int{2, 4, 6, 8}
fmt.Println("For s =", s)
fmt.Println("For s =", s)
fmt.Println(" fsf1:", fsf1(2, 4, 6, 8))
fmt.Println(" fsf1:", fsf1(2, 4, 6, 8))
fmt.Println(" fsf2:", fsf2(s...))
fmt.Println(" fsf2:", fsf2(s...))
fmt.Println(" fsf3:", fsf3(s...))
fmt.Println(" fsf3:", fsf3(s...))
fmt.Println(" fsf3(fsf1):", fsf3(fsf1(s...)...))
fmt.Println(" fsf3(fsf1):", fsf3(fsf1(s...)...))
}</lang>
}</lang>
{{out}}
{{out}}
Line 843: Line 806:


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


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


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


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


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


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


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


static SequenceFunction fsf2 = fs(f2);
static SequenceFunction fsf2 = fs(f2);


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


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


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


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


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


create_partial(P, fs(P)).
create_partial(P, fs(P)).
Line 1,316: Line 1,279:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fs :-
fs :-
% partial functions
% partial functions
create_partial(f1, FSF1),
create_partial(f1, FSF1),
create_partial(f2, FSF2),
create_partial(f2, FSF2),


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


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


Explicitly spelling out the partial function without hiding behind a library:<lang Python>def partial(f, g):
Explicitly spelling out the partial function without hiding behind a library:<lang Python>def partial(f, g):
def fg(*x): return f(g, *x)
def fg(*x): return f(g, *x)
return fg
return fg


def fs(f, *x): return [ f(a) for a in x]
def fs(f, *x): return [ f(a) for a in x]
Line 1,507: Line 1,470:
variable ctr
variable ctr
coroutine __curry[incr ctr] apply {{f1 f2} {
coroutine __curry[incr ctr] apply {{f1 f2} {
for {set x [info coroutine]} 1 {} {
for {set x [info coroutine]} 1 {} {
set x [{*}$f1 $f2 [yield $x]]
set x [{*}$f1 $f2 [yield $x]]
}
}
}} $f1 $f2
}} $f1 $f2
}</lang>
}</lang>
Line 1,516: Line 1,479:
set r {}
set r {}
foreach n $s {
foreach n $s {
lappend r [{*}$f $n]
lappend r [{*}$f $n]
}
}
return $r
return $r