I'm trying to get a better grip on the new functional possibilities of Java 8.
As an example, I took this very elegant Haskell snippet:
nqueens :: Int -> [[(Int,Int)]]
nqueens n = foldr qu [[]] [1..n]
where qu k qss = [ ((j,k):qs) | qs <- qss, j <- [1..n], all (safe (j,k)) qs ]
safe (j,k) (l,m) = j /= l && k /= m && abs (j-l) /= abs (k-m)
I translated it to Scala, and was quite satisfied:
object queens {
def nqueens(n: Int) = {
import math.abs
type Pos = (Int, Int)
def safe(p:Pos, q:Pos) = p._1 != q._1 && p._2 != q._2 && abs(p._1 - q._1) != abs(p._2 - q._2)
def qu(k: Int, qss:List[List[Pos]]) =
for(qs <- qss; j <- (1 to n) if qs.forall(safe(_ ,(j,k)))) yield ((j,k) :: qs)
(1 to n).foldRight(List(List[Pos]()))(qu)
}
def main(args:Array[String]) = println(nqueens(8).mkString("\n"))
}
But I think my Java translation is terrible, and I have the feeling it's still way too iterative:
import static java.lang.Math.*;
import java.util.*;
public class Queens {
private static boolean safe(Pos p, Pos q) {
return p.x != q.x && p.y != q.y && abs(p.x - q.x) != abs(p.y - q.y);
}
private static List<List<Pos>> qu(int k, int n, List<List<Pos>> qss) {
List<List<Pos>> result = new ArrayList<>();
for(List<Pos> qs : qss) {
for(int j = 1; j <= n; j++) {
Pos newPos = new Pos(j,k);
if (qs.stream().allMatch(pos -> safe(pos, newPos))) {
List<Pos> partialResult = new ArrayList<>(qs);
partialResult.add(newPos);
result.add(partialResult);
}
}
}
return result;
}
public static List<List<Pos>> nqueens(int n) {
List<List<Pos>> result = Collections.singletonList(new ArrayList<>());
for(int i = n; i > 0; i--) {
result = qu(i,n,result);
}
return result;
}
public static void main(String[] args) {
nqueens(8).forEach(System.out::println);
}
public static class Pos {
public final int x;
public final int y;
public Pos(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return String.format("(%d,%d)",x,y);
}
}
}
Even ignoring the overhead of the Pos
class the code seems to be way too verbose, and even worse, constantly jumping back and forth between imperative and functional style.
I'm still using a lot of for loops. Especially I couldn't find a good replacement for foldRight
. Further, I found no good way to utilize IntStream
, as its range
or rangeClosed
methods seemed just too inconvenient.
I'm looking for hints how to improve my code in a functional way without straying too far from the original snippets.
[Update]
Thanks to both answers and some API diving I came up with the following, which is IMHO a good compromise between conciseness and readability:
public class Queens {
private static boolean safe(Pos p, Pos q) {
return p.x != q.x && p.y != q.y && abs(p.x - q.x) != abs(p.y - q.y);
}
private static <T> List<T> snoc(List<T> ts, T t) {
List<T> result = new LinkedList<>(ts);
result.add(t);
return result;
}
private static Stream<Integer> range(int fromInclusive, int toInclusive) {
return IntStream.rangeClosed(fromInclusive, toInclusive).boxed();
}
private static Stream<List<Pos>> solveRow(int row, int boardSize, Stream<List<Pos>> solutions) {
return solutions.flatMap(solution ->
range(1, boardSize).flatMap(column ->
solution.stream().allMatch(pos ->
safe(pos, new Pos(row, column)))
? Stream.of(snoc(solution, new Pos(row, column)))
: Stream.empty()));
}
public static Stream<List<Pos>> nqueens(int boardSize) {
return range(1, boardSize).reduce(
Stream.of(Collections.emptyList()),
(solutions, row) -> solveRow(row, boardSize, solutions),
Stream::concat);
}
public static void main(String[] args) {
nqueens(8).forEach(System.out::println);
}
public static class Pos {
public final int x;
public final int y;
public Pos(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return String.format("(%d,%d)", x, y);
}
}
}