Problems with Set in OCaml - ocaml

So I need to write a function that basically prints out variables at risk and normal variables in a code, and I wanted to do it like this:
(*Names and Risk are of type Set(String)*)
let names=Names.empty
let risk=Risk.empty
let printRes names risk=
if(Names.is_empty names=false) then printNames names else print_string "oops1";
print_newline();
if(Risk.is_empty risk=false) then Risk.iter print_string risk else print_string "oops2";
print_newline();
;;
let rec varsBlock (p:block) (ind:int)=
match p with
|[]->printRes names risk
|(line,instr)::r->match instr with
|Set(n,e)-> let names=Names.add n names in (); varsBlock r ind
|Read(n)-> let names=Names.add n names in (); varsBlock r ind
;;
But the problem here is, every Names.add returns a whole new set, and my function printRes considers the set names (same goes for risk which is used in another function that follows the same pattern) as empty. Is there any other way of doing it without "obsuring" the original set I want to add everything to?

Instead of using a global mutable variable I would suggest explicitly passing the names set to varsBlock. Then you can easily pass the updated set to the next iteration.
let rec varsBlock (p:block) (ind:int) names =
match p with
| [] -> printRes names risk
| (_, Set(n, _))::r
| (_, Read(n))::r -> varsBlock r ind (Names.add n names)

Related

How to process elements of an OCAML list?

I want to process the data present in file "persons.txt".
But i have tried everything to process all the lines from text file.
The only way i can process data is by creating the list manually.
let myList = ["John";"23"]
I want the program to iterate through all the lines of the text file.
I have managed a way to pass all the content of the text file into a list but i can+t seem to move on from that stage.
My way of thinking is:
Read content from text file
Convert to OCaml list
Separate list into sublists
Iterate through sublists
Only print to screen text respecting conditions
Can you please guide me?
Thanks!!
open Printf
(* FILE CONTENTS *)
(*
John;23;
Mary;16;
Anne;21;
*)
let file = "data/persons.txt"
;;
(* READ FROM EXTERNAL FILE *)
let read_lines name : string list =
if Sys.file_exists (name) then
begin
let ic = open_in name in
try
let try_read () =
try Some (input_line ic) with End_of_file -> None in
let rec loop acc = match try_read () with
| Some s -> loop (s :: acc)
| None -> close_in_noerr ic; List.rev acc in
loop []
with e ->
close_in_noerr ic;
[]
end
else
[]
;;
(...)
Your question is not at all clear. Here are some observations:
First, your read_lines function doesn't return the input in the form you need.
What read_lines returns looks like this:
["John;23;"; "Mary;16;"; "Anne;21;"]
But what you want is something more like this:
[("John", "23)"; ("Mary", "16"); ("Anne", "21")]
The key here is to split the strings into pieces using ; as a separator. You can probably use String.split_on_char for this.
Second, you are not defining a function to calculate an answer from paramters. Instead your calculation is based on global variables. This won't generalize.
Instead of saying this:
let adult_check_condition =
... using global age and name ...
You need to define a function:
let adult_check_condition age name =
... use parameters age and name ...
Then you can call this function with different ages and names.

OCaml initializing list in loop for

I am a beginner with OCaml. I would like to skip the first element of my list.
Here is my list:
let l = [1;2;3;4;5;6;7;2;1];;
I want to use this in my FOR:
let l = List.tl l;
here is my full code:
let l = [1;2;3;4;5;6;7;2;1];;
let n = 1;;
let counter = ref 0;;
for i = 0 to (List.length l) do
if List.hd l = n then counter := !counter + 1;
print_int(!counter);
print_string("\n");
let l = List.tl l
done;;
But I have errors in the DONE and it says syntax error.
Can anyone help me please?
Your problem is that let always requires a matching in. The full expression looks like this:
let var = expr1 in expr2
Since you're missing the in part, you get a syntax error.
However, the deeper problem is that you're trying to modify the value of l. The way you have defined l, it's immutable. You can't change its value. If you want to be able to change its value you can define it as a reference, as you have done for counter.
(There is another form of let used at the top level of a module. This form doesn't have a matching in. But your code isn't defining a top-level name, so this is not relevant.)

trimming a list of pairs with OCaml

I am trying to filter a list of pairs and return a new list containing only the first element of each pair. The input/output should go like this:
input = [('A', 3); ('B', 2); ('D', 1)]
output = ['A'; 'B'; 'D']
The code i have so far is this:
let rec trimList l = function
| [] -> []
| head::tail -> let l' = [fst head] # trimList List.tl l;;
but i get the following error:
Line 3, characters 59-61:
3 | | head::tail -> let l' = [fst (head)] # trimList List.tl l;;
^^
Error: Syntax error
I don't know why this isn't working. I know this is very simple, but i am new to OCaml.
Any help would be appreciated, thank you.
Your syntax problem is caused by the fact that you have let with no corresponding in.
A let expression looks like this:
let v = expr1 in expr2
In essence this establishes a local variable v with value expr1 and has the value of expr2 (which will probably contain instances of the variable v).
You are missing the in part of the let expression.
As another comment, if you define a function like this:
let f l = function ...
You are defining a function of two parameters. There is an implicit parameter defined by the function keyword; the parameter is matched against the following patterns.
Most likely you want to remove the l from you function definition.
There are a few other problems with your code, but I hope this helps to make progress.

OCaml Syntax Error in Parser

Can someone help me explain why I have a syntax error at this line: let wordMap = StringMap.empty? This is contained in an .mll file. The module StringMap is defined above.
let lexbuf = Lexing.from_channel stdin in
let wordlist =
let rec next l = match token lexbuf with
EOF -> l
| Word(s) -> next (s :: l)
in next []
let wordMap = StringMap.empty in
let wcList = StringMap.fold (fun word count l -> (string_of_int count ^ " " ^ word) :: l) wordMap [] in
List.iter print_endline wcList;;
I know it prints nothing, this is just for testing.
A declaration like:
let v = expr
can only appear at the outermost level of a module. It's the way to declare the global names of the module.
But you have such a declaration (of wordlist) inside an expression:
let lexbuf = ... in
let wordlist = ...
In all places other than the outer level of a module, let must be followed by in. This is the way to declare a local variable (in any expression).
let v = expr1 in expr2
I'm not clear which of your names you want to be global. But one way to solve the problem would be to remove the first in. Then you would have three global names, lexbuf, wordlist, and wordMap.
Another way would be to add in after the definition of wordlist. Then you would have no global names.
You have a problem with your let-bindings. This should work if I rewrite your as below:
let main () =
let lexbuf = Lexing.from_channel stdin in
let wordlist =
let rec next l = match token lexbuf with
EOF -> l
| Word s -> next (s :: l) in
next []
in
wordlist
let wordMap = StringMap.empty
The function main return wordList as the result.
A golden rule for this sort of trouble: use a proper indentation tool, caml-mode, tuareg-mode or ocp-indent. If these tools show an indentation different from your intention, it is often the case that you made a syntax error.

Filtering a list of arrays f#

sorry if the questions to basic, but i havent been able to do this for some time. I have created a lists of lists in which the second array contains a parameter that can be either an f or a p. I need to create two new lists of arrays, one containing the items that have the f parameter and the other one containing the p parameter.
edit: trying to explain myself:
I have a list containing a series of facebook publications, and each one of this publications has information, such as what type of publication it is.. they can be either a p (text) or f (picture). What i need to do is to create two separate lists of this publications by the type publication they are.
example of data: [[|"publication0ID", "Poster0ID","TypeofPublication0"|];[|"publication1ID", "Poster1ID","TypeofPublication1"|]]
let data = [[|"publication0ID"; "Poster0ID"; "f"|];[|"publication1ID"; "Poster1ID"; "p"|]]
let texts, pictures =
data
|> List.partition (List.ofArray >> function
| _ :: _ :: "f" :: _ -> true
| _ :: _ :: "p" :: _ -> false
| _ -> failwith "neither f nor p"
)
This will split the lists according to the third "parameter", which you called "TypeOfPublication".
I changed your sample code, because your sub-arrays sub-lists contain only one tuple and judging by your "..." I tought that might be wrong.
To explain:
List.partition splits a list according to a function that is called for every element in the list. When the function returns true, the element will be put into the first list of the result tuple, and into the second list when false.
Since your elements are arrays also lists, it will be checked if the third element in the array list is either "f", which will cause the array list to be put in the texts result, and "p", which will be put into pictures.
If the third element is neither "f" nor "p", an exception will be thrown.
Update for the comment:
If your sub-arrays are always exactly three elements long, you can use this version:
let texts, pictures =
data
|> List.partition (function
| [| _; _; "f" |] -> true
| [| _; _; "p" |] -> false
| _ -> failwith "neither f nor p or wrong array length"
)
Or, you can use the first version and just put List.ofArray >> in between the function keyword and the opening paren so that it reads: List.partition (List.ofArray >> function (I updated the code above as well).
Assuming that your main list is of type (int, string) list list, then if you
let f = 1
let p = 1
you should be able to filter your main_list by using
let f_items = seq {
let! sub_list = main_list
let! (selector, item) = sub_list
if selector == f then
yield item
}
and likewise, to get the "p" items, you would use selector == p.
I had to bring out my F# book to be able to write this code, I haven't used F# for so long! I don't have F# on this computer, so I don't know if the above code actually works.