Nice, thank you for sharing! For comparison, here is a Prolog solution for one of the mentioned puzzles, namely "an unusually difficult puzzle of this type, which is to make 2,5,6,6 total to 17".
Let us start by defining suitable operators so that we can conveniently use the domain-specific language to reason about such tasks, using infix notation:
:- op(400, yfx, ×).
:- op(400, yfx, ÷).
Next, I describe the relation between a list of numbers and possible shapes of binary trees we can build from these numbers. We distinguish between leaves and inner nodes of the tree, and consequently use two functors that let us symbolically distinguish the different cases: numbers_tree([N], leaf(N)).
numbers_tree(Vs0, binary(Left, Right)) :-
permutation(Vs0, Vs),
append([L|Ls], [R|Rs], Vs),
numbers_tree([L|Ls], Left),
numbers_tree([R|Rs], Right).
For example: ?- numbers_tree([1,2], T).
T = binary(leaf(1), leaf(2)) ;
T = binary(leaf(2), leaf(1)) ;
false.
This does not yet say anything about the arithmetic operators that we can use. Note that this definition may yield redundant solutions, as in: ?- numbers_tree([1,1], T).
T = binary(leaf(1), leaf(1)) ;
T = binary(leaf(1), leaf(1)) ;
false.
That's completely OK though, and we can think about making it more efficient if necessary.Now we are almost done. It only remains to describe how different arithmetic operations affect the result of the evaluation. This can be expressed with the following relations:
tree_op_expr_value(leaf(N), _, N, N).
tree_op_expr_value(binary(Left0, Right0), Op, Expr, Value) :-
tree_op_expr_value(Left0, _, Left, VL),
tree_op_expr_value(Right0, _, Right, VR),
op_values_value(Op, VL, VR, Value),
Expr =.. [Op,Left,Right].
op_values_value(+, A, B, V) :- V is A + B.
op_values_value(-, A, B, V) :- V is A - B.
op_values_value(×, A, B, V) :- V is A * B.
op_values_value(÷, A, B, V) :- B =\= 0, V is A rdiv B.
Time to try it out, using for example the following query: ?- time((numbers_tree([2,5,6,6], T),
tree_op_expr_value(T, _, Expr, 17))).
This yields: % 6,060 inferences, 0.004 CPU in 0.004 seconds (92% CPU, 1551459 Lips)
T = binary(binary(leaf(2), binary(leaf(5), leaf(6))), leaf(6)),
Expr = (2+5÷6)×6 .
It seems to work nicely. On backtracking, all solutions are generated. Note that this solution uses built-in rational numbers that are available in several Prolog systems.