Wednesday, January 30, 2008

Haskell Snippet: looking at foldl (also a java version)

In the functional programming toolkit; foldl is pretty useful. In layman terms, it is basically a way to call a function on a given input list. From zvon.org; the haskell foldl is defined as:

"It takes the second argument and the first item of the list and applies the function to them, then feeds the function with this result and the second argument and so on. See scanl for intermediate results."

The type definition is:

Foldl: (a -> b -> a) -> a -> [b] -> a

Lets say that out loud; I can call the foldl function with the following parameters; the first parameter passed to foldl is a generic function that has two inputs a and b. This input function returns a type of a. The second parameter has a type of a, the first, initial item or the result of the previous operation. The third parameter is an array of type b.

The listing below shows how you might use foldl.


let a = foldl (\x y -> (++) x (show y)) "-->" [77, 88, 99]


To make it more complicated and unreadable, I defined the first parameter function input as a lambda function with inputs 'x' and 'y':


(\x y -> (++) x (show y))


Here are some other variations of calling foldl:

-- foldl :: (a -> b -> a) -> a -> [b] -> a
-- Fold given an input array [77,88,99] = b
-- b = Array of Integer type
-- a = String type
-- Output = -->778899
let a = foldl (\x y -> (++) x (show y)) "-->" [77, 88, 99]
-- Other functions, operators
-- (++) :: [a] -> [a] -> [a]
-- In our case; x ++ (show y) where y = the integer from [b]

-- Other variations:
let lst = [77, 88, 99]
-- Pass an empty list as 'a'
b = foldl (\x y -> x ++ show y) [] lst
-- What happens if want to find the max given an array of ints
c = foldl max 0 [1, 2, 3, 4,99, 5]
-- Look at it differently with a lambda call
d = foldl (\x y -> x `max` y) 0 [1, 2, 3, 4, 99, 5]
-- How would I take the sum of a list of values (w/o using sum)
e = foldl (\x y -> x + y) 0 [1, 2, 3]
-- Output as you would expect is e = 6


The key is to use the type definition as your guide:

Foldl: (a -> b -> a) -> a -> [b] -> a


foldl with inputs function (a -> b -> a) and input a and input array [b] returns a.

How would this example look in java?
At first, I was going to give a simpler java example that outputs the same result as in haskell, but instead I ended up with this more generic java function. Try this, visualize the result of running the first haskell example shown in the listing above:

Output=-->778899

Ok, define how you would solve that result in an imperative language (like Java) with the simplest possible implementation. You might end up with this (pseudo code):


public String foldl(String init_a, int b[]) {
StringBuffer buf = init_a + b[0]
for (int i = 0; i < b.length(); i++) {
buf.append(b[i]
}
return buf.toString();
}


Something like that, now here is a generic example in Java:

// Date: 1/29/2008
// Example mimic of foldl function in haskell in java.
// foldl :: (a -> b -> a) -> a -> [b] -> a
public class A {
public interface FuncCall {
public Object exec_AtoBtoA(Object o1, Object o2);
}
public static Object exFoldl(Object initA, Object b[],
FuncCall func) {
Object a_res = func.exec_AtoBtoA(initA, b[0]);
for (int i = 1; i < b.length; i++) {
a_res = func.exec_AtoBtoA(a_res, b[i]);
}
return a_res;
}
public static void main(String [] args) {
System.out.println("running");

// -- How would I take the sum of a list of values (w/o using sum)
// let a = foldl (\x y -> (++) x (show y)) "-->" [77, 88, 99]
Object b[] = { 77, 88, 99 };
Object initA = "-->";
Object finalRes = exFoldl(initA, b, new FuncCall () {
public Object exec_AtoBtoA(Object x, Object y) {
String lambdaRes = (x.toString() + y.toString());
return lambdaRes;
}
});
System.out.println("Output=" + finalRes);
Object b2[] = { 1, 2, 3 };
Integer initA2 = 0;
finalRes = exFoldl(initA2, b2, new FuncCall () {
public Object exec_AtoBtoA(Object x, Object y) {
Integer lambdaRes = Integer.parseInt(x.toString()) +
Integer.parseInt(y.toString());
return lambdaRes;
}
});
System.out.println("Output=" + finalRes);

/*
Output after running example:
Output=-->778899
Output=6
*/
}
}

That is all there is to it to understanding foldl and other prelude haskell functions. Read the definition from the haskell documentation to get an idea of the inputs and output. Then pass the correct inputs.
For example, some other useful functions are zip and unzip. Zip has the following type:
zip :: [a] -> [b] -> [(a, b)]
Create a list of tuples from two input lists.

Prelude> let a = [1, 2, 3]
Prelude> let b = ["a", "b", "c"]
Prelude> zip a b
[(1,"a"),(2,"b"),(3,"c")]
Prelude> :t
Prelude> :t zip
zip :: [a] -> [b] -> [(a, b)]

Prelude> unzip (zip a b)
([1,2,3],["a","b","c"])
Prelude>

No comments: