OCaml bits list to tree - ocaml
I have made this following function :
let rec arbre_vers_bits_rec arb l =
match arb with
| Feuille f -> (match f with
| Blanc -> 0 :: 0 :: l;
| Noir -> 0 :: 1 :: l;)
| Noeud(a,b,c,d) -> (
1 ::
arbre_vers_bits_rec a (
arbre_vers_bits_rec b (
arbre_vers_bits_rec c (
arbre_vers_bits_rec d (l))));
);;
let arbre_vers_bits arb =
arbre_vers_bits_rec arb [];;
Which give me a bits list like : [1;0;0;0;1;0;1;0;0]
Now I'm trying to make the reverse function : tree to bits list
So I have made this :
let rec bits_vers_arbres_aux lb res =
match lb with
| [] -> res;
| 1 :: tl -> (Noeud((bits_vers_arbres_aux (sublist 1 9 tl) res),
(bits_vers_arbres_aux (sublist 10 18 tl) res),
(bits_vers_arbres_aux (sublist 19 27 tl) res),
(bits_vers_arbres_aux (sublist 28 35 tl) res)));
| 0 :: a :: 0 :: b :: 0 :: c :: 0 :: d :: tl -> (bits_vers_feuille a b c d);
| _ -> failwith "error";;
let bits_vers_arbres lb =
let a = Noeud(Feuille Blanc, Feuille Blanc, Feuille Blanc, Feuille Blanc) in
bits_vers_arbres_aux lb a;;
with bits_vers_feuille which return me a tree with 4 node a b c d.
I understand how I need to do but I can't figure out how to split the list without using sublist ( it works with bits list like [1;1;...] but not bigger.
sublist :
let rec sublist b e l =
match l with
[] -> failwith "sublist"
| h :: t ->
let tail =
if e = 0 then []
else sublist (b-1) (e-1) t
in
if b > 0 then tail
else h :: tail
My tree type:
type arbre =
Feuille of couleur
| Noeud of arbre * arbre * arbre * arbre
couleur type:
type couleur = Noir | Blanc
What should I try ?
The intuition is that you want to work through the string of bits with the rule that if you see 1 you have a subtree at that point and if you see 0 you have a leaf. This seems pretty close to the definition of a recursive function. The only problem (it seems to me) is in tracking the remainder of the list of bits after you extract a subtree. Hence your function needs to return not only a tree, but also the remaining undecoded bits:
let rec bits_vers_arbres lb =
match lb with
| [] -> failwith "Ill-formed bit string"
| 0 :: bn :: rest -> (Feuille (if bn = 0 then Blanc else Noir), rest)
| 1 :: rest ->
let (a, rest') = bits_vers_arbres rest in
let (b, rest'') = bits_vers_arbres rest' in
. . .
I think this will work, but I haven't finished coding it myself.
I have translated a lot of this to English, because I can read the French, and I can reason out coding problems, but doing both at the same time is really taxing.
type color = White | Black
type tree =
| Leaf of color
| Node of tree * tree * tree * tree
let tree_to_bits t =
let rec aux t bit_list =
match t with
| Leaf White -> 0 :: 0 :: bit_list
| Leaf Black -> 0 :: 1 :: bit_list
| Node (a, b, c, d) ->
1 :: aux a (aux b (aux c (aux d bit_list)))
in
aux t []
let rec bits_to_tree bit_list =
let rec consume_leaves bit_list leaves_acc =
if List.length leaves_acc >= 4 then
(List.rev leaves_acc, bit_list)
else
match bit_list with
| [] | 1 :: _ -> (List.rev leaves_acc, bit_list)
| 0 :: 0 :: rest -> consume_leaves rest (Leaf White :: leaves_acc)
| 0 :: 1 :: rest -> consume_leaves rest (Leaf Black :: leaves_acc)
in
match bit_list with
| [] -> failwith "ill formed"
| 0 :: 0 :: rest -> (Leaf White, rest)
| 0 :: 1 :: rest -> (Leaf Black, rest)
(* A node with at least one leaf! *)
| 1 :: (0 :: _ as rest) ->
print_endline "Found node";
let leaves, rest = consume_leaves rest [] in
Printf.printf "Consumed %d leaves\n" (List.length leaves);
(match leaves with
| [a] ->
let (b, rest') = bits_to_tree rest in
let (c, rest'') = bits_to_tree rest' in
let (d, rest''') = bits_to_tree rest'' in
Node (a, b, c, d), rest'''
| [a; b] ->
let (c, rest') = bits_to_tree rest in
let (d, rest'') = bits_to_tree rest' in
Node (a, b, c, d), rest''
| [a; b; c] ->
let (d, rest') = bits_to_tree rest in
Node (a, b, c, d), rest'
| [a; b; c; d] ->
Node (a, b, c, d), rest)
(* A node that contains a node immediately *)
| 1 :: (1 :: _ as rest) ->
let (a, rest') = bits_to_tree rest in
let (b, rest'') = bits_to_tree rest' in
let (c, rest''') = bits_to_tree rest'' in
let (d, rest'''') = bits_to_tree rest''' in
Node (a, b, c, d), rest''''
It throws all kinds of non-exhaustive pattern matching warnings, and I am as certain that there is a more elegant way to do this as I am that water is wet, but...
─( 12:40:54 )─< command 65 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # t;;
- : tree =
Node (Leaf White, Node (Leaf White, Leaf Black, Leaf White, Leaf Black),
Leaf White, Leaf White)
─( 12:41:22 )─< command 66 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # tree_to_bits t;;
- : int list = [1; 0; 0; 1; 0; 0; 0; 1; 0; 0; 0; 1; 0; 0; 0; 0]
─( 12:44:39 )─< command 67 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # tree_to_bits t |> bits_to_tree;;
Found node
Consumed 1 leaves
Found node
Consumed 4 leaves
- : tree * int list =
(Node (Leaf White, Node (Leaf White, Leaf Black, Leaf White, Leaf Black),
Leaf White, Leaf White),
[])
─( 12:44:47 )─< command 68 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # tree_to_bits t |> bits_to_tree |> fst |> tree_to_bits;;
Found node
Consumed 1 leaves
Found node
Consumed 4 leaves
- : int list = [1; 0; 0; 1; 0; 0; 0; 1; 0; 0; 0; 1; 0; 0; 0; 0]
─( 13:38:17 )─< command 79 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # let t =
let w = Leaf White
and b = Leaf Black
in
Node (Node (w, b, w, b), Node (b, w, b, w),
Node (w, w, b, b), Node (b, b, w, w));;
val t : tree =
Node (Node (Leaf White, Leaf Black, Leaf White, Leaf Black),
Node (Leaf Black, Leaf White, Leaf Black, Leaf White),
Node (Leaf White, Leaf White, Leaf Black, Leaf Black),
Node (Leaf Black, Leaf Black, Leaf White, Leaf White))
─( 13:38:52 )─< command 80 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # tree_to_bits t ;;
- : int list =
[1; 1; 0; 0; 0; 1; 0; 0; 0; 1; 1; 0; 1; 0; 0; 0; 1; 0; 0; 1; 0; 0; 0; 0; 0; 1;
0; 1; 1; 0; 1; 0; 1; 0; 0; 0; 0]
─( 13:39:06 )─< command 81 >───────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # tree_to_bits t |> bits_to_tree;;
Found node
Consumed 4 leaves
Found node
Consumed 4 leaves
Found node
Consumed 4 leaves
Found node
Consumed 4 leaves
- : tree * int list =
(Node (Node (Leaf White, Leaf Black, Leaf White, Leaf Black),
Node (Leaf Black, Leaf White, Leaf Black, Leaf White),
Node (Leaf White, Leaf White, Leaf Black, Leaf Black),
Node (Leaf Black, Leaf Black, Leaf White, Leaf White)),
[])
More Elegant
Having more time to think about this while out on a walk, we end up with a more elegant approach that still passes the same tests as before.
let rec bits_to_tree' = function
| 0 :: 0 :: rest -> Leaf White, rest
| 0 :: 1 :: rest -> Leaf Black, rest
| 1 :: rest ->
let (a, rest' ) = bits_to_tree' rest in
let (b, rest'' ) = bits_to_tree' rest' in
let (c, rest''' ) = bits_to_tree' rest'' in
let (d, rest'''') = bits_to_tree' rest''' in
Node (a, b, c, d), rest''''
| _ -> failwith "Ill-formed bit list"
If the first two elements in the bit list are 0 and 0, this indicates a Leaf White. If 0 and 1, then this indicates a Leaf Black. Either way, we return the rest of the bit list as well.
If the first number is 1, then it indicates a Node. We know a Node contains four trees, so we use a chain of let bindings to recursively call the function on the rest. Each time we get the tree, but also the remaining bit list. Doing this ensures we "consume" the bit list.
If the bit list doesn't start with 0 followed by 0 or 1; or a 1, then the bit list is ill-formed.
The ' suffixes on rest are not necessary, but they demonstrate how we're changing this value. We could just call all of these rest because we don't access previous rest values.
As a further exercise, this could be a locally scoped function, that hides the passing of rest.
let bits_to_tree bit_list =
let rec bits_to_tree' = function
| 0 :: 0 :: rest -> Leaf White, rest
| 0 :: 1 :: rest -> Leaf Black, rest
| 1 :: rest ->
let (a, rest) = bits_to_tree' rest in
let (b, rest) = bits_to_tree' rest in
let (c, rest) = bits_to_tree' rest in
let (d, rest) = bits_to_tree' rest in
Node (a, b, c, d), rest
| _ -> failwith "Ill-formed bit list"
in
bits_to_tree' bit_list |> fst
Related
Why is this OCaml code resulting in a runtime error?
I am trying to run the following code on a coding question website and it says there is a runtime error, but running it on the top-level ocaml seems to work fine. Could there be any source of error in the code? Thanks in advance The question is to find the number of 'good segments' within the given list and a specific number. A good segment is defined as follows: A and B are positive integers such that A < B. x that satisfies A <= x <= B is not an element of the given list. The following are the inputs. n, which is the number of elements in the list that will be given. a, b, c, ... which are the elements of the list. t, which is the number that must be included in the segment. The output should be a single number printed out. Edited Code: let rec drop_value l to_drop = match l with | [] -> [] | hd :: tl -> let new_tl = drop_value tl to_drop in if hd = to_drop then new_tl else hd :: new_tl ;; let rec find_start li t cur_min = match li with | [] -> cur_min | hd :: tl -> let new_min = abs (t - hd) in if new_min = 0 then find_start tl t new_min else if new_min < cur_min && t > hd then find_start tl t new_min else find_start tl t cur_min ;; let rec find_end li t cur_min = match li with | [] -> cur_min | hd :: tl -> let new_min = abs (t - hd) in if new_min = 0 then find_end tl t new_min else if new_min < cur_min && t < hd then find_end tl t new_min else find_end tl t cur_min ;; let rec contains_value l value = match l with | [] -> false | hd :: tl -> if hd = value then true else contains_value tl value ;; let nums = ref [];; let n = read_int () in for i = 1 to n do Scanf.scanf " %d" (fun a -> nums := a :: !nums) done; Scanf.scanf " %d" (fun t -> if contains_value !nums t then print_int 0 else let start = if List.length !nums = 1 then 1 else abs (find_start !nums t 1001 - t) in let finish = find_end (drop_value !nums start) t 1001 + t in if t > start && t < finish then (if start = 1 && List.length ! nums = 1 then print_int ((t - start + 1) * (finish - t) - 1) else print_int ((t - start) * (finish - t) - 1)) else let start = 1 in print_int ((t - start + 1) * (finish - t) - 1)) ;; eg. 5 4 8 13 24 30 10 should give 5 => [9, 10], [9, 11], [9, 12], [10, 11], [10, 12]
You don't describe the exact input format that your code is going to get. This makes it pretty much impossible to debug your code. When I compile and run your code (as m.ml) using the input you describe I see this: $ ./m 5 4 8 13 24 30 10 Fatal error: exception Failure("int_of_string") In fact no matter what format I try for the input I get the same result. So that is probably what is happening at the website. In my experience it always causes more harm than good to use scanf. Combining it with other input functions is probably going to make things worse. If you describe the expected format of the input carefully, somebody on StackOverflow can recommend a way to get your numbers. In the meantime here's a way to read all the numbers on one line: let rec split_at list n = if n = 0 then ([], list) else match list with | [] -> ([], []) | h :: t -> let (a, b) = split_at t (n - 1) in (h :: a, b) in let (nums, t) = let line = read_line () in let nstrs = Str.split (Str.regexp "[ \t][ \t]*") line in match List.map int_of_string nstrs with | [] -> failwith "no numbers" | n :: rest -> if List.length rest <> n + 1 then failwith "bad count" else let (nums, tlist) = split_at rest n in (nums, List.hd tlist) in . . .
Haskell List Comprehensions listA listB -> listC
I have two lists with elements ListA ([String]) and sample positions ListB([Int]) how to create a new ListC ([String]) using list comprehensions? for example: the left number is always more right (see ListB) Step 1: get elem 1, add the head of the ListC ListC = ["a"] Step 2: get elem 2, add the head of the ListC ListC = ["c","a"] Step 3: get elem 1, add the head of the ListC ListC = ["b","c","a"] so the full chain: a b c -> 1 2 1 -> a -> c a -> b c a more templates: ListA::[String] ListB::[int] ListC::[String] ListA ListB ListC a b c -> 3 2 1 -> a b c a b c -> 2 2 1 -> a c b a b c -> 3 1 1 -> b a c a b c -> 1 2 1 -> b c a a b c -> 2 1 1 -> c a b a b c -> 1 1 1 -> c b a this function is to generate valid numeric sequences (note each left element, it is more than the previous one, at least per 1, ie. head is the greatest element) module Main ( main ) where import System.Random main :: IO () randomList :: Int -> [Int] -> StdGen -> [Int] randomList 0 xlist _ = reverse xlist randomList n xlist gen = randomList (n-1) (randomVal : xlist) gen' where (randomVal, gen') = randomR (1,n) gen shuffle :: [Int] -> [String] -> [String] -> [String] shuffle [] _ deckB = deckB shuffle pl deckA deckB = shuffle (tail pl) (hs ++ tail ts) (head ts : deckB) where (hs, ts) = splitAt (pos-1) deckA pos = head pl ranks = ["2","3","4","5","6","7","8","9","T","J","Q","K","A"] suits = ["C","D","H","S"] deck = [rank ++ suit | suit <- suits, rank <- ranks] main = do gen <- newStdGen let len = 52 :: Int let permutationList = randomList len [] gen let newDeck = shuffle permutationList deck [] print permutationList print deck print "-------------------------------------" print newDeck
You chose a complicated way to create the permutations but perhaps that's what the problem domain dictates. The required permutation cannot be created by list comprehensions but can be written with some simple utility functions first write a drop element function dropAt :: Int -> [a] -> [a] dropAt _ [] = [] dropAt n x = let (h,t) = splitAt n x in (init h) ++ t now using this your own picking function pickAt :: [Int] -> [a] -> [a] pickAt _ [] = [] pickAt [] _ = [] pickAt (n:ns) xs = xs!!(n-1) : pickAt ns (dropAt n xs) gives you the reverse order though, run through reverse > reverse $ pickAt [2,1,1] ['a','b','c'] "cab" > reverse $ pickAt [1,1,1] ['a','b','c'] "cba"
Adding up two lists in OCaml
Assume we use a list to represent number reversely, each node is a digit inside the number. So [1;2;3;4;5] is the number 54321 Now we want to add up two such lists, e.g., adding [1;2] and [3;4], we get [4;6], which is the number 64. here is my code: let add l1 l2 = let rec add_to up acc = function | [] -> if up = 1 then 1::acc else acc | hd::tl -> let s = hd+up in if s >= 10 then add_to 1 ((s-10)::acc) tl else List.rev_append tl (s::acc) and add_up up acc = function | [], [] -> if up = 1 then 1::acc else acc | l, [] | [], l -> (add_to up [] l) # acc | hd1::tl1, hd2::tl2 -> let s = hd1+hd2+up in if s >= 10 then add_up 1 ((s-10)::acc) (tl1, tl2) else add_up 0 (s::acc) (tl1, tl2) in List.rev (add_up 0 [] (l1, l2)) The idea is very simple, just add two hds from two lists, and carry 1 to the next if the sum of two hds are bigger or equal with 10. However, I think my code does not look beautiful. we have the redundant part of the logic to solve the carry. I have to do # on two lists. Anyone can help me to make it more beautiful?
I think the trick is to generalize. The essence is to add three things, not two. let sum a b = let rec isum a b c = match a, b with | [], [] -> if c = 0 then [] else [c] | [], x | x, [] -> isum [0] x c | ah :: at, bh :: bt -> let s = ah + bh + c in (s mod 10) :: isum at bt (s / 10) in isum a b 0 This code isn't tail recursive. A tail recursive version will be a little less elegant. Note: I assume you use [] to represent 0.
Rotate list in OCaml
I want to write a function rotate n l that returns a new list containing the same elements as l, "rotated" n times to the right. For example, rotate 0 [1;2;3;4] should return [1;2;3;4] rotate 1 [1;2;3;4] should return [4;1;2;3] rotate 2 [1;2;3;4] should return [3;4;1;2] rotate 3 [1;2;3;4] should return [2;3;4;1] rotate 4 [1;2;3;4] should return [1;2;3;4] etc. The behavior of rotate n for n less than 0 should be the same as for n equal to 0. I want to write this without using the list concatenation operator # from Pervasives. Update: Here is the rotation function I wrote: let rot1 l = let rec iterate acc = function [] -> [] | [x] -> x :: List.rev acc | x :: l -> iterate (x :: acc) l in iterate [] l;; But I want it to do the same thing without using List.rev. Is there a way to do this?
Agree with Jeffrey, show us what you tried. Here's a small hint in case you need to get started. If you can write a function that performs only 1 rotation i.e. equivalent to rotate 1 l. (I call it one_rot). Then rotate can be easily defined as: let rec rotate n l = match n with | 0 -> l | _ -> rotate (n-1) (one_rot l) Your solution is perfectly fine for me. Not sure what you have against List.rev but here's a completely stand alone one_rot. Note that we have to sacrifice tail recursion. You could probably make this quite a bit shorter too: let rec last = function | [] -> assert false | [x] -> x | x::xs -> last xs let rec init = function | [] -> [] | [x] -> [] | x::xs -> x::(init xs) let one_rot l = (last l)::(init l)
This problem can be solved by combining these 3 functions: cat(skip(list, places), take(list, places)) The implementation looks like: let rec cat = function ([], y) -> y | (x::xs, y) -> x :: cat (xs, y) let rec skip = function ([], _) -> [] | (_::xs as xs1, c) -> if c > 0 then skip(xs, c - 1) else xs1 let rec take = function ([], _) -> [] | (x::xs, c) -> if c > 0 then x :: take(xs, c - 1) else [] let cycle l i = cat (skip (l, i), take (l, i)) cycle ([1;2;3;4;5;6], 3);; val it : int list = [4; 5; 6; 1; 2; 3]
How to write a function to get the position of the smallest int in a list?
The prototype must be: listMinPos(lst) I'm able to write the same using two arguments, (list and index), but am not able to even think how it can be possible using only the list argument. The following must hold: only 1 argument (the list). no external libraries. function should be recursive (no 'let' inside the function)
I have a solution that cheats slightly : I return the position of the smallest element, but not only. The value of the smallest element is also returned. let rec min_pos = function | [] -> invalid_arg "min_pos" | [x] -> (0, x) | hd::tl -> let p, v = min_pos tl in if hd < v then (0, hd) else (p + 1, v) (As Pascal Cuoq noticed, there is still one let p, v = .. in .. remaining; it can be replaced by match .. with p, v -> ... See comments). Another solution that relax your second constraint (no external library) : let rec min_pos = function | [] -> invalid_arg "min_pos" | [x] -> 0 | hd::tl -> let p = min_pos tl in if hd < List.nth tl p then 0 else p + 1 It's inefficient but I don't think you can do much better without passing more information. Edit I didn't understand this was a homework. Is there a policy against giving complete solution to homework questions ? Anyway, in this case I suppose that the list of restriction you gave is not, as I supposed, a creativity-forcing constraint, and I suppose that you can break them if it gives better solutions. I therefore propose, using local let : let min_pos li = let rec min_pos = function | [] -> invalid_arg "min_pos" | [x] -> (0, x) | hd::tl -> let p, v = min_pos tl in if hd < v then (0, hd) else (p + 1, v) in fst (min_pos li) And a tail-recursive version : let min_pos li = let rec min_pos mini mpos cur_pos = function | [] -> mpos | hd::tl -> if hd < mini then min_pos hd cur_pos (cur_pos + 1) tl else min_pos mini mpos (cur_pos + 1) tl in match li with | [] -> invalid_arg "min_pos" | hd::tl -> min_pos hd 0 1 tl