Run bash script from ocaml - ocaml

I think that what i mean is in the title. I have tried to search if it is possible to run bash script from ocaml like from java or from php but i could not find.
i know that we can use ocaml as a scripting language but it is not what i want
Ocaml as a scripting language
In other words

From the Ocaml documentation :
val command : string -> int
So if you want to call a script from Ocaml, do this :
let status = Sys.command "./myexecutable.sh" in
Printf.printf "status = %d\n" status
Feel free to do what you want with the exit code.

Just in case you are interested in collecting the output of the bash script,
let () =
(* Just using pstree as an example, you can pick something else *)
let ic = Unix.open_process_in "pstree" in
let all_input = ref [] in
try
while true do
all_input := input_line oc :: !all_input
done
with
End_of_file ->
(* Just an example, you can do something else here *)
close_in ic;
List.iter print_endline !all_input

I think what you are looking for is the Sys module (http://caml.inria.fr/pub/docs/manual-ocaml/libref/Sys.html).
Sys.command might be one way to do what you want.
If this is not enough, then you may want to take a look at what the Unix has to offer (http://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html).

Related

How to list files of a given extension in OCaml

I want to retrieve the list of direct files (i.e. no recursive search) of a given directory and a given extension in OCaml.
I tried the following but:
It does not look OCaml-spirit
It does not work (error of import)
let list_osc2 =
let list_files = Sys.readdir "tests/osc2/expected/pp" in
List.filter (fun x -> Str.last_chars x 4 = ".osc2") (Array.to_list list_files)
I got the error (I am using OCamlPro):
Required module `Str' is unavailable
Thanks
You can use Filename.extension instead of Str.last_chars:
let list_osc2 =
let list_files = Sys.readdir "tests/osc2/expected/pp" in
List.filter (fun x -> Filename.extension x = ".osc2") (Array.to_list list_files)
and then use the pipe operator to make it a bit more readable:
let list_osc2 =
Sys.readdir "tests/osc2/expected/pp"
|> Array.to_list
|> List.filter (fun x -> Filename.extension x = "osc2")
I don't know how you expect this to work in OCamlPro though, as it doesn't have a filesystem as far as I'm aware.
To use the Str module, you need to link with the str library. For example, with ocamlc, you need to pass str.cma, and with ocamlopt, you need to pass str.cmxa. I don't know how to do that with OcamlPro.
In any case, Str.last_chars is not particularly useful here. It doesn't work if the file name is shorter than the suffix. By the way, your code would never match because ".osc2" is 5 characters, which is never equal to last_chars x 4.
The Filename module from the standard library has functions to extract and check a file's extension. You don't need to do any string manipulation.
I don't know what you consider “ugly as hell”, but apart from the mistake with string manipulation, I don't see any problem with your code. Enumerating the matches and filtering them is perfectly idiomatic.
let list_osc2 =
let list_files = Sys.readdir "tests/osc2/expected/pp" in
List.filter (fun name -> check_suffix name ".osc2") (Array.to_list list_files)

F# append to list in a loop functiuonally

I am looking to convert this code to use F# list instead of the C# list implementation.
I am connecting to a database and running a query usually with C# would create a list of a type and keep adding the list while the datareader has values. How would I go about converting this to use an F# list
let queryDatabase (connection: NpgsqlConnection) (queryString: string) =
let transactions = new List<string>()
let command = new NpgsqlCommand(queryString, connection)
let dataReader = command.ExecuteReader()
while dataReader.Read() do
let json = dataReader.GetString(1)
transactions.Add(json)
transactions
The tricky thing here is that the input data source is inherently imperative (you have to call Read which mutates the internal state). So, you're crossing from imperative to a functional world - and so you cannot avoid all mutation.
I would probably write the code using a list comprehension, which keeps a similar familiar structure, but removes explicit mutation:
let queryDatabase (connection: NpgsqlConnection) (queryString: string) =
[ let command = new NpgsqlCommand(queryString, connection)
let dataReader = command.ExecuteReader()
while dataReader.Read() do
yield dataReader.GetString(1) ]
Tomas' answer is a solution to use in product code. But for sake of learning F# and functional programming I present my snippet with tail recursion and cons operator:
let drToList (dr:DataReader) =
let rec toList acc =
if not dr.Read then acc
else toList <| dr.GetString(1) :: acc
toList []
This tail recursion function is compiled into imperative-like code, thus no stack overflow and fast execution.
Also I advice you look at this C# thread and this F# documentation to see how properly dispose your command. Basically, you need to use smth like this:
let queryDb (conn: NpgsqlConnection) (qStr: string) =
use cmd = new NpgsqlCommand(qStr, conn)
cmd.ExecuteReader() |> drToList
And if we go deeper, you should also think about exception handling.

OCaml - Creating a function which prompts for floats and returns a list of floats

I'm teaching myself OCaml and I sometimes need to create a function where I'm not really sure what the proper solution should be. Here's one that I'm a little confused about.
I need a function that will prompt the user for individual float values and return everything entered in a float list. I can create this function but I'm not sure if its the proper/best way to do it in Ocaml.
Here's my attempt.
let rec get_floats() =
match
(
try Some(read_float())
with
| float_of_string -> None
)
with
| None -> []
| Some s -> s :: get_floats();;
This code works buts I'm at a loss deciding if its a 'proper OCaml' solution. Note, to exit the function and return the float list just enter a non-integer value.
(I hope that) this is a simple peephole rewrite involving no thought whatsoever of the function in your question:
let rec get_floats() =
try
let f = read_float() in (* as suggested by Martin Jambon *)
f :: (get_floats())
with
| float_of_string -> []
The idea I tried to apply here is that you do not need to convert the success/failure of read_float into an option that you immediately match: just do what you have to do with the value read, and let the with handle the failure case.
Now that I think of it, I should point out that in both your question and my rewrite, float_of_string is a fresh variable. If you meant to match a specific exception, you failed at it: all exception constructors, like datatype constructors, are Capitalized. You might as well have written with _ -> instead of with float_of_string ->, and a recent version of OCaml with all warnings active should tell you that your function (or mine) binds a variable float_of_string without ever using it.
Thanks everyone for the help. This works.
let rec get_floats() =
try
let x = read_float() in
x :: get_floats()
with
| _ -> [];;
List.iter (fun x -> print_endline(string_of_float x)) (get_floats());;

how to generate a list quickly iterating a file

Me coming from a c# and python background, feels there must be a better way to read a file and populate a classic F# list. But then I know that a f# list is immutable. There must be an alternative using a List<string> object and calling its Add method.
So far what I have at hand:
let ptr = new StreamReader("stop-words.txt")
let lst = new List<string>()
let ProcessLine line =
match line with
| null -> false
| s ->
lst.Add(s)
true
while ProcessLine (ptr.ReadLine()) do ()
If I were to write the similar stuff in python I'd do something like:
[x[:-1] for x in open('stop-words.txt')]
Simple solution
System.IO.File.ReadAllLines(filename) |> List.ofArray
Although you can write a recursive function
let processline fname =
let file = new System.IO.StreamReader("stop-words.txt")
let rec dowork() =
match file.ReadLine() with
|null -> []
|t -> t::(dowork())
dowork()
If you want to read all lines from a file, you can just use ReadAllLines. The method returns the data as an array, but you can easily turn that into F# list using List.ofArray or process it using the functions in the Seq module:
open System.IO
File.ReadAllLines("stop-words.txt")
Alternatively, if you do not want to read all the contents into memory, you can use File.ReadLines which reads the lines lazily.

Convert a string into array of words

How do I separate a string into a list/array of white space separated words.
let x = "this is my sentence";;
And store them inan list/array like this:
["this", "is", "my", "sentence"]
Using the standard library Str split_delim and the regexp type.
Str.split_delim (Str.regexp " ") "this is my sentence";;
- : bytes list = ["this"; "is"; "my"; "sentence"]
Highly recommend getting UTop, it's really good for quickly searching through Libraries (I typed Str, saw it was there, then Str. and looked for the appropriate function).
The full process goes like this:
first opam install re
if you are using utop, then you can do something like this
#require "re.pcre"
let () =
Re_pcre.split ~rex:(Re_pcre.regexp " +") "Hello world more"
|> List.iter print_endline
and then just run it with utop code.ml
if you want to compile native code, then you'd have:
let () =
Re_pcre.split ~rex:(Re_pcre.regexp " +") "Hello world more"
|> List.iter print_endline
Notice how the #require is gone.
then at command line you'd do: ocamlfind ocamlopt -package re.pcre code.ml -linkpkg -o Test
The OCaml website has tons of tutorials and help, I also have a blog post designed to get you up to speed quickly: http://hyegar.com/2015/10/20/so-youre-learning-ocaml/