I am actually sitting over a hour on a problem and donĀ“t find a solution for it.
I have this data type:
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
And i have to find a function which converts a given tree in a ordered list. There is also no invariant like that the left child has to be less then the right. I already found a "normal" recursion solution but not a tail recursive solution. I already thought about to build a unordered list and sort it with List.sort, but this uses a merge sort which is not tail recursive. Maybe someone has a good advice.
Thank you!
If you want to traverse the tree in order and return a list, that means our function inorder must have the type 'a tree -> 'a list.
let rec inorder t =
match t with
| Empty -> []
| Node (v, l, r) -> List.append (inorder l) (v :: (inorder r)) (* ! *)
However List.append is in tail position, not inorder. Another problem is we have two calls to inorder. If we put inorder l in tail position, inorder r could not possibly be in tail position - and vice versa.
A neat way to work around this problem is continuation passing style. We take our function above and convert it into a helper function with an extra parameter for our continuation, return
(* convert to helper function, add an extra parameter *)
let rec loop t return =
match t with
| Empty -> ...
| Node (v, l, r) -> ...
The continuation represents "what to do next", so instead of sending values directly out of our function, we must hand them to the continuation instead. That means for the Empty case, we'll return [] - instead of simply []
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) -> ...
For the Node (v, l, r) case, now that we have an extra parameter we can write our own continuation that informs loop what to do next. So to construct our sorted list, we will need to loop l, then loop r (or vice versa), then we can append them. We'll write our program just like this.
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop l ... (* build the left_result *)
loop r ... (* build the right_result *)
return (List.append left_result (v :: right_result))
In this next step, we'll fill in the actual lambda syntax for the continuations.
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop l (fun left ->
loop r (fun right ->
return (List.append left (v :: right))))
Last, we define inorder which is a call to loop with the default continuation, identity.
let identity x =
x
let inorder t =
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop r (fun right ->
loop l (fun left ->
return (List.append left (v :: right))))
in
loop t identity
As you can see loop r (fun right -> ...) is in tail position for the Node branch. loop l (fun left -> ...) is in tail position of the first continuation. And List.append ... is in tail position of the second continuation. Provided List.append is a tail-recursive procedure, inorder will not grow the stack.
Note using List.append could be a costly choice for big trees. Our function calls it once per Node. Can you think of a way to avoid it? This exercise is left for the reader.
In a learning environment, what are my options to provide type signatures for functions?
Standard ML doesn't have top-level type signatures like Haskell. Here are the alternatives I have considered:
Module signatures, which require either a separate signature file, or the type signature being defined in a separate block inside the same file as the module itself. This requires the use of modules, and in any production system that would be a sane choice.
Modules may seem a little verbose in a stub file when the alternative is a single function definition. They both introduce the concept of modules, perhaps a bit early,
Using val and val rec I can have the complete type signature in one line:
val incr : int -> int =
fn i => i + 1
val rec map : ('a -> 'b) -> 'a list -> 'b list =
fn f => fn xs => case xs of
[] => []
| x::ys => f x :: map f ys
Can I have this and also use fun?
If this is possible, I can't seem to get the syntax right.
Currently the solution is to embed the argument types and the result type as such:
fun map (f : 'a -> 'b) (xs : 'a list) : 'b list =
raise Fail "'map' is not implemented"
But I have experienced that this syntax gives the novice ML programmer the impression that the solution either cannot or should not be updated to the model solution:
fun map f [] = []
| map f (x::xs) = f x :: map f xs
It seems then that the type signatures, which are supposed to aid the student, prevents them from pattern matching. I cannot say if this is because they think that the type signatures cannot be removed or if they should not be removed. It is, of course, a matter of style whether they should (and where), but the student should be enabled to explore a style of type inference.
By using a let or local bound function, and shadowing
you can declare the function, and then assign it to a value.
using local for this is more convenient, since it has the form:
local decl in decl end, rather than let decl in expr end,
meaning let's expr, wants a top-level argument f
val map = fn f => let fun map = ... in map end
I don't believe people generally use local, anymore primarily because modules can do anything that local can, and more, but perhaps it is worth considering it as an anonymous module, when you do not want to explain modules yet.
local
fun map (f : 'a -> 'b) (x::rest : 'a list) : 'b list
= f x :: map f rest
| map _ ([]) = []
in
val (map : ('a -> 'b) -> 'a list -> 'b list) = map;
end
Then when it comes time to explain modules, you can declare the structure inside the local, around all of the declarations,
and then remove the local, and try to come up with a situation, where they have coded 2 functions, and it's more appropriate to replace 2 locals, with 1 structure.
local
structure X = struct
fun id x = x
end
in val id = X.id
end
perhaps starting them off with something like the following:
exception ReplaceSorryWithYourAnswer
fun sorry () = raise ReplaceSorryWithYourAnswer
local
(* Please fill in the _'s with the arguments
and the call to sorry() with your answer *)
fun map _ _ = sorry ()
in
val map : ('a -> 'b) -> ('a list) -> ('b list) = map
end
Given any list in Erlang, e.g.:
L = [foo, bar, foo, buzz, foo].
How can I only show the unique items of that list, using a recursive function?
I do not want to use an built-in function, like one of the lists functions (if it exists).
In my example, where I want to get to would be a new list, such as
SL = [bar, buzz].
My guess is that I would first sort the list, using a quick sort function, before applying a filter?
Any suggestions would be helpful. The example is a variation of an exercise in chapter 3 of Cesarini's & Thompson's excellent "Erlang Programming" book.
I propose this one:
unique(L) ->
unique([],L).
unique(R,[]) -> R;
unique(R,[H|T]) ->
case member_remove(H,T,[],true) of
{false,Nt} -> unique(R,Nt);
{true,Nt} -> unique([H|R],Nt)
end.
member_remove(_,[],Res,Bool) -> {Bool,Res};
member_remove(H,[H|T],Res,_) -> member_remove(H,T,Res,false);
member_remove(H,[V|T],Res,Bool) -> member_remove(H,T,[V|Res],Bool).
The member_remove function returns in one pass the remaining tail without all occurrences of the element being checked for duplicate and the test result.
I may do it this way :)
get_unique(L) ->
SortedL = lists:sort(L),
get_unique(SortedL, []).
get_unique([H | T], [H | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, H} | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, _} | Acc]) ->
get_unique(T, [H | Acc]);
get_unique([H | T], Acc) ->
get_unique(T, [H | Acc]);
get_unique([], [{dup, _} | Acc]) ->
Acc;
get_unique([], Acc) ->
Acc.
I think idea might be: check if you already seen the head of list. If so, skip it and recursively check the tail. If not - add current head to results, to 'seen' and recursively check the tail. Most appropriate structure for checking if you already have seen the item is set.
So,i'd propose following:
remove_duplicates(L) -> remove_duplicates(L,[], sets:new()).
remove_duplicates([],Result,_) -> Result;
remove_duplicates([Head|Tail],Result, Seen) ->
case sets:is_element(Head,Seen) of
true -> remove_duplicates(Tail,Result,Seen);
false -> remove_duplicates(Tail,[Head|Result], sets:add_element(Head,Seen))
end.
Use two accumulators. One to keep elements you have seen so far, one to hold the actual result. If you see the item for the first time (not in Seen list) prepend the item to both lists and recurse. If you have seen the item before, remove it from your result list (Acc) before recursing.
-module(test).
-export([uniques/1]).
uniques(L) ->
uniques(L, [], []).
uniques([], _, Acc) ->
lists:reverse(Acc);
uniques([X | Rest], Seen, Acc) ->
case lists:member(X, Seen) of
true -> uniques(Rest, Seen, lists:delete(X, Acc));
false -> uniques(Rest, [X | Seen], [X | Acc])
end.
unique(List) ->
Set = sets:from_list(List),
sets:to_list(Set).
This solution only filters out duplicates from a list. probably requires building upon to make it do what you want.
remove_duplicates(List)->
lists:reverse(removing(List,[])).
removing([],This) -> This;
removing([A|Tail],Acc) ->
removing(delete_all(A,Tail),[A|Acc]).
delete_all(Item, [Item | Rest_of_list]) ->
delete_all(Item, Rest_of_list);
delete_all(Item, [Another_item| Rest_of_list]) ->
[Another_item | delete_all(Item, Rest_of_list)];
delete_all(_, []) -> [].
EDIT
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Windows\System32>erl
Eshell V5.9 (abort with ^G)
1> List = [1,2,3,4,a,b,e,r,a,b,v,3,2,1,g,{red,green},d,2,5,6,1,4,6,5,{red,green}].
[1,2,3,4,a,b,e,r,a,b,v,3,2,1,g,
{red,green},
d,2,5,6,1,4,6,5,
{red,green}]
2> remove_duplicates(List).
[1,2,3,4,a,b,e,r,v,g,{red,green},d,5,6]
3>
Try the following code
-module(util).
-export([unique_list/1]).
unique_list([]) -> [];
unique_list(L) -> unique_list(L, []).
% Base Case
unique_list([], Acc) ->
lists:reverse(Acc);
% Recursive Part
unique_list([H|T], Acc) ->
case lists:any(fun(X) -> X == H end, T) of
true ->
unique_list(lists:delete(H,T), Acc);
false ->
unique_list(T, [H|Acc])
end.
unique(L) -> sets:to_list(sets:from_list(L)).
The simplest way would be to use a function with an "accumulator" that keeps track of what elements you already have.
So you'd write a function like
% unique_acc(Accumulator, List_to_take_from).
You can still have a clean function, by not exporting the accumulator version, and instead exporting its caller:
-module(uniqueness).
-export([unique/1]).
unique(List) ->
unique_acc([], List).
If the list to take from is empty, you're done:
unique_acc(Accumulator, []) ->
Accumulator;
And if it's not:
unique_acc(Accumulator, [X|Xs]) ->
case lists:member(X, Accumulator) of
true -> unique_acc(Accumulator, Xs);
false -> unique_acc([X|Accumulator], Xs)
end.
2 things to note:
-- This does use a list BIF -- lists:member/2. You can easily write this yourself, though.
-- The order of the elements are reversed, from original list to result. If you don't like this, you can define unique/1 as lists:reverse(unique_acc([], List)). Or even better, write a reverse function yourself! (It's easy).