I wrote the following function while following Real World OCaml, which uses the Core library.
open Core.Core_list
open Core.Option
open Core.Std
open Re2
let getMaxFilename target =
let Ok pat = Regex.create "^.*(..)\\.txt$" in
Sys.ls_dir target |>
List.map ~f:(Regex.find_submatches pat) |>
List.filter ~f:is_ok |>
List.map ~f:(fun x -> ok_exn x |> Array.to_list |> (Fn.flip nth_exn) 1 |> fun x -> value_exn x) |>
List.reduce ~f:max
It looks messy to me since I have a lot of "opens" at the top and I have to name List, Array, Sys, Fn, and the other modules names in all the functions that I use. This is the "right" way to write OCaml? Is there a standard style that dispenses with these?
I'm not sure this is the best way to do this, but here's a fairly straight-ahead stylistic cleanup, without really doing anything material.
open Core.Std
module Regex = Re2.Regex
let get_max_filename target =
let pat = Regex.create_exn "^.*(..)\\.txt$" in
Sys.ls_dir target
|> List.map ~f:(Regex.find_submatches pat)
|> List.filter_map ~f:Result.ok
|> List.filter_map ~f:(fun x -> x.(1))
|> List.reduce ~f:max
Generally speaking, heavy use of open is frowned upon.
The following might be yet clearer and easier to follow.
let get_max_filename target =
let pat = Regex.create_exn "^.*(..)\\.txt$" in
Sys.ls_dir target
|> List.filter_map ~f:(fun entry ->
match Regex.find_submatches pat entry with
| Error _ -> None
| Ok ar -> ar.(1))
|> List.reduce ~f:max
Related
i am in a bit of a pickle, i have tried for 2 hours straight trying to get this code to work and im lost.
let DropColumn list =
if List.exists List.isEmpty list then "empty value"
else
list |> List.map List.tail
This gives me an error error FS0001: The type 'string' does not match the type ''a list'
The usual way to deal with failure in functional programming is to use the Result type, which is essentially defined as:
type Result<'T,'TError> =
| Ok of 'T
| Error of 'TError
To apply it to your code we can just wrap the string in the unhappy path with Error and the list from the happy path with Ok:
let DropColumn list =
if List.exists List.isEmpty list then
Error "empty value"
else
list |> List.map List.tail |> Ok
Then to use it you can use pattern matching:
match DropColumn myList with
| Ok newList ->
newList
| Error message ->
printfn "Error occurred: %s" message
[]
The answer given by #glennsl is correct and in many cases the preferred way. However, I'd like to add that there are two other common ways of dealing with invalid input:
Raise an exception. Use this for exceptional cases only, i.e. where you expect your code to halt as the result of invalid data. Do not use it for normal validation where you expect that data can often be wrong.
Use option. This is similar to using Result, but doesn't maintain information for the invalid case. This approach is very common and used a lot in library functions like List.tryFind, List.tryHead etc.
Raise an exception
In the comments you show you already know this option exists, but let's give it here for completeness:
let dropColumnOrRaise list =
if List.exists List.isEmpty list then failwith "empty value"
else
list |> List.map List.tail
Use option
This method usually requires that the business logic that shows an error or does recovery, goes elsewhere.
let tryDropColumn list =
if List.exists List.isEmpty list then None
else
list
|> List.map List.tail
|> Some
Use it as follows:
match tryDropColumn myCols with
| Some columns ->
// do something with valid columns, i.e., display them
printfn "%i columns remaining (List.length (List.head myCols))"
| None ->
// error recovery or showing a message
printfn "No column selected"
When you are dealing with several functions that operate on data that all return option, you can pipe them together with Option.bind (or Option.map if a function doesn't return option).
myCols
|> tryDropColumn
|> Option.map logColumns // function that always succeeds
|> Option.bind tryAtLeastTwoColumns // function that returns None on 1 or 0
|> Option.map showColumns
The code above removes the need to have a match x with for each returned option. Similar code can be used for Result from the previous answer.
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)
I have set up a project and I want to write tests for it. Now the problem is my functions in production work with a database but in tests I want to direct them towards a fake database.
for example I have the string mongoHostAdress = "192.168.0.1" which my functions use to access mongo database, and I when testing I want it to change to mongoHostAdress = "127.0.0.1".
how can I tell Haskell to automatically do this for me ?
Edit : more general outlook
how can I create a config file for a project and use different params for different stages of the project?
So the concept is create file input.txt which looks like this:
fstParameterName:fstParameterValue
sndParameterName:sndParameterValue
trdParameterName:trdParameterValue
Now inside main function you can easily set your params using construction like this:
main = do
text <- readFile "input.txt"
mongoHostAdress <- (getConfigValue "mongoHostAdress" (lines text))
print(mongoHostAdress)
getConfigValue name (l:ls) = if(containsPrefix name l)
then (return(skipPrefix name l))
else (getConfigValue name ls)
containsPrefix [] x = True
containsPrefix (x:xs) (y:ys) = if(x==y) then (containsPrefix xs ys) else False
skipPrefix [] (x:xs) = xs --x is just ":" and ofc we dont want it
skipPrefix (x:xs) (y:ys) = skipPrefix xs ys
Could someone explain what the |> operator does? This code was taken from the reference here:
let m = PairsMap.(empty |> add (0,1) "hello" |> add (1,0) "world")
I can see what it does, but I wouldn't know how to apply the |> operator otherwise.
For that matter, I have no idea what the Module.() syntax is doing either. An explanation on that would be nice too.
Module.(e) is equivalent to let open Module in e. It is a shorthand syntax to introduce things in scope.
The operator |> is defined in module Pervasives as let (|>) x f = f x. (In fact, it is defined as an external primitive, easier to compile. This is unimportant here.) It is the reverse application function, that makes it easier to chain successive calls. Without it, you would need to write
let m = PairsMap.(add (1,0) "world" (add (0,1) "hello" empty))
that requires more parentheses.
The |> operator looks like the | in bash.
The basic idea is that
e |> f = f e
It is a way to write your applications in the order of execution.
As an exemple you could use it (I don't particularly think you should though) to avoid lets:
12 |> fun x -> e
instead of
let x = 12 in e
For the Module.() thing, it is to use a specific function of a given module.
You probably have seen List.map before.
You could of course use open List and then only refer to the function with map. But if you also open Array afterwards, map is now referring to Array.map so you need to use List.map.
The |> operator represents reverse function application. It sounds complicated but it just means you can put the function (and maybe a few extra parameters) after the value you want to apply it to. This lets you build up something that looks like a Unix pipeline:
# let ( |> ) x f = f x;;
val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>
# 0.0 |> sin |> exp;;
- : float = 1.
The notation Module.(expr) is used to open the module temporarily for the one expression. In other words, you can use names from the module directly in the expression, without having to prefix the module name.
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());;