Backtracking in Standard ML - standards
I have seen in my SML manual the following function, which computes how many coins of a particular kind are needed for a particular change.
For example change [5,2] 16 =[5,5,2,2,2] because with two 5-coins and three 2-coins one gets 16.
the following code is a backtracking approach:
exception Change;
fun change _ 0 = nil|
change nil _ = raise Change|
change (coin::coins)=
if coin>amt then change coins amt
else (coin:: change (coin::coins) (amt-coin))
handle Change=> change coins amt;
It works, but I don't understand how exactly.
I know what backtracking is, I just don't understand this particular function.
What I understood so far: If amt is 0, it means our change is computed, and there is nothing to be cons'd onto the final list.
If there are no more coins in our 'coin-list', we need to go back one step.
This is where I get lost: how exactly does raising an exception helps us go back?
as I see it, the handler tries to make a call to the change function, but shouldn't the "coins" parameter be nil? therefore entering an infinite loop? why does it "go back"?
The last clause is pretty obvious to me: if the coin-value is greater than the amount left to change, we use the remaining coins to build the change. If it is smaller than the amount left, we cons it onto the result list.
This is best seen by writing out how evaluation proceeds for a simple example. In each step, I just replace a call to change by the respective right-hand side (I added extra parentheses for extra clarity):
change [3, 2] 4
= if 3 > 4 then ... else ((3 :: change [3, 2] (4 - 3)) handle Change => change [2] 4)
= (3 :: change [3, 2] 1) handle Change => change [2] 4
= (3 :: (if 3 > 1 then change [2] 1 else ...)) handle Change => change [2] 4
= (3 :: change [2] 1) handle Change => change [2] 4
= (3 :: (if 2 > 1 then change [] 1 else ...)) handle Change => change [2] 4
= (3 :: (raise Change)) handle Change => change [2] 4
At this point an exception has been raised. It bubbles up to the current handler so that evaluation proceeds as follows:
= change [2] 4
= if 2 > 4 then ... else ((2 :: change [2] (4 - 2)) handle Change => change [] 4)
= (2 :: change [2] 2) handle Change => change [] 4
= (2 :: (if 2 > 2 then ... else ((2 :: change [2] (2 - 2)) handle Change => change [] 2)) handle Change => change [] 4
= (2 :: ((2 :: change [2] 0) handle Change => change [] 2)) handle Change => change [] 4
= (2 :: ((2 :: []) handle Change => change [] 2)) handle Change => change [] 4
= (2 :: (2 :: [])) handle Change => change [] 4
= 2 :: 2 :: []
No more failures up to here, so we terminate successfully.
In short, every handler is a backtracking point. At each failure (i.e., raise) you proceed at the innermost handler, which is the last backtracking point. Each handler itself is set up such that it contains the respective call to try instead.
You can rewrite this use of exceptions into using the 'a option type instead. The original function:
exception Change;
fun change _ 0 = []
| change [] _ = raise Change
| change (coin::coins) amt =
if coin > amt
then change coins amt
else coin :: change (coin::coins) (amt-coin)
handle Change => change coins amt;
In the modified function below, instead of the exception bubbling up, it becomes a NONE. One thing that becomes slightly more apparent here is that coin only occurs in one of the two cases (where in the code above it always occurs but is reverted in case of backtracking).
fun change' _ 0 = SOME []
| change' [] _ = NONE
| change' (coin::coins) amt =
if coin > amt
then change' coins amt
else case change' (coin::coins) (amt-coin) of
SOME result => SOME (coin :: result)
| NONE => change' coins amt
Another way to demonstrate what happens is by drawing a call tree. This does not gather the result as Andreas Rossberg's evaluation by hand, but it does show that only the times change is taking an else-branch is there a possibility to backtrack, and if a backtrack occurs (i.e. NONE is returned or an exception is thrown), don't include coin in the result.
(original call ->) change [2,5] 7
\ (else)
`-change [2,5] 5
/ \ (else)
___________________/ `-change [2,5] 3
/ / \ (else)
/ / `-change [2,5] 1
`-change [5] 5 / \ (then)
\ (else) / `-change [5] 1
`-change [] 0 / \ (then)
\ / `-change [] 1
`-SOME [] `-change [5] 3 \ (base)
\ (then) `-NONE
`-change [] 3
\
`-NONE
Source: https://www.cs.cmu.edu/~rwh/introsml/core/exceptions.htm
The expression exp handle match is an exception handler. It is
evaluated by attempting to evaluate exp. If it returns a value, then
that is the value of the entire expression; the handler plays no role
in this case. If, however, exp raises an exception exn, then the
exception value is matched against the clauses of the match (exactly
as in the application of a clausal function to an argument) to
determine how to proceed. If the pattern of a clause matches the
exception exn, then evaluation resumes with the expression part of
that clause. If no pattern matches, the exception exn is re-raised so
that outer exception handlers may dispatch on it. If no handler
handles the exception, then the uncaught exception is signaled as the
final result of evaluation. That is, computation is aborted with the
uncaught exception exn.
In more operational terms, evaluation of exp handle match proceeds by
installing an exception handler determined by match, then evaluating
exp. The previous binding of the exception handler is preserved so
that it may be restored once the given handler is no longer needed.
Raising an exception consists of passing a value of type exn to the
current exception handler. Passing an exception to a handler
de-installs that handler, and re-installs the previously active
handler. This ensures that if the handler itself raises an exception,
or fails to handle the given exception, then the exception is
propagated to the handler active prior to evaluation of the handle
expression. If the expression does not raise an exception, the
previous handler is restored as part of completing the evaluation of
the handle expression.
Related
F# define search function
I am new to F# and am having trouble with my code. Its a simple problem to define a function, search, with that take a boolean function and a list and return an index. So for example: > search (fun x -> x > 10) [ 2; 12; 3; 23; 62; 8; 2 ];; val it : int = 1 > search (fun s -> s < "horse") [ "pig"; "lion"; "horse"; "cow"; "turkey" ];; val it : int = 3 What I have as of right now finds the right match but what I cant figure out is how to return a number instead of the rest of the list. I know I'm getting the list instead of a value back because I wrote "if f head then list". What I don't know is what I should put there instead or if what I have is not going to get the result I want. Below is the code I have written. let rec search f list = match list with | [] -> [-1] | head::tail -> if f head then list else search f tail
Returning a number is easy, you just... return it. Your problem is that you don't have a number to return, because you can't derive it directly from the current state. You have to keep track of the number yourself, using some internal state variable. When using recursion you change state by calling your function recursively with "modified" arguments. You're already doing that with the list here. To keep internal state in a recursive function you have to introduce another argument, but not expose it outside. You can solve that by using an internal recursive helper function. Here's one that keeps track of the previous item and returns that when it encounters a match: let search f list = let rec loop list prev = match list with | [] -> None | head::tail -> if f head then prev else loop tail (Some head) in loop list None That's a silly example, but I don't want to just solve your homework for you, because then you wouldn't learn anything. Using this you should be able to figure out how to keep a counter of which position the current item is in, and return that when it matches. Good luck!
You typically define an inner recursive function to help you carry state as you loop, and then call the inner function with an initial state. let search predicate list = let rec loop list index = match list with | [] -> -1 | head::tail -> if predicate head then index else loop tail (index + 1) loop list 0
Erlang: How to create a function that returns a string containing the date in YYMMDD format?
I am trying to learn Erlang and I am working on the practice problems Erlang has on the site. One of them is: Write the function time:swedish_date() which returns a string containing the date in swedish YYMMDD format: time:swedish_date() "080901" My function: -module(demo). -export([swedish_date/0]). swedish_date() -> [YYYY,MM,DD] = tuple_to_list(date()), string:substr((integer_to_list(YYYY, 3,4)++pad_string(integer_to_list(MM))++pad_string(integer_to_list(DD)). pad_string(String) -> if length(String) == 1 -> '0' ++ String; true -> String end. I'm getting the following errors when compiled. demo.erl:6: syntax error before: '.' demo.erl:2: function swedish_date/0 undefined demo.erl:9: Warning: function pad_string/1 is unused error How do I fix this?
After fixing your compilation errors, you're still facing runtime errors. Since you're trying to learn Erlang, it's instructive to look at your approach and see if it can be improved, and fix those runtime errors along the way. First let's look at swedish_date/0: swedish_date() -> [YYYY,MM,DD] = tuple_to_list(date()), Why convert the list to a tuple? Since you use the list elements individually and never use the list as a whole, the conversion serves no purpose. You can instead just pattern-match the returned tuple: {YYYY,MM,DD} = date(), Next, you're calling string:substr/1, which doesn't exist: string:substr((integer_to_list(YYYY,3,4) ++ pad_string(integer_to_list(MM)) ++ pad_string(integer_to_list(DD))). The string:substr/2,3 functions both take a starting position, and the 3-arity version also takes a length. You don't need either, and can avoid string:substr entirely and instead just return the assembled string: integer_to_list(YYYY,3,4) ++ pad_string(integer_to_list(MM)) ++ pad_string(integer_to_list(DD)). Whoops, this is still not right: there is no such function integer_to_list/3, so just replace that first call with integer_to_list/1: integer_to_list(YYYY) ++ pad_string(integer_to_list(MM)) ++ pad_string(integer_to_list(DD)). Next, let's look at pad_string/1: pad_string(String) -> if length(String) == 1 -> '0' ++ String; true -> String end. There's a runtime error here because '0' is an atom and you're attempting to append String, which is a list, to it. The error looks like this: ** exception error: bad argument in operator ++/2 called as '0' ++ "8" Instead of just fixing that directly, let's consider what pad_string/1 does: it adds a leading 0 character if the string is a single digit. Instead of using if to check for this condition — if isn't used that often in Erlang code — use pattern matching: pad_string([D]) -> [$0,D]; pad_string(S) -> S. The first clause matches a single-element list, and returns a new list with the element D preceded with $0, which is the character constant for the character 0. The second clause matches all other arguments and just returns whatever is passed in. Here's the full version with all changes: -module(demo). -export([swedish_date/0]). swedish_date() -> {YYYY,MM,DD} = date(), integer_to_list(YYYY) ++ pad_string(integer_to_list(MM)) ++ pad_string(integer_to_list(DD)). pad_string([D]) -> [$0,D]; pad_string(S) -> S. But a simpler approach would be to use the io_lib:format/2 function to just format the desired string directly: swedish_date() -> io_lib:format("~w~2..0w~2..0w", tuple_to_list(date())). First, note that we're back to calling tuple_to_list(date()). This is because the second argument for io_lib:format/2 must be a list. Its first argument is a format string, which in our case says to expect three arguments, formatting each as an Erlang term, and formatting the 2nd and 3rd arguments with a width of 2 and 0-padded. But there's still one more step to address, because if we run the io_lib:format/2 version we get: 1> demo:swedish_date(). ["2015",["0",56],"29"] Whoa, what's that? It's simply a deep list, where each element of the list is itself a list. To get the format we want, we can flatten that list: swedish_date() -> lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))). Executing this version gives us what we want: 2> demo:swedish_date(). "20150829" Find the final full version of the code below. -module(demo). -export([swedish_date/0]). swedish_date() -> lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))). UPDATE: #Pascal comments that the year should be printed as 2 digits rather than 4. We can achieve this by passing the date list through a list comprehension: swedish_date() -> DateVals = [D rem 100 || D <- tuple_to_list(date())], lists:flatten(io_lib:format("~w~2..0w~2..0w", DateVals)). This applies the rem remainder operator to each of the list elements returned by tuple_to_list(date()). The operation is needless for month and day but I think it's cleaner than extracting the year and processing it individually. The result: 3> demo:swedish_date(). "150829"
There are a few issues here: You are missing a parenthesis at the end of line 6. You are trying to call integer_to_list/3 when Erlang only defines integer_to_list/1,2. This will work: -module(demo). -export([swedish_date/0]). swedish_date() -> [YYYY,MM,DD] = tuple_to_list(date()), string:substr( integer_to_list(YYYY) ++ pad_string(integer_to_list(MM)) ++ pad_string(integer_to_list(DD)) ). pad_string(String) -> if length(String) == 1 -> '0' ++ String; true -> String end.
In addition to the parenthesis error on line 6, you also have an error on line 10 where yo use the form '0' instead of "0", so you define an atom rather than a string. I understand you are doing this for educational purpose, but I encourage you to dig into erlang libraries, it is something you will have to do. For a common problem like this, it already exists function that help you: swedish_date() -> {YYYY,MM,DD} = date(), % not useful to transform into list lists:flatten(io_lib:format("~2.10.0B~2.10.0B~2.10.0B",[YYYY rem 100,MM,DD])). % ~X.Y.ZB means: uses format integer in base Y, print X characters, uses Z for padding
Why do I get a weird data type in sml? (?.X! instr)
datatype 'a instr = Put of 'a|Get|Restore; fun makeCell (n:int):('a instr->unit)= let val stack = ref [] in (fn (instruction:'a instr)=> case instruction of Put (x) => ((stack := x :: !stack)) |Get => stack := [] |Restore => (stack := [])) end; val alice = makeCell 0; alice (Put (3)); alice (Put 3); alice (Get); alice (Get); it returns an error when i build: val alice = fn : ?.X1 instr -> unit /usr/local/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0 raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27 /Users/Carl/Desktop/assignment 4.sml:113.1-113.16 Error: operator and operand don't agree [literal] operator domain: ?.X1 instr operand: int instr in expression: alice (Put 3) What Should I do to fix this problem? I have tried different approaches, but none of them have worked.
Types like ?.X1 are created when the value restriction is violated. Your definition of alice creates a violation because it defines alice as something other than a value. (Your definition is a function application). Hence your alice can't be fully polymorphic. Here's a definition that is closer: fun alice x = (makeCell 0) x This modification of the definition is called eta expansion. Unfortunately, this definition makes a new cell for each call. (Your current definitions don't allow this to be observed, however.) Here's a definition that works for your test code and uses a single cell: val alice : int instr -> unit = makeCell 0 It doesn't make sense for alice to be fully polymorphic while using just a single ref cell. A single cell can contain values of only one type.
Erlang sudoku solver - How to find the empty spots and try possible values recursively
I have been busy with a sudoku solver in Erlang yesterday and today. The working functionality I have now is that I can check if a sudoku in the form of a list, e.g., [6,7,1,8,2,3,4,9,5,5,4,9,1,7,6,3,2,8,3,2,8,5,4,9,1,6,7,1,3,2,6,5,7,8,4,9,9,8,6,4,1,2,5,7,3,4,5,7,3,9,8,6,1,2,8,9,3,2,6,4,7,5,1,7,1,4,9,3,5,2,8,6,2,6,5,7,8,1,9,3,4]. is valid or not by looking at the constraints (no duplicates in squares, rows, and columns). This function is called valid(S) which takes a sudoku S and returns true if it is a valid sudoku and false if it is not. The function ignores 0's, which are used to represent empty values. This is an example of the same sudoku with some random empty values: [0,7,1,8,2,3,4,0,5,5,4,9,0,7,6,3,2,8,3,0,8,5,0,9,1,6,7,1,3,2,6,5,7,8,4,9,0,8,6,4,1,2,5,7,0,4,5,7,3,9,8,6,1,0,8,9,3,2,6,4,7,5,1,7,1,4,9,3,0,2,8,6,2,6,5,7,8,1,9,3,4]. The next step is to find the first 0 in the list, and try a value from 1 to 9 and check if it produces a valid sudoku. If it does we can continue to the next 0 and try values there and see if it is valid or not. Once we cannot go further we go back to the previous 0 and try the next values et cetera until we end up with a solved sudoku. The code I have so far looks like this (based on someone who got it almost working): solve(First,Nom,[_|Last]) -> try_values({First,Nom,Last},pos()). try_values(_,[]) -> {error, "No solution found"}; try_values({First,Nom,Last},[N|Pos]) -> case valid(First++[N]++Last) of true -> case solve({First++[N]},Nom,Last) of {ok,_} -> {ok, "Result"}; {error,_} -> try_values({First,N,Last},Pos) end; false -> try_values({First,N,Last},Pos) end. pos() is a list consisting of the values from 1 to 9. The idea is that we enter an empty list for First and a Sudoku list for [_|Last] in which we look for a 0 (Nom?). Then we try a value and if the list that results is valid according to our function we continue till we fail the position or have a result. When we fail we return a new try_values with remaining (Pos) values of our possibitilies. Naturally, this does not work and returns: 5> sudoku:solve([],0,S). ** exception error: bad argument in operator ++/2 called as {[6]} ++ [1,1,8,2,3,4,0,5,5,4,9,0,7,6,3,2,8,3,2,8,5,4,9,1,6,7,1,3,2|...] in call from sudoku:try_values/2 (sudoku.erl, line 140) in call from sudoku:try_values/2 (sudoku.erl, line 142) With my inexperience I cannot grasp what I need to do to make the code logical and working. I would really appreciate it if someone with more experience could give me some pointers.
try_values([], []) -> error("No solution found"); try_values([Solution], []) -> Solution; try_values(_, []) -> error("Bad sudoku: multiple solutions"); try_values(Heads, [0|Tail]) -> NewHeads = case Heads of [] -> [[P] || P <- pos()]; _ -> [Head++[P] || P <- pos(), Head <- Heads] end, ValidHeads = [Head || Head <- NewHeads, valid(Head++Tail)], try_values(ValidHeads, Tail); try_values([], [H|Tail]) -> try_values([[H]], Tail); try_values(Heads, [H|Tail]) -> try_values([Head++[H] || Head <- Heads], Tail). solve(Board) -> case valid(Board) of true -> try_values([], Board); false -> error("No solution found") end. try_values does what you described. It builds solution by going through Board, trying all possible solutions (from pos()) when it finds 0 and collecting valid solutions in ValidHeads to pass them further to continue. Thus, it goes all possible ways, if at some point there are multiple valid sudoku they all will be added to Heads and will be tested on validity on following steps. solve is just a wrapper to call try_values([], Board). Basically, the way to iterate recursively over 0's is to skip all non-zeros (2 last try_values expression) and do the job on zeros (fourth try_values expression). First three try_values expressions check if solution is exist and single and return it in that case.
Why does not init:stop() terminate directly?
My code for display all days in this year. I don't understand why if NewSec =< EndSec -> init:stop() end did not execute the first time in run_calendar? I expect init:stop() could be executed first time but it is not. What is wrong? Code: -module(cal). -export([main/0]). main() -> StartSec = calendar:datetime_to_gregorian_seconds({{2009,1,1},{0,0,0}}), EndSec = calendar:datetime_to_gregorian_seconds({{2009,12,31},{0,0,0}}), run_calendar(StartSec,EndSec). run_calendar(CurSec, EndSec) -> {Date,_Time} = calendar:gregorian_seconds_to_datetime(CurSec), io:format("~p~n", [Date]), NewSec = CurSec + 60*60*24, if NewSec =< EndSec -> init:stop() end, run_calendar(NewSec, EndSec). Result: wk# erlc cal.erl wk# erl -noshell -s cal main {2009,1,1} {2009,1,2} {2009,1,3} {2009,1,4} {2009,1,5} ... {2009,12,22} {2009,12,23} {2009,12,24} {2009,12,25} {2009,12,26} {2009,12,27} {2009,12,28} {2009,12,29} {2009,12,30} {2009,12,31} wk#
I believe that init:stop() is an asynchronous process that will attempt to shut down the runtime smoothly. According to the docs, "All applications are taken down smoothly, all code is unloaded, and all ports are closed before the system terminates." It probably takes a while to actually stop, because you have an actively running process. If you change "init:stop()" to "exit(stop)", it will terminate immediately: 3> cal:main(). {2009,1,1} ** exception exit: stop in function cal:run_calendar/2
Init:stop is asynchronous and it will take time to quit. An alternate way would be to wrap up the test in the call itself and use pattern matching to terminate the loop: -module(cal). -export([main/0]). main() -> StartSec = calendar:datetime_to_gregorian_seconds({{2009,1,1},{0,0,0}}), EndSec = calendar:datetime_to_gregorian_seconds({{2009,12,31},{0,0,0}}), run_calendar(false, StartSec, EndSec). run_calendar(true, _StartSec, _EndSec) -> finished; run_calendar(false, CurSec, EndSec) -> {Date,_Time} = calendar:gregorian_seconds_to_datetime(CurSec), io:format("~p~n", [Date]), NewSec = CurSec + 60*60*24, run_calendar(NewSec =< EndSec, NewSec, EndSec). (or something similar, hopefully you get the idea)
You have a mistake in your if statement You said if NewSec =< EndSec -> init:stop() end, This is incorrect. You have to write something like: if A =< B -> do something ...; true -> do something else end The if syntax is if Condition1 -> Actions1; Condition2 -> Actions2; ... end One of these conditions must always be true. Why is this? Erlang is a functional language, not a statement language. In an functional language every expression must have a value. if is an expression, so it must have a value. The value of (if 2 > 1 -> 3 end) is 3 but what is the value of (if 1 > 2 -> 3 end) - answer it has no value - but it must have a value everything must have a value. In a statement language everything is evaluated for its side effect -so this would be a valid construction. In Erlang you will generate an exception. So your code generates an exception - which you don't trap so you don't see it and init:stop() never gets called ...