Partial function application: Difference between revisions
Content added Content deleted
No edit summary |
|||
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> |
|||
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; |
|||
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) |
int square(int a) |
||
{ |
{ |
||
return a * a; |
|||
} |
} |
||
int dbl(int a) |
int dbl(int a) |
||
{ |
{ |
||
return a + a; |
|||
} |
} |
||
int main() |
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; |
|||
}</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 { |
|||
r = append(r, f(i)) |
|||
} |
|||
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 { |
|||
var r []int |
|||
for _, i := range s { |
|||
r = append(r, n+i) |
|||
} |
|||
} |
|||
return r |
|||
} |
|||
} |
} |
||
func main() { |
func main() { |
||
// Turning a method into a function bound to it's reciever: |
|||
fsf1 := fn(f1).fs |
|||
fsf2 := fn(f2).fs |
|||
// Or using a function that returns a function: |
|||
fsf3 := addn(100) |
|||
s := []int{0, 1, 2, 3} |
|||
fmt.Println("For s =", s) |
|||
fmt.Println(" fsf1:", fsf1(s...)) // Called with a slice |
|||
fmt.Println(" fsf2:", fsf2(0, 1, 2, 3)) // ... or with individual arguments |
|||
fmt.Println(" fsf3:", fsf3(0, 1, 2, 3)) |
|||
fmt.Println(" fsf2(fsf1):", fsf2(fsf1(s...)...)) |
|||
s = []int{2, 4, 6, 8} |
|||
fmt.Println("For s =", s) |
|||
fmt.Println(" fsf1:", fsf1(2, 4, 6, 8)) |
|||
fmt.Println(" fsf2:", fsf2(s...)) |
|||
fmt.Println(" fsf3:", fsf3(s...)) |
|||
fmt.Println(" fsf3(fsf1):", fsf3(fsf1(s...)...)) |
|||
}</lang> |
}</lang> |
||
{{out}} |
{{out}} |
||
Line 843: | Line 806: | ||
public class PartialApplication { |
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> |
}</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). |
|||
f1(X, Y) :- |
f1(X, Y) :- |
||
Y is 2 * X. |
|||
f2(X, Y) :- |
f2(X, Y) :- |
||
Y is X * X. |
|||
create_partial(P, fs(P)). |
create_partial(P, fs(P)). |
||
Line 1,316: | Line 1,279: | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
||
fs :- |
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> |
</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) |
|||
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 {} { |
|||
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] |
|||
} |
} |
||
return $r |
return $r |