How to dynamically call an operator in Elixir - function

I'm working my way through Dave's upcoming book on Elixir, and in one exercise I would like to dynamically construct a function reference to Kernel.+/2, Kernel.-/2 etc, based on the contents of one character of a string, '+', '-' and so on.
Based on another SO question I expected to be able to call apply/3 passing Kernel, :+ and the two numbers like this:
apply(Kernel, :+, [5, 7])
This doesn't work because (if I understand right) Kernel.+/2 is a macro, not a function. I looked up the source code, and + is defined in terms of __op__, and I can call it from iex:
__op__(:+, 5, 7)
This works until I put the :+ into a variable:
iex(17)> h = list_to_atom('+')
:+
iex(18)> __op__(h, 5, 7)
** (CompileError) iex:18: undefined function __op__/3
src/elixir.erl:151: :elixir.quoted_to_erl/3
src/elixir.erl:134: :elixir.eval_forms/4
And I'm guessing there's no way to call __op__ using apply/3.
Of course, the brute-force method gets the job done.
defp _fn(?+), do: &Kernel.+/2
defp _fn(?-), do: &Kernel.-/2
defp _fn(?*), do: &Kernel.*/2
# defp _fn(?/), do: &Kernel.//2 # Nope, guess again
defp _fn(?/), do: &div/2 # or &(&1 / &2) or ("#{div &1, &2} remainder #{rem &1, &2}")
But is there something more concise and dynamic?
José Valim nailed it with his answer below. Here's the code in context:
def calculate(str) do
{x, op, y} = _parse(str, {0, :op, 0})
apply :erlang, list_to_atom(op), [x, y]
end
defp _parse([] , acc ) , do: acc
defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0})
defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0})
defp _parse([_ | t], acc ) , do: _parse(t, acc)

You can just use the Erlang one:
apply :erlang, :+, [1,2]
We are aware this is confusing and we are studying ways to make it or more explicit or more transparent.
UPDATE: Since Elixir 1.0, you can dispatch directly to Kernel (apply Kernel, :+, [1, 2]) or even use the syntax the OP first attempted (&Kernel.+/2).

Related

Comma separated binary arguments? - elixir

I've been learning elixir this month, and was in a situation where I wanted to convert a binary object into a list of bits, for pattern matching.
My research led me here, to an article showing a method for doing so. However, I don't fully understand one of the arguments passed to the extract function.
I could just copy and paste the code, but I'd like to understand what's going on under the hood here.
The argument is this: <<b :: size(1), bits :: bitstring>>.
What I understand
I understand that << x >> denotes a binary object x. Logically to me, it looks as though this is similar to performing: [head | tail] = list on a List, to get the first element, and then the remaining ones as a new list called tail.
What I don't understand
However, I'm not familiar with the syntax, and I have never seen :: in elixir, nor have I ever seen a binary object separated by a comma: ,. I also, haven't seen size(x) used in Elixir, and have never encountered a bitstring.
The Bottom Line
If someone, could explain exactly how the syntax for this argument breaks down, or point me towards a resource I would highly appreciate it.
For your convenience, the code from that article:
defmodule Bits do
# this is the public api which allows you to pass any binary representation
def extract(str) when is_binary(str) do
extract(str, [])
end
# this function does the heavy lifting by matching the input binary to
# a single bit and sends the rest of the bits recursively back to itself
defp extract(<<b :: size(1), bits :: bitstring>>, acc) when is_bitstring(bits) do
extract(bits, [b | acc])
end
# this is the terminal condition when we don't have anything more to extract
defp extract(<<>>, acc), do: acc |> Enum.reverse
end
IO.inspect Bits.extract("!!") # => [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1]
IO.inspect Bits.extract(<< 99 >>) #=> [0, 1, 1, 0, 0, 0, 1, 1]
Elixir pattern matching seems mind blowingly easy to use for
structured binary data.
Yep. You can thank the erlang inventors.
According to the documentation, <<x :: size(y)>> denotes a bitstring,
whos decimal value is x and is represented by a string of bits that is
y in length.
Let's dumb it down a bit: <<x :: size(y)>> is the integer x inserted into y bits. Examples:
<<1 :: size(1)>> => 1
<<1 :: size(2)>> => 01
<<1 :: size(3)>> => 001
<<2 :: size(3)>> => 010
<<2 :: size(4)>> => 0010
The number of bits in the binary type is divisible by 8, so a binary type has a whole number of bytes (1 byte = 8 bits). The number of bits in a bitstring is not divisible by 8. That's the difference between the binary type and the bitstring type.
I understand that << x >> denotes a binary object x. Logically to me,
it looks as though this is similar to performing: [head | tail] = list
on a List, to get the first element, and then the remaining ones as a
new list called tail.
Yes:
defmodule A do
def show_list([]), do: :ok
def show_list([head|tail]) do
IO.puts head
show_list(tail)
end
def show_binary(<<>>), do: :ok
def show_binary(<<char::binary-size(1), rest::binary>>) do
IO.puts char
show_binary(rest)
end
end
In iex:
iex(6)> A.show_list(["a", "b", "c"])
a
b
c
:ok
iex(7)> "abc" = <<"abc">> = <<"a", "b", "c">> = <<97, 98, 99>>
"abc"
iex(9)> A.show_binary(<<97, 98, 99>>)
a
b
c
:ok
Or you can interpret the integers in the binary as plain old integers:
def show(<<>>), do: :ok
def show(<<ascii_code::integer-size(8), rest::binary>>) do
IO.puts ascii_code
show(rest)
end
In iex:
iex(6)> A.show(<<97, 98, 99>>)
97
98
99
:ok
The utf8 type is super useful because it will grab as many bytes as required to get a whole utf8 character:
def show(<<>>), do: :ok
def show(<<char::utf8, rest::binary>>) do
IO.puts char
show(rest)
end
In iex:
iex(8)> A.show("ۑ")
8364
235
:ok
As you can see, the uft8 type returns the unicode codepoint of the character. To get the character as a string/binary:
def show(<<>>), do: :ok
def show(<<codepoint::utf8, rest::binary>>) do
IO.puts <<codepoint::utf8>>
show(rest)
end
You take the codepoint(an integer) and use it to create the binary/string <<codepoint::utf8>>.
In iex:
iex(1)> A.show("ۑ")
€
ë
:ok
You can't specify a size for the utf8 type, though, so if you want to read multiple utf8 characters, you have to specify multiple segments.
And of course, the segment rest::binary, i.e. a binary type with no size specified, is super useful. It can only appear at the end of a pattern, and rest::binary is like the greedy regex: (.*). The same goes for rest::bitstring.
Although the elixir docs don't mention it anywhere, the total number of bits in a segment, where a segment is one of those things:
| | |
v v v
<< 1::size(8), 1::size(16), 1::size(1) >>
is actually unit * size, where each type has a default unit. The default type for a segment is integer, so the type for each segment above defaults to integer. An integer has a default unit of 1 bit, so the total number of bits in the first segment is: 8 * 1 bit = 8 bits. The default unit for the binary type is 8 bits, so a segment like:
<< char::binary-size(6)>>
has a total size of 6 * 8 bits = 48 bits. Equivalently, size(6) is just the number of bytes. You can specify the unit just like you can the size, e.g. <<1::integer-size(2)-unit(3)>>. The total bit size of that segment is: 2 * 3 bits = 6 bits.
However, I'm not familiar with the syntax
Check this out:
def bitstr2bits(bitstr) do
for <<bit::integer-size(1) <- bitstr>>, do: bit
end
In iex:
iex(17)> A.bitstr2bits <<1::integer-size(2), 2::integer-size(2)>>
[0, 1, 1, 0]
Equivalently:
iex(3)> A.bitstr2bits(<<0b01::integer-size(2), 0b10::integer-size(2)>>)
[0, 1, 1, 0]
Elixir tends to abstract away recursion with library functions, so usually you don't have to come up with your own recursive definitions like at your link. However, that link shows one of the standard, basic recursion tricks: adding an accumulator to the function call to gather results that you want the function to return. That function could also be written like this:
def bitstr2bits(<<>>), do: []
def bitstr2bits(<<bit::integer-size(1), rest::bitstring>>) do
[bit | bitstr2bits(rest)]
end
The accumulator function at the link is tail recursive, which means it takes up a constant (small) amount of memory--no matter how many recursive function calls are needed to step through the bitstring. A bitstring with 10 million bits? Requiring 10 million recursive function calls? That would only require a small amount of memory. In the old days, the alternate definition I posted could potentially crash your program because it would take up more and more memory for each recursive function call, and if the bitstring were long enough the amount of memory needed would be too large, and you would get stackoverflow and your program would crash. However, erlang has optimized away the disadvantages of recursive functions that are not tail recursive.
You can read about all these here, short answer:
:: is similar as guard, like a when is_integer(a), in you case size(1) expect a 1 bit binary
, is a separator between matching binaries, like | in [x | []] or like comma in [a, b]
bitstring is a superset over binaries, you can read about it here and here, any binary can be respresented as bitstring
iex> ?h
104
iex> ?e
101
iex> ?l
108
iex> ?o
111
iex> <<104, 101, 108, 108, 111>>
"hello"
iex> [104, 101, 108, 108, 111]
'hello'
but not vice versa
iex> <<1, 2, 3>>
<<1, 2, 3>>
After some research, I realized I overlooked some important information located at: elixir-lang.
According to the documentation, <<x :: size(y)>> denotes a bitstring, whos decimal value is x and is represented by a string of bits that is y in length.
Furthermore, <<binary>> will always attempt to conglomerate values in a left-first direction, into bytes or 8-bits, however, if the number of bits is not divisible by 8, there will by x bytes, followed by a bitstring.
For example:
iex> <<3::size(5), 5::size(6)>> # <<00011, 000101>>
<<24, 5::size(3)>> # automatically shifted to: <<00011000(24) , 101>>
Now, elixir also lets us pattern match binaries, and bitstrings like so:
iex> <<3 :: size(2), b :: bitstring>> = <<61 :: size(6)>> # [11] [1101]
iex> b
<<13 :: size(4)>> # [1101]
So, i completly misunderstood binaries and biststrings, and pattern matching between the two.
Not really the answer to the question stated, but I’d put it here for the sake of formatting. In elixir we usually use Kernel.SpecialForms.for/1 comprehension for bitstring generation.
for << b :: size(1) <- "!!" >>, do: b
#⇒ [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1]
for << b :: size(1) <- <<99>> >>, do: b
#⇒ [0, 1, 1, 0, 0, 0, 1, 1]
I wanted to use the bits, in an 8 bit binary to toggle conditions. So
[b1, b2, ...] = extract(<<binary>>)
I then wanted to say:
if b1, do: x....
if b2, do: y...
Is there a better way to do what I'm trying to do, instead of pattern
matching?
First of all, the only terms that evaluate to false in elixir are false and nil (just like in ruby):
iex(18)> x = 1
1
iex(19)> y = 0
0
iex(20)> if x, do: IO.puts "I'm true."
I'm true.
:ok
iex(21)> if y, do: IO.puts "I'm true."
I'm true.
:ok
Although, the fix is easy:
if b1 == 1, do: ...
Extracting the bits into a list is unnecessary because you can just iterate the bitstring:
def check_bits(<<>>), do: :ok
def check_bits(<<bit::integer-size(1), rest::bitstring>>) do
if bit == 1, do: IO.puts "bit is on"
check_bits(rest)
end
In other words, you can treat a bitstring similarly to a list.
Or, instead of performing the logic in the body of the function to determine whether the bit is 1, you can use pattern matching in the head of the function:
def check_bits(<<>>), do: :ok
def check_bits(<< 1::integer-size(1), rest::bitstring >>) do
IO.puts "The bit is 1."
check_bits(rest)
end
def check_bits(<< 0::integer-size(1), rest::bitstring >>) do
IO.puts "The bit is 0."
check_bits(rest)
end
Instead of using a variable, bit, for the match like here:
bit::integer-size(1)
...you use a literal value, 1:
1::integer-size(1)
The only thing that can match a literal value is the literal value itself. As a result, the pattern:
<< 1::integer-size(1), rest::bitstring >>
will only match a bitstring where the first bit, integer-size(1), is 1. The literal matching employed there is similar to doing the following with a list:
def list_contains_4([4|_tail]) do
IO.puts "found a 4"
true #end the recursion and return true
end
def list_contains_4([head|tail]) do
IO.puts "#{head} is not a 4"
list_contains_4(tail)
end
def list_contains_4([]), do: false
The first function clause tries to match the literal 4 at the head of the list. If the head of the list is not 4, there's no match; so elixir moves on to the next function clause, and in the next function clause the variable head will match anything in the list.
Using pattern matching in the head of a function rather than performing logic in the body of a function is considered more stylish and efficient in erlang.

Julia: creating a method for Any vector with missing values

I would like to create a function that deals with missing values. However, when I tried to specify the missing type Array{Missing, 1}, it errors.
function f(x::Array{<:Number, 1})
# do something complicated
println("no missings.")
println(sum(x))
end
function f(x::Array{Missing, 1})
x = collect(skipmissing(x))
# do something complicated
println("removed missings.")
f(x)
end
f([2, 3, 5])
f([2, 3, 5, missing])
I understand that my type is not Missing but Array{Union{Missing, Int64},1}
When I specify this type, it works in the case above. However, I would like to work with all types (strings, floats etc., not only Int64).
I tried
function f(x::Array{Missing, 1})
...
end
But it errors again... Saying that
f (generic function with 1 method)
ERROR: LoadError: MethodError: no method matching f(::Array{Union{Missing, Int64},1})
Closest candidates are:
f(::Array{Any,1}) at ...
How can I say that I wand the type to be union missings with whatever?
EDIT (reformulation)
Let's have these 4 vectors and two functions dealing with strings and numbers.
x1 = [1, 2, 3]
x2 = [1, 2, 3, missing]
x3 = ["1", "2", "3"]
x4 = ["1", "2", "3", missing]
function f(x::Array{<:Number,1})
println(sum(x))
end
function f(x::Array{String,1})
println(join(x))
end
f(x) doesn't work for x2 and x3, because they are of type Array{Union{Missing, Int64},1} and Array{Union{Missing, String},1}, respectively.
It is possible to have only one function that detects whether the vector contains missings, removes them and then deals appropriately with it.
for instance:
function f(x::Array{Any, 1})
x = collect(skipmissing(x))
print("removed missings")
f(x)
end
But this doesn't work because Any indicates a mixed type (e.g., strings and nums) and does not mean string OR numbers or whatever.
EDIT 2 Partial fix
This works:
function f(x::Array)
x = collect(skipmissing(x))
print("removed missings")
f(x)
end
[But how, then, to specify the shape (number of dimensions) of the array...? (this might be an unrelated topic though)]
You can do it in the following way:
function f(x::Vector{<:Number})
# do something complicated
println("no missings.")
println(sum(x))
end
function f(x::Vector{Union{Missing,T}}) where {T<:Number}
x = collect(skipmissing(x))
# do something complicated
println("removed missings.")
f(x)
end
and now it works:
julia> f([2, 3, 5])
no missings.
10
julia> f([2, 3, 5, missing])
removed missings.
no missings.
10
EDIT:
I will try to answer the questions raised (if I miss something please add a comment).
First Vector{Union{Missing, <:Number}} is the same as Vector{Union{Missing, Number}} because of the scoping rules as tibL indicated as Vector{Union{Missing, <:Number}} translates to Array{Union{Missing, T} where T<:Number,1} and where clause is inside Array.
Second (here I am not sure if this is what you want). I understand you want the following behavior:
julia> g(x::Array{>:Missing,1}) = "$(eltype(x)) allows missing"
g (generic function with 2 methods)
julia> g(x::Array{T,1}) where T = "$(eltype(x)) does not allow missing"
g (generic function with 2 methods)
julia> g([1,2,3])
"Int64 does not allow missing"
julia> g([1,2,missing])
"Union{Missing, Int64} allows missing"
julia> g(["a",'a'])
"Any allows missing"
julia> g(Union{String,Char}["a",'a'])
"Union{Char, String} does not allow missing"
Note the last two line - although ["a", 'a'] does not contain missing the array has Any element type so it might contain missing. The last case excludes it.
Also you can see that you could change the second parameter of Array{T,N} to something else to get a different dimensionality.
Also this example works because the first method, as more specific, catches all cases that allow Missing and a second method, as more general, catches what is left (i.e. essentially what does not allow Missing).

MapleSoft: solutions to the inverse of a function puzzle

I have to find the inverse of a function which looks like:
T := ->x (x)^0.5/(x^0.5+(1-x)^0.5)^2.
As we can see from the polynomial, we have 4 solutions when solving y= f(x). In maple,I soled for the inverse of T(x)
V := x-> solve(t=T(x),x,useassumptions=true) assuming 0<=t<=1.
and I can evaluate V, i.e maple can do V(0)=0 V(1)=1 etc.
However, as discussed, there are four solutions to the inverse function, the output of V is an expressions sequence, which looks like (solution1, solution2, solution3, solution4).
In later part of the task, I have to find the derivative of V(x)and integrate it. When I apply diff(V(x),x), maple gives me an error, saying V(x) is not valid.As V(x) is an expression sequence. I tried to use the function D(V), but still no luck.
My questions is how would I be able to handle this V(x) as an expression sequence to finish the rest of the task. Is V(x) a piecewise function? If that's the case, how would I be able to convert this expression sequence to a piecewise function.
Regards,
restart:
T := proc (x) options operator, arrow; sqrt(x)/(sqrt(x)+sqrt(1-x))^2 end proc:
V := proc (x) options operator, arrow; solve(x = T(y), y) end proc:
sol := [allvalues(V(x))]:# Extract 4 solution, with command op(1, sol)->Only first solution is correct.
plot([x, T(x), op(1, sol)], x = 0 .. 2, legend = [typeset("Curve: ", "x"),
typeset("Curve: ", "T(x)"), typeset("Curve: ", "V(x)")]);
VV := proc (x) options operator, arrow; evalf(op(1, sol)) end proc;
eval(VV(x), x = 1/2); #Inverse function at point x=1/2
eval(diff(VV(x), x), x = 1/2);# Derivative of inverse function at point x=1/2
int(VV(x), x = 1/10 .. 1/2, numeric);# Integral of inverse function at range (1/10..1/2)
Mathematica 11.3 solution:

julia lang - how to apply multiple functions to a value

I would like to apply a set of functions to a value and get a set of values as output. I see in help?> groupby (DataFrames package) we can do:
> df |> groupby(:a) |> [sum, length]
> df |> groupby([:a, :b]) |> [sum, length]
but can we do
> [sum, length](groupby([:a, :b]))
MethodError: objects of type Array{Function,1} are not callable
square brackets [] for indexing an Array.
eval_user_input(::Any, ::Base.REPL.REPLBackend) at ./REPL.jl:64
in macro expansion at ./REPL.jl:95 [inlined]
in (::Base.REPL.##3#4{Base.REPL.REPLBackend})() at ./event.jl:68
or even
> [sum, length](1:5)
I would expect the output:
[15, 5]
Yes and no. (i.e. yes it's possible, but no, not with that syntax):
No: The syntax you see with |> and dataframes is not general syntax. It's just how the |> method is defined for dataframes. See its definition in file grouping.jl (line 377) and you'll see it's just a wrapper to another function, and it's defined to either accept a function, or a vector of functions.
PS: Note that the generic |> which "pipes" an argument into a function, only expects 1-argument functions on the right hand side, and has very little to do with this particular "dataframe-overloaded" method.
Yes:
You can apply a set of functions to a set of inputs in other ways.
One simple way, e.g. would be via a list comprehension:
julia> a = [1 2 3;2 3 4];
julia> [f(a) for f in [sum, length, size]]
3-element Array{Any,1}:
15
6
(2,3)
Or using map:
julia> map( (x) -> x(a), [sum, length, size])
etc.
PS: If you're keen to use |> to achieve this, clearly you could also do something like this:
julia> a |> (x) -> [sum(x), length(x), size(x)]
but presumably that defeats the purpose of what you're trying to do :)
Your proposed syntax is possible in Julia by adding a method to the type Array{T} (here, T is restricted to subtypes of Function):
julia> (a::Array{T}){T<:Function}(x) = [f(x) for f in a]
julia> [sin cos; exp sqrt](0)
2×2 Array{Float64,2}:
0.0 1.0
1.0 0.0
However, this has a large overhead if the number of functions is small. For maximum speed, one can use Tuples and a #generated function to unroll the loop manually:
julia> #generated (t::NTuple{N, Function}){N}(x) = :($((:(t[$i](x)) for i in 1:N)...),)
julia> (cos, sin)(0)
(1.0,0.0)

How to pass the return type of a function to an exception in OCaml?

I have function 'my_a' in OCaml, which could have a very complicated return type:
exception Backtrack
exception Continue of (* How do I put the type of function 'my_a' here? *)
let my_a arg = try do_stuff (List.hd arg)
with
| Backtrack -> my_a (List.tl arg)
| Continue (found_answer) -> (try my_a (List.tl arg)
with
| Backtrack -> raise Continue(found_answer)
| Continue (other_answer) ->
raise Continue (compare_answer(found_answer,other_answer));;
(* the caller of my_a will handle the Continue exception to catch the found value
if something was found*)
This is my problem: I'm using backtrack to find a solution. When a backtrack exception is raised by do_stuff, there was no solution going that path. However, when it raises an exception of type Continue, it means it found a solution, but, it may not be the best solution there is, that's when I try again with a different path. If there is another exception, I want to return the answer it already had found.
The thing is, to be able to use that feature of OCaml I need to to tell it what data type Continue will be carrying. What the OCaml top level returns when i define my_a:
'a * ('a -> ('a, 'b) symbol list list) ->
'b list -> ('a * ('a, 'b) symbol list) list * 'b list = <fun>
Does anyone have any idea of how to do that, or a different solution to that?
It's hard to tell exactly what you're asking. I think you might be asking how to get the type inside the Two exception to be set to the return type of A without having to specifically declare this type. I can't think of any way to do it.
Things might go better if you used option types instead of exceptions. Or you can just declare the return type of A explicitly. It might be good documentation.
A couple of side comments: (a) function names have to start with a lower case letter (b) this code looks quite convoluted and hard to follow. There might be a simpler way to structure your computation.
You are gaining nothing by using exceptions. Here is a possible solution.
(** There are many ways to implement backtracking in Ocaml. We show here one
possibility. We search for an optimal solution in a search space. The
search space is given by an [initial] state and a function [search] which
takes a state and returns either
- a solution [x] together with a number [a] describing how good [x] is
(larger [a] means better solution), or
- a list of states that need still to be searched.
An example of such a problem: given a number [n], express it as a sum
[n1 + n2 + ... + nk = n] such that the product [n1 * n2 * ... * nk] is
as large as possible. Additionally require that [n1 <= n2 <= ... <= nk].
The state of the search can be expressed as pair [(lst, s, m)] where
[lst] is the list of numbers in the sum, [s] is the sum of numbers in [lst],
and [m] is the next number we will try to add to the list. If [s = n] then
[lst] is a solution. Otherwise, if [s + m <= n] then we branch into two states:
- either we add [m] to the list, so the next state is [(m :: lst, m+s, m)], or
- we do not add [m] to the list, and the next state is [(lst, s, m+1)].
The return type of [search] is described by the following datatype:
*)
type ('a, 'b, 'c) backtrack =
| Solution of ('a * 'b)
| Branches of 'c list
(** The main function accepts an initial state and the search function. *)
let backtrack initial search =
(* Auxiliary function to compare two optional solutions, and return the better one. *)
let cmp x y =
match x, y with
| None, None -> None (* no solution *)
| None, Some _ -> y (* any solution is better than none *)
| Some _, None -> x (* any solution is better than none *)
| Some (_, a), Some (_, b) ->
if a < b then y else x
in
(* Auxiliary function which actually performs the search, note that it is tail-recursive.
The argument [best] is the best (optional) solution found so far, [branches] is the
list of branch points that still needs to be processed. *)
let rec backtrack best branches =
match branches with
| [] -> best (* no more branches, return the best solution found *)
| b :: bs ->
(match search b with
| Solution x ->
let best = cmp best (Some x) in
backtrack best bs
| Branches lst ->
backtrack best (lst # bs))
in
(* initiate the search with no solution in the initial state *)
match backtrack None [initial] with
| None -> None (* nothing was found *)
| Some (x, _) -> Some x (* the best solution found *)
(** Here is the above example encoded. *)
let sum n =
let search (lst, s, m) =
if s = n then
(* solution found, compute the product of [lst] *)
let p = List.fold_left ( * ) 1 lst in
Solution (lst, p)
else
if s + m <= n then
(* split into two states, one that adds [m] to the list and another
that increases [m] *)
Branches [(m::lst, m+s, m); (lst, s, m+1)]
else
(* [m] is too big, no way to proceed, return empty list of branches *)
Branches []
in
backtrack ([], 0, 1) search
;;
(** How to write 10 as a sum of numbers so that their product is as large as possible? *)
sum 10 ;; (* returns Some [3; 3; 2; 2] *)
OCaml happily informs us that the type of backtrack is
'a -> ('a -> ('b, 'c, 'a) backtrack) -> 'b option
This makes sense:
the first argument is the initial state, which has some type 'a
the second argument is the search function, which takes a state of type 'a and
returns either a Solution (x,a) where x has type 'b and a has type 'c,
or Branches lst where lst has type 'a list.