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.
Related
In Python, it is quite simple to manage certain error with unit tests. For instance, to verify if a list is emptied or not, I can use assert test != []
Suppose the empty list let test = [];;
try
ignore (nth test 0)
with
Not_found -> print_string("Erreur!");;
Exception: Failure "nth"
I need to raise an error - print_string ("Erreur!") when I encounter Exception: Failure "nth". So far the try/with did not really help me. In Ocaml, is there a workaround to raise the error and print something when I get Exception: Failure "nth"?
In Python, it is quite simple to manage certain error, with unit tests. For instance, to verify if a list is emptied or not, I can use assert test != []
You can do exactly the same (modulo syntax) in OCaml
let require_non_empty xs =
assert (xs <> [])
If you would like to hush an exception and raise in its absence, you can use the match construction, here is how your example could be expressed in OCaml,
let require_empty xs = match List.nth xs 0 with
| exception _ -> ()
| _ -> failwith "the list shall be empty"
In addition, testing frameworks, e.g., OUnit2, provide special functions such as assert_raises for these specific cases.
You seem to be asking whether you can test for specific exceptions. Yes. The exception handling part after with is a list of patterns similar to the match expression.
try
ignore (List.nth [] 0)
with
| Not_found -> ()
| Failure s -> print_string ("Erreur: " ^ s)
| _ -> ()
(It probably isn't wise to depend on the exact string supplied as the argument to Failure. The compiler, in fact, warns you not to do this.)
OCaml also has an asssert expression:
# let list = [] in assert (List.length list > 0);;
Exception: Assert_failure ("//toplevel//", 1, 17).
You can use try/with to handle the resulting exception, of course. The argument to Assert_failure gives the filename, line number, and character number on the line.
I need to modify an OCaml function:
let removeDuplicates l =
let rec helper (seen,rest) =
match rest with
[] -> seen
| h::t ->
let seen' = failwith "to be written" in
let rest' = failwith "to be written" in
helper (seen',rest')
in
List.rev (helper ([],l));;
The function needs to take a list l and return the list with all duplicates removed. The failwith "to be written" parts is where I'm supposed to write my code. I understand how the helper function works but am having trouble understanding this part helper (seen',rest'). I'm not exactly sure how the function is supposed to flow with this part or how it works when you include a bunch of in's all together. We are allowed to use List.rev which reverses a list and list.mem which returns true if a certain element is in a list. Can someone please explain to me how the flow of the function is supposed to work so I can start to write a solution.
That line is confusing because it's indented incorrectly, or so I would claim. The proper indentation looks like this:
let seen' = failwith "to be written" in
let rest' = failwith "to be written" in
helper (seen',rest')
What it's saying is: calculate a new value for seen and a new value for rest, then call yourself recursively with the two new values.
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());;
I'm still fairly new to OCaml, and would like some assistance on optimizing code.
I'm trying to multiply each element of a given list by the list's last element.
Here's a snippet of my code:
(* Find the last element of a function *)
let rec lastE = function
| [] -> []
| [x] -> x
| _ :: t -> lastE t;;
(*multiply a list by the last element*)
let rec lmul list =
match list with
[] -> []
| hd::tl -> (hd *. (lastE tl)) :: lmul tl;;
When I run the code I get this error message:
Error: This expression has type float list but
an expression was expected of type 'a list list
I'm been studying it for a while, but any assistance on this problem will be much appreciated.
To rephrase differently what Dave Newman is telling you, your basic problem is that lastE needs to handle an empty list differently. If lastE is supposed to return a number, it has to return a number in all cases. As it stands, lastE returns a list when it receives an empty list.
If you don't want to use List.map (again as Dave Newman suggests), you might at least consider calling lastE just once rather than once for each element of the list. This will make a big difference for long lists.
type node = {
lan: string;
lat: string;
};;
let rec read_nodes_from_list list = match list with
| Xml.Element("node", _, _)::list' -> {lan="A"; lat="B"}::read_nodes_from_list list'
;;
I tried this to create a node record but it doesn't work. And suppose I have another type that has same attributes of node, how can I tell ocaml which type object to create?
Thank you.
Obviously, your function didn't work because you forgot to match with empty list:
let rec read_nodes_from_list list = match list with
| Xml.Element("node", _, _)::list' -> {lan="A"; lat="B"}::read_nodes_from_list list'
| [] -> []
What you're actually trying to do is a map operation on list, so your function could be written more elegantly as follows:
let read_nodes_from_list list =
List.map (fun (Xml.Element("node", _, _)) -> {lan="A"; lat="B"}) list
However, the function may not work because pattern matching on Xml.Element is not exhaustive. You should be careful when handling remaining cases. For example, something like this would work:
let read_nodes_from_list list =
List.map (function | (Xml.Element("node", _, _)) -> {lan="A"; lat="B"}
| _ -> {lan=""; lat=""}) list
To answer your question about record types, it considers a bad practice to have two record types with the same field label. You still can put these record types in different submodules and distinguish them using module prefixes. But as I said, having two similar record types in the same module causes confusion to you and the OCaml compiler.