Pattern matching nested tuples in ocaml - recursion

I'm trying to recursively go through a nested list of files and folders. While I do that I want to print the names of files and folders I visit, but I am doing something very wrong. This is what I have:
type 'a fileTree =¬
| File of 'a¬
| Folder of 'a * ('a fileTree list)
let printFiles tree =
let rec visit tree = function
| [] -> print_string "Done"
| File f :: t -> visit t
| Folder (name, contents) :: t -> visit contents
in
visit tree
Doing that I get
Error: This expression has type 'a fileTree list -> unit but an expression was expected of type unit
for line (File f :: t -> visit t).
What am I doing wrong?
EDIT 1
The code is now
let printFiles tree =
let rec visit = function
| File file -> Printf.printf "file: %s\n" file
| Folder (name, contents) ->
Printf.printf "folder: %s\n" name;
List.iter visit contents
in
List.iter visit tree
But I still get this error for the last line:
Error: This function has type ('a -> unit) -> 'a list -> unit
It is applied to too many arguments; maybe you forgot a `;'

You forget parenthesis here:
print_string "File " ^ f
it is evaluated as (print_string "File ") ^ f, but what you're expecting is
print_string ("File " ^ f)
The same is with "Folder" case.
Update
In the updated example, you have a function of two arguments applied to one. I suppose, that instead of:
let rec visit tree = function
You want to write
let rec visit = function
which is equivalent to
let rec visit tree = match tree with

The problem is that you've written visit as a function over lists but called it on a file tree.
Let's change it to a function over trees and use List.iter to travese lists:
let print_files tree =
let rec visit = function
| File file ->
Printf.printf "file: %s\n" file
| Folder (name, contents) ->
Printf.printf "folder: %s\n" name;
List.iter visit contents in
visit tree

I solved it in the following way in the end:
let writeFilesFromTree tree =
let rec visit = function
| [] -> print_string "-\n"
| File f :: t -> Printf.printf "file: %s\n" f ; visit t
| Folder (name, contents) :: t ->
Printf.printf "name: %s\n" name ;
visit contents ;
visit t in
visit tree;;
It still doesn't feel like an optimal solution at all, and I have the feeling I am sabotaging tail recursion with the last two consecutive calls to visit.

Related

How to iterate a stream in Ocaml

I am trying to iterate through a stream in order to print the content.
type 'a stream = Nil | Cons of 'a * 'a stream thunk and 'a thunk = unit -> 'a
This is where my function is called
|> iter_stream ~f:(fun (f,c,l) -> printf "%s %s %s\n" f c l)
And this is the type
let rec iter_stream st ~f
(* val iter_stream : 'a stream -> ('a -> unit) -> unit *)
I can't seem to find any examples on how to implement it. The only idea I have is to think about it like a list which is obviously wrong since I get type errors.
let rec iter_stream st ~f =
match st with
| None -> ()
| Some(x, st') -> f x; iter_stream st' ~f
Your stream is extremely similar to a list, except that you need to call a function to get the tail of the list.
Your proposed code has many flaws. The main two flaws that I see are:
You're using the constructors None and Some while a stream has constructors Nil and Cons.
You're not calling a function to get the tail of the stream. Note that in Cons (a, b), b is a "stream thunk", i.e., it's a function that you can call to get a stream.
(Perhaps these are the only two flaws :-)
I hope this helps.

Tree to ordered list with tail recursion

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.

Why am I getting an error in first case but not in second?

I started learning OCaml recently and came across the following problem:
*Write a function last : 'a list -> 'a option that returns the last element of a list. *
I tried the following code:
# let rec last = function
| [] -> None
| _ :: t -> last t
| [x] -> Some x;;
I got the following response:
Characters 65-68:
Warning 11: this match case is unused.
val last : 'a list -> 'a option = <fun>
But the following code compiles without an error:
# let rec last = function
| [] -> None
| [x] -> Some x
| _ :: t -> last t;;
giving the response
val last : 'a list -> 'a option = <fun>
So, my doubt is why just by changing the order I am getting the error?
Any remarks and guidance will be highly appreciated.
I asked this question on programmers.stackexchange As per suggestion I am asking on overflow.
in this line,
| _ :: t -> last t
what is t? it's a list!. That means it could either be a cons cell of (a :: a list), or it could be []. Since this case, along with the first, now match every possible list, the third case cannot be reached.

How to convert a string to integer list in ocaml?

I need to pass two list as command line arguments in ocaml.
I used the following code to access it in the program.
let list1=Sys.argv.(1);;
let list2=Sys.argv.(2);;
I need to have the list1 and list2 as list of integers.
I am getting the error
This expression has type string but an expression was expected of type
int list
while processing.
How can I convert that arguments to a list of integers.
The arguments are passed in this format [1;2;3;4] [1;5;6;7]
Sys.argv.(n) will always be a string. You need to parse the string into a list of integers. You could try something like this:
$ ocaml
OCaml version 4.01.0
# #load "str.cma";;
# List.map int_of_string (Str.split (Str.regexp "[^0-9]+") "[1;5;6;7]");;
- : int list = [1; 5; 6; 7]
Of course this doesn't check the input for correct form. It just pulls out sequences of digits by brute force. To do better you need to do some real lexical analysis and simple parsing.
(Maybe this is obvious, but you could also test your function in the toplevel (the OCaml read-eval-print loop). The toplevel will handle the work of making a list from what you type in.)
As Sys.argv is a string array, you need to write your own transcription function.
I guess the simplest way to do this is to use the Genlex module provided by the standard library.
let lexer = Genlex.make_lexer ["["; ";"; "]"; ]
let list_of_string s =
let open Genlex in
let open Stream in
let stream = lexer (of_string s) in
let fail () = failwith "Malformed string" in
let rec aux acc =
match next stream with
| Int i ->
( match next stream with
| Kwd ";" -> aux (i::acc)
| Kwd "]" -> i::acc
| _ -> fail () )
| Kwd "]" -> acc
| _ -> fail ()
in
try
match next stream with
| Kwd "[" -> List.rev (aux [])
| _ -> fail ()
with Stream.Failure -> fail ()
let list1 = list_of_string Sys.argv.(1)
let list2 = list_of_string Sys.argv.(2)
Depending on the OCaml flavor you want to use, some other library may look more interesting. If you like yacc, Menhir may solve your problem in a few lines of code.

Why doesn't my F# map implementation compile

I've started learning F# and I'd like to write my own map function using tail-recursion. Here is what I have
let my_map ff list =
let rec mapAcc ff_inner list_inner acc =
match list_inner with
| [] -> acc
| front::rest -> mapAcc( ff_inner rest (ff_inner(front) :: acc) ) //error
mapAcc ff list []
It would be called like this:
let list = my_map (fun x -> x * 2) [1;2;3;4;5] // expect [2;4;6;8;10]
I get an compilation error message on the second condition that says Type mismatch. Expecting a 'a but given a 'b list -> 'a -> 'a The resulting type would be infinite when unifying ''a' and ''b list -> 'a -> 'a'
I don't know what this error message means. I'm not sure how this can be infinite if I am passing the rest in the recursive call to mapAcc.
Note: I realize I'm rebuilding the list backwards. I'm ignoring that for now.
Just remove the parenthesis when the function calls itself:
let my_map ff list =
let rec mapAcc ff_inner list_inner acc =
match list_inner with
| [] -> acc
| front::rest -> mapAcc ff_inner rest (ff_inner(front) :: acc)
mapAcc ff list []
otherwise everything contained there is interpreted as a single parameter and ff_inner as a function call with the rest as parameters.

Resources