OCaml error: wrong type of expression in constructor - ocaml

I have a function save that take standard input, which is used individually like this:
./try < input.txt (* save function is in try file *)
input.txt
2
3
10 29 23
22 14 9
and now i put the function into another file called path.ml which is a part of my interpreter. Now I have a problem in defining the type of Save function and this is because save function has type in_channel, but when i write
type term = Save of in_channel
ocamlc complain about the parameter in the command function.
How can i fix this error? This is the reason why in my last question posted on stackoverflow, I asked for the way to express a variable that accept any type. I understand the answers but actually it doesn't help much in make the code running.
This is my code:
(* Data types *)
open Printf
type term = Print_line_in_file of int*string
| Print of string
| Save of in_channel (* error here *)
;;
let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i = n then begin
close_in ic;
(line)
end else aux (succ i)
| None ->
close_in ic;
failwith "end of file reached"
in
aux 1
(* get all lines *)
let k = ref 1
let first = ref ""
let second = ref ""
let sequence = ref []
let append_item lst a = lst # [a]
let save () =
try
while true do
let line = input_line stdin in
if k = ref 1
then
begin
first := line;
incr k;
end else
if k = ref 2
then
begin
second := line;
incr k;
end else
begin
sequence := append_item !sequence line;
incr k;
end
done;
None
with
End_of_file -> None;;
let rec command term = match term with
| Print (n) -> print_endline n
| Print_line_in_file (n, f) -> print_endline (nth_line n f)
| Save () -> save ()
;;
EDIT
Error in code:
Save of in_channel:
Error: This pattern matches values of type unit
but a pattern was expected which matches values of type in_channel
Save of unit:
Error: This expression has type 'a option
but an expression was expected of type unit

There are many errors in this code, so it's hard to know where to start.
One problem is this: your save function has type unit -> 'a option. So it's not the same type as the other branches of your final match. The fix is straightforward: save should return (), not None. In OCaml these are completely different things.
The immediate problem seems to be that you have Save () in your match, but have declared Save as taking an input channel. Your current code doesn't have any way to pass the input channel to the save function, but if it did, you would want something more like this in your match:
| Save ch -> save ch
Errors like this suggest (to me) that you're not so familiar with OCaml's type system. It would probably save you a lot of trouble if you went through a tutorial of some kind before writing much more code. You can find tutorials at http://ocaml.org.

Related

Read a file line per line and store every line read in a single list

I'm a student and I've been given a exercice i've been struggling with for about a month or so.
I'm trying to write a function in Ocaml. This function must read a text file which has a word per line, and it must store all the words in a list.
But the problem is that this program must be a recursive one (which means no loops, no "while").
All I've been able to do so far is to create a function which reads the text file (pretty much like the BASH command "cat")
let dico filename =
let f = open_in filename in
let rec dico_rec () =
try
print_string (input_line f);
print_newline ();
dico_rec();
with End_of_file -> close_in f
in dico_rec() ;;
I just don't know how to do it. Ocaml is hardly my favourite language.
Here's an alternate definition of build_list that is tail recursive. You can use it instead of #MitchellGouzenko's definition if your inputs can have many lines.
let rec build_list l =
match input_line ic with
| line -> build_list (line :: l)
| exception End_of_file -> close_in ic; List.rev l
open Printf
let file = "example.dat"
let () =
let ic = open_in file in
let rec build_list infile =
try
let line = input_line infile in
line :: build_list(infile)
with End_of_file ->
close_in infile;
[] in
let rec print_list = function
[] -> ()
| e::l -> print_string e ; print_string " " ; print_list l in
print_list(build_list(ic))
Edit: The algorithm I previously proposed was unnecessarily complicated. Try to understand this one instead.
To understand this recursion, we assume that build_list works correctly. That is, assume build_list correctly takes an open file as an argument and returns a list of lines in the file.
Now, let's look at the function's body. It reads a line from the file and calls build_list again. If there are N lines in the file, calling build_list again should return a list of the remaining N-1 lines in the file (since we just read the first line ourselves). We append the line we just read to the list returned from build_list, and return the resulting list, which has all N lines.
The recursion continues until it hits the base case. The base case is when there's an End_of_file. In this case we return an empty list.

Write command-line arguments to file in SML

I am trying to write the command line arguments from my SML program into a file, each on a separate line. If I were to run sml main.sml a b c easy as 1 2 3 on the command line, the desired output would be to have a file with the contents:
a
b
c
easy
as
1
2
3
However, I am getting the following output from SML:
$ sml main.sml a b c easy as 1 2 3
val filePath = "/Users/Josue/Desktop/espi9890.txt" : string
val args = ["a","b","c","easy","as","1","2","3"] : string list
main.sml:4.21 Error: syntax error: inserting EQUALOP
/usr/local/smlnj/bin/sml: Fatal error -- Uncaught exception Compile with "syntax error" raised at
../compiler/Parse/main/smlfile.sml:15.24-15.46
With this code:
val filePath = "/Users/Josue/Desktop/espi9890.txt";
val args = CommandLine.arguments();
fun writeListToFile x =
val str = hd x ^ "\n";
val fd = TextIO.openAppend filePath;
TextIO.output (fd, str);
TextIO.closeOut fd;
writeListToFile (tl x);
| fun writeListToFile [] =
null;
writeListToFile args;
Am I missing something?
The correct syntax for nested value declarations is:
fun writeListToFile (s::ss) =
let val fd = TextIO.openAppend filePath
val _ = TextIO.output (fd, s ^ "\n")
val _ = TextIO.closeOut fd
in writeListToFile ss end
| writeListToFile [] = ()
That is,
(Error) You're forgetting the let ... in ... end.
(Error) Your second pattern, [], will never match because the first one, x, is more general and matches all input lists (including the empty one). So even if your syntax error was fixed, this function would loop until it crashes because you are trying to take the hd/tl of an empty list.
(Error) When a function has multiple match cases, only the first one must be prepended with fun and the rest must have a | instead. (You can decide freely how to indent this.)
(Error) There are two kinds of semicolons in SML: One is for separating declarations, and one is an operator that discards the value (but not the effect) of its first operand. The first kind that separates declarations can always be avoided. The second kind is the one you are trying to employ in order to chain multiple expressions that each have a desired (file I/O) effect (and is equivalent to having a let-expressions with multiple effectful declarations in a row, like above).
But... at the top-level (e.g. in a function body), SML is unable to tell the difference between the two kinds of semicolons, since they could both occur there. After all, the first kind that we want to avoid marks the ending of the function body while the second kind just marks the end of a sub-expression in the function body.
The way to avoid this ambiguity is to wrap the ; operator where no declarations are allowed, e.g. between in and end, or inside a parenthesis.
(Error) There is no point in having this function return null. You were probably thinking nil (the empty list, aka []), but val null : 'a list -> bool is a function! Really, it is nonsensical to have a return value for this function. If anything, it could be a bool indicating if the lines were written successfully (in which case you probably need to handle IO exceptions). The closest you get to a function that does not return anything is a function that returns the type unit (with the value ()).
(Suggestion) You can use hd/tl to split the list, but you can also use pattern matching. Use pattern matching, like the examples I've given.
(Suggestion) You can use semi-colons instead of the val _ = ... declarations; also; it's just a matter of taste. E.g.:
fun writeListToFile (s::ss) =
let val fd = TextIO.openAppend filePath
in TextIO.output (fd, s ^ "\n")
; TextIO.closeOut fd
; writeListToFile ss
end
| writeListToFile [] = ()
(Suggestion) It is rather silly that every time the function calls itself, it opens the file, appends, and closes the file. Ideally you only open and close the file once:
fun writeListToFile lines =
let val fd = TextIO.openAppend filePath
fun go [] = TextIO.closeOut fd
| go (s::ss) = ( TextIO.output (fd, s ^ "\n") ; go ss )
in go lines end
(Suggestion) Since you are doing the same thing to each element in a list, you may also consider using a higher-order function that generalizes the iteration. Normally, that would be a val map : ('a -> 'b) -> 'a list -> 'b list, but since TextIO.output returns a unit, the very similar val app : ('a -> unit) -> 'a list -> unit is even better:
fun writeListToFile lines =
let val fd = TextIO.openAppend filePath
in List.app (fn s => TextIO.output (fd, s ^ "\n")) lines
; TextIO.closeOut fd
end
(Suggestion) Lastly, you may want to call this function appendListToFile, or simply appendLines, and take filePath as an argument to the function, since filePath implies that it is to a file, and the function does add linebreaks to each s. Names matter.
fun appendLines filePath lines =
let val fd = TextIO.openAppend filePath
in List.app (fn s => TextIO.output (fd, s ^ "\n")) lines
; TextIO.closeOut fd
end

How to easily read lines from stdin?

Some time ago, I decided to solve a simple task on HackerRank but using OCaml and Core, in order to learn them. In one of the tasks, I'm supposed to read data from standard input:
The first line contains an integer, denoting the number of entries
in the phone book. Each of the subsequent lines describes an entry in
the form of space-separated values on a single line. The first value
is a friend's name, and the second value is an -digit phone number.
After the lines of phone book entries, there are an unknown number of
lines of queries. Each line (query) contains a to look up, and you
must continue reading lines until there is no more input.
The main issues:
I don't know how many lines there will be
Last line don't ends by newline, so I can't just read scanf "%s\n" until End_of_file
And my code became messy:
open Core.Std
open Printf
open Scanf
let read_numbers n =
let phone_book = String.Table.create () ~size:n in
for i = 0 to (n - 1) do
match In_channel.input_line stdin with
| Some line -> (
match (String.split line ~on:' ') with
| key :: data :: _ -> Hashtbl.set phone_book ~key ~data
| _ -> failwith "This shouldn't happen"
)
| None -> failwith "This shouldn't happen"
done;
phone_book
let () =
let rec loop phone_book =
match In_channel.input_line stdin with
| Some line -> (
let s = match Hashtbl.find phone_book line with
| Some number -> sprintf "%s=%s" line number
| None -> "Not found"
in
printf "%s\n%!" s;
loop phone_book
)
| None -> ()
in
match In_channel.input_line stdin with
| Some n -> (
let phone_book = read_numbers (int_of_string n) in
loop phone_book
)
| None -> failwith "This shouldn't happen"
If I solve this task in Python, then code looks like this:
n = int(input())
book = dict([tuple(input().split(' ')) for _ in range(n)])
while True:
try:
name = input()
except EOFError:
break
else:
if name in book:
print('{}={}'.format(name, book[name]))
else:
print('Not found')
This is shorter and clearer than the OCaml code. Any advice on how to improve my OCaml code? And there two important things: I don't want to abandon OCaml, I just want to learn it; second - I want to use Core because of the same reason.
The direct implementation of the Python code in OCaml would look like this:
let exec name =
In_channel.(with_file name ~f:input_lines) |> function
| [] -> invalid_arg "Got empty file"
| x :: xs ->
let es,qs = List.split_n xs (Int.of_string x) in
let es = List.map es ~f:(fun entry -> match String.split ~on:' ' entry with
| [name; phone] -> name,phone
| _ -> invalid_arg "bad entry format") in
List.iter qs ~f:(fun name ->
match List.Assoc.find es name with
| None -> printf "Not found\n"
| Some phone -> printf "%s=%s\n" name phone)
However, OCaml is not a script-language for writing small scripts and one shot prototypes. It is the language for writing real software, that must be readable, supportable, testable, and maintainable. That's why we have types, modules, and all the stuff. So, if I were writing a production quality program, that is responsible for working with such input, then it will look very differently.
The general style that I personally employ, when I'm writing a program in a functional language is to follow these two simple rules:
When in doubt use more types.
Have fun (lots of fun).
I.e., allocate a type for each concept in the program domain, and use lots of small function.
The following code is twice as big, but is more readable, maintainable, and robust.
So, first of all, let's type: the entry is simply a record. I used a string type to represent a phone for simplicity.
type entry = {
name : string;
phone : string;
}
The query is not specified in the task, so let's just stub it with a string:
type query = Q of string
Now our parser state. We have three possible states: the Start state, a state Entry n, where we're parsing entries with n entries left so far, and Query state, when we're parsing queries.
type state =
| Start
| Entry of int
| Query
Now we need to write a function for each state, but first of all, let's define an error handling policy. For a simple program, I would suggest just to fail on a parser error. We will call a function named expect when our expectations fail:
let expect what got =
failwithf "Parser error: expected %s got %s\n" what got ()
Now the three parsing functions:
let parse_query s = Q s
let parse_entry s line = match String.split ~on:' ' line with
| [name;phone] -> {name;phone}
| _ -> expect "<name> <phone>" line
let parse_expected s =
try int_of_string s with exn ->
expect "<number-of-entries>" s
Now let's write the parser:
let parse (es,qs,state) input = match state with
| Start -> es,qs,Entry (parse_expected input)
| Entry 0 -> es,qs,Query
| Entry n -> parse_entry input :: es,qs,Entry (n-1)
| Query -> es, parse_query input :: qs,Query
And finally, let's read data from file:
let of_file name =
let es,qs,state =
In_channel.with_file name ~f:(fun ch ->
In_channel.fold_lines ch ~init:([],[],Start) ~f:parse) in
match state with
| Entry 0 | Query -> ()
| Start -> expect "<number-of-entries><br>..." "<empty>"
| Entry n -> expect (sprintf "%d entries" n) "fewer"
We also check that our state machine reached a proper finish state, that is it is either in Query or Entry 0 state.
As in Python, the key to a concise implementation is to let the standard library do most of the work; the following code uses Sequence.fold in lieu of Python's list comprehension. Also, using Pervasives.input_line rather than In_channel.input_line allows you to cut down on extraneous pattern matching (it will report an end of file condition as an exception rather than a None result).
open Core.Std
module Dict = Map.Make(String)
let n = int_of_string (input_line stdin)
let d = Sequence.fold
(Sequence.range 0 n)
~init:Dict.empty
~f:(fun d _ -> let line = input_line stdin in
Scanf.sscanf line "%s %s" (fun k v -> Dict.add d ~key:k ~data:v))
let () =
try while true do
let name = input_line stdin in
match Dict.find d name with
| Some number -> Printf.printf "%s=%s\n" name number
| None -> Printf.printf "Not found.\n"
done with End_of_file -> ()

Extracting data from a tuple in OCaml

I'm trying to use the CIL library to parse C source code. I'm searching for a particular function using its name.
let cil_func = Caml.List.find (fun g ->
match g with
| GFun(f,_) when (equal f.svar.vname func) -> true
| _ -> false
) cil_file.globals in
let body g = match g with GFun(f,_) -> f.sbody in
dumpBlock defaultCilPrinter stdout 1 (body cil_func)
So I have a type GFun of fundec * location, and I'm trying to get the sbody attribute of fundec.
It seems redundant to do a second pattern match, not to mention, the compiler complains that it's not exhaustive. Is there a better way of doing this?
You can define your own function that returns just the fundec:
let rec find_fundec fname = function
| [] -> raise Not_found
| GFun (f, _) :: _ when equal (f.svar.vname fname) -> f (* ? *)
| _ :: t -> find_fundec fname t
Then your code looks more like this:
let cil_fundec = find_fundec func cil_file.globals in
dumpBlock defaultCilPrinter stdout 1 cil_fundec.sbody
For what it's worth, the line marked (* ? *) looks wrong to me. I don't see why f.svar.vname would be a function. I'm just copying your code there.
Update
Fixed an error (one I often make), sorry.

prompt user to build a string list

I would like to build a string list by prompting the user for input. My end goal is to be able to parse a string list against a simple hash table using a simple routine.
`let list_find tbl ls =
List.iter (fun x ->
let mbr = if Hashtbl.mem tbl x then "aok" else "not found"
in
Printf.printf "%s %s\n" x mbr) ls ;;`
Building a string list is accomplished with the cons operator ::, but somehow I am not able to get the prompt to generate a string list. A simpe list function returns anything that is put into it as a list:
`let build_strlist x =
let rec aux x = match x with
| [] -> []
| hd :: tl -> hd :: aux tl
in
aux x ;;`
Thus far, I have been able to set the prompt, but building the string list did not go so well. I am inclined to think I should be using Buffer or Scanning.in_channel. This is what I have thus far:
`#load "unix.cma" ;;
let prompt () = Unix.isatty Unix.stdin && Unix.isatty Unix.stdout ;;
let build_strlist () =
let rec loop () =
let eof = ref false in
try
while not !eof do
if prompt () then print_endline "enter input ";
let line = read_line () in
if line = "-1" then eof := true
else
let rec build x = match x with
| [] -> []
| hd :: tl -> hd :: build tl
in
Printf.printf "you've entered %s\n" (List.iter (build line));
done
with End_of_file -> ()
in
loop () ;;`
I am getting an error the keyword "line" has the type string, but an expression was expected of type 'a list. Should I be building the string list using Buffer.create buf and then Buffer.add_string buf prepending [ followed by quotes " another " and a semicolon? This seems to be an overkill. Maybe I should just return a string list and ignore any attempts to "peek at what we have"? Printing will be done after checking the hash table.
I would like to have a prompt routine so that I can use ocaml for scripting and user interaction. I found some ideas on-line which allowed me to write the skeleton above.
I would probably break down the problem in several steps:
get the list of strings
process it (in your example, simply print it back)
1st step can be achieved with a recursive function as follow:
let build_strlist' () =
let rec loop l =
if prompt () then (
print_string "enter input: ";
match read_line () with
"-1" -> l
| s -> loop (s::l)
) else l
in loop [];;
See how that function loops on itself and build up the list l as it goes. As you mentioned in your comment, I dropped the imperative part of your code to keep the functional recursion only. You could have achieved the same by keeping instead the imperative part and leaving out the recursion, but recursion feels more natural to me, and if written correctly, leads to mostly the same machine code.
Once you have the list, simply apply a List.iter to it with the ad hoc printing function as you did in your original function.