I decided to teach myself Haskell and tried to translate some code from Java to Haskell so I can get more familiar with recursion, backtracking and search tree pruning.
Java Code :
private static boolean isListOkay(ArrayList<Integer> numbers) {
return listSum(numbers) == 8 && numbers.size() == 3;
}
private static int listSum(ArrayList<Integer> numbers) {
int sum = 0;
for (Integer number : numbers)
sum += number;
return sum;
}
public static ArrayList<Integer> sumTo8(ArrayList<Integer> numbers) {
return sumTo8(numbers, 0, new ArrayList<Integer>());
}
private static ArrayList<Integer> sumTo8(ArrayList<Integer> numbers, int i, ArrayList<Integer> list) {
if (isListOkay(list))
return list;
else if (i == numbers.size() && !isListOkay(list))
return null;
else if (listSum(list) > 8 || listSum(list) == 8 && list.size() != 3)
return null;
else {
int currentNumber = numbers.get(i);
ArrayList<Integer> pickIt = new ArrayList<>(list);
pickIt.add(currentNumber);
ArrayList<Integer> leaveIt = new ArrayList<>(list);
ArrayList<Integer> pickItResult = sumTo8(numbers, i + 1, pickIt);
if (pickItResult == null)
return sumTo8(numbers, i + 1, leaveIt);
return pickItResult;
}
}
Haskell code :
listSumUtil :: [Int] -> Int -> Int
listSumUtil [] sum = sum
listSumUtil (x:xs) sum = x + y
where y = listSumUtil xs sum
listSum :: [Int] -> Int
listSum list = listSumUtil list 0
sumTo8Util :: [Int] -> [Int] -> [Int]
sumTo8Util [] list
| sum == 8 && listLength == 3 = list
| otherwise = []
where sum = listSum list
listLength = length list
sumTo8Util (x:xs) l2 =
if sum > 8 && listLength > 3 then []
else if sum == 8 && listLength == 3 then l2
else (if l3 == [] then l4 else l3)
where sum = listSum l2
listLength = length l2
l3 = sumTo8Util xs pickIt
pickIt = l2 ++ [x]
l4 = sumTo8Util (x:xs) l2
sumTo8 :: [Int] -> [Int]
sumTo8 list = sumTo8Util list []
The Java code is working and I was able to compile the Haskell one. When I executed main though there was no output and it just kept running so there must be an infinite loop somewhere and here is where I need your help. How would one implement the exact Java code in Haskell ? Am I missing something in my implementation? As you see I avoided syntactic sugar in my Haskell code because I just started and can't understand it yet.
Update 1 :
Added the else if sum == 8 && listLength == 3 then l2 condition in Haskell code but still doesn't work.
Update 2 :
Found a way to do it.
Working code :
listSum :: [Int] -> Int
listSum list = foldl (+) 0 list
insertAtEnd :: [Int] -> Int -> [Int]
insertAtEnd [] c = [c]
insertAtEnd (h:t) c = h : insertAtEnd t c
sumTo8Util :: [Int] -> Int -> [Int] -> [Int]
sumTo8Util lst i rlst
| (length rlst == 3) && (listSum rlst == 8) = rlst
| (i == length lst) && ((listSum rlst /= 8) || (length rlst /= 3)) = []
| otherwise = if (length pickIt == 0) then (sumTo8Util lst (i+1) rlst) else pickIt
where number = lst !! i
nrlst = insertAtEnd rlst number
pickIt = sumTo8Util lst (i+1) nrlst
sumTo8 :: [Int] -> [Int]
sumTo8 list = sumTo8Util list 0 []
Basically I try to trigger backtrack by returning the empty list.
If there is an alternative that makes use of backtrack and is way more efficient than my code* feel free to suggest it.
*Pretty sure it will be as I've been teaching myself Haskell for a few days now