How to resolve the algorithm Partial function application step by step in the Java programming language
How to resolve the algorithm Partial function application step by step in the Java programming language
Table of Contents
Problem Statement
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:
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.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Partial function application step by step in the Java programming language
The provided Java code showcases partial function application, a programming technique that allows you to create new functions by fixing one or more arguments of an existing function. It demonstrates this concept with a specific example of applying a function to an array of integers.
Interface and Method Definitions:
- IntegerFunction: An interface representing a function that takes an integer as an argument and returns an integer.
- SequenceFunction: An interface representing a function that takes an array of integers as an argument and returns an array of integers.
Original Function "fs":
static int[] fs(IntegerFunction f, int[] s)
: This method takes two arguments, anIntegerFunction
and an array of integers, and applies the function to each element of the array. It returns the resulting array.
Currying the Function "fs":
static SequenceFunction fs(final IntegerFunction f)
: This method takes anIntegerFunction
as an argument and returns aSequenceFunction
. It creates a new function that applies the givenIntegerFunction
to each element of an input array. This currying is necessary for partial application.
Concrete Function Implementations:
- f1: An
IntegerFunction
that multiplies an integer by 2. - f2: An
IntegerFunction
that squares an integer.
Partial Application Using Currying:
- fsf1: A
SequenceFunction
that represents the partial application offs
withf1
. It is created usingfs(f1)
. - fsf2: A
SequenceFunction
that represents the partial application offs
withf2
. It is created usingfs(f2)
.
Main Method:
- The
main
method initializes a 2D arraysequences
containing sets of integers. - It iterates over each array in
sequences
and appliesfsf1
andfsf2
to it. - The results are printed to the console.
Understanding the Output:
The output shows the original array, the result of applying fsf1
(partial application of fs
with f1
), and the result of applying fsf2
(partial application of fs
with f2
) to each input array.
High-Level Explanation:
Partial application allows you to create new functions by fixing one or more arguments of an existing function. In this example, fsf1
and fsf2
are partially applied versions of fs
with the f1
and f2
functions, respectively. This allows you to apply f1
and f2
to an array of integers with simpler syntax and improved code readability, as shown in the main
method.
In another version, it contains a similar approach using Java 8 lambda expressions and the java.util.function
package. The definition of the PartialApplication
interface implements the BiFunction
and provides a default method for partial application, which curries the function. The code then defines sample functions f1
and f2
and partially applies fs
to them, creating fsf1
and fsf2
for convenient application to arrays.
Source code in the java programming language
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)));
}
}
}
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
@FunctionalInterface
public interface PartialApplication<INPUT1, INPUT2, OUTPUT> extends BiFunction<INPUT1, INPUT2, OUTPUT> {
// Original method fs(f, s).
public static int[] fs(IntUnaryOperator f, int[] s) {
return Arrays.stream(s)
.parallel()
.map(f::applyAsInt)
.toArray()
;
}
// Currying method f.apply(a).apply(b),
// in lieu of f.apply(a, b),
// necessary for partial application.
public default Function<INPUT2, OUTPUT> apply(INPUT1 input1) {
return input2 -> apply(input1, input2);
}
// Original method fs turned into a partially-applicable function.
public static final PartialApplication<IntUnaryOperator, int[], int[]> fs = PartialApplication::fs;
public static final IntUnaryOperator f1 = i -> i + i;
public static final IntUnaryOperator f2 = i -> i * i;
public static final UnaryOperator<int[]> fsf1 = fs.apply(f1)::apply; // Partial application.
public static final UnaryOperator<int[]> fsf2 = fs.apply(f2)::apply;
public static void main(String... args) {
int[][] sequences = {
{0, 1, 2, 3},
{2, 4, 6, 8},
};
Arrays.stream(sequences)
.parallel()
.map(array ->
Stream.of(
array,
fsf1.apply(array),
fsf2.apply(array)
)
.parallel()
.map(Arrays::toString)
.toArray()
)
.map(array ->
String.format(
String.join("\n",
"array: %s",
" fsf1(array): %s",
" fsf2(array): %s"
),
array
)
)
.forEachOrdered(System.out::println)
;
}
}
You may also check:How to resolve the algorithm 100 doors step by step in the Wren programming language
You may also check:How to resolve the algorithm Literals/String step by step in the Vim Script programming language
You may also check:How to resolve the algorithm Ackermann function step by step in the SmileBASIC programming language
You may also check:How to resolve the algorithm Text processing/2 step by step in the J programming language
You may also check:How to resolve the algorithm Balanced brackets step by step in the Quackery programming language