Why is this Ocaml statement giving me a syntax error?
let a = 0;; if a = 0 then let b = 0;;
Do if then else statements always have to return a value?
EDIT: Here is the code I am struggling with. I want to apply this function over a list with the map function. The function is supposed to look at each word in the list wordlist and add to the stringmap. If it has already been added to the string map then add 1 to its password.
module StringMap = Map.Make(String)
let wordcount = StringMap.empty
let findword testword =
let wordcount = (if (StringMap.mem testword wordcount)
then (StringMap.add testword ((StringMap.find testword wordcount)+1) wordcount)
else (StringMap.add testword 1 wordcount))
List.map findword wordlist
You can only have an if then without else if the then expression evaluates to unit () Otherwise, the expression will not type check. An if without an else is equivalent to writing if x then y else () which can only type check if y is unit.
Check this out for a reference.
(Terminology note: there are no statements in OCaml because everything is an expression, so the term "if statement" doesn't quite apply. I still understood what you meant, but I thought this was worth noting)
Yes, if is an expression in OCaml, not a statement. The best way to look at it is that there are no statements in OCaml. Everything is an expression. (Admittedly there are expressions that return (), which are similar to statements.)
You can only have if b then e if the type of e is unit (i.e., if it returns ()).
Note also that you can't just say let v = e, except at the top level of a module. At the top level it defines a global name in the module. In other cases you need to say let v = e1 in e2; the let defines a local symbol v for use in the expression e2.
One answer to the let b = problem - it works like this:
let a = 0
let b = if a = 0 then 0 else 1
(* or whatever value you need in the else branch *)
And then the Map problem: the manual says Map is applicative - that means Stringmap.add returns a new map. You must use a ref to store your map - see this ocaml toplevel protocol:
# module StringMap = Map.Make(String);;
# let mymap = ref StringMap.empty ;;
val mymap : '_a StringMap.t ref = {contents = <abstr>}
# mymap := StringMap.add "high" 1 !mymap;;
- : unit = ()
# StringMap.mem "high" !mymap;;
- : bool = true
# StringMap.mem "nono" !mymap;;
- : bool = false
# StringMap.find "high" !mymap;;
- : int = 1
# StringMap.find "nono" !mymap;;
Exception: Not_found.
Related
Why am I getting Warning this expression should have type unit with this code? although it does what it should do.
let matchInf42 list =
let a = ref 0 in
let lstLength = List.length list in
let rec matchInf4242 list =
match list with
|[]->[]
|m::body->
begin
if (m < 42) then a := !a + 1;
matchInf4242 body
end
in matchInf4242 list;
if(!a = lstLength) then -1 else 0
Warning:
ocamlopt match.ml -o m
File "match.ml", line 14, characters 7-24:
14 | in matchInf4242 list;
^^^^^^^^^^^^^^^^^
Warning 10: this expression should have type unit.
TL;DR: The error you obtain is a typical type error (mostly)
"Mostly" because, admittedly, it is not an "error" but a mere "warning" here, yet it appears this kind of warning (Warning 10: non-unit-statement) is always worth being addressed (i.e., avoided).
It is actually an instance of the following pattern:
42; print_string "…" ;;
(* or more generally *)
any_value_not_having_type_unit; any_value_having_type_unit ;;
(* which would raise *)
> Characters 0-2:
> 42; print_string "…";;
> ^^
> Warning 10: this expression should have type unit.
> …- : unit = ()
Further details
Just to recall, unit is a singleton type (which only has the value ()) and is typically chosen to assign a return type to functions that "return no specific value" but produce some side-effect.
Actually, the sequence operator is "a bit more general / more flexible" as what we might expect:
# let semicolon i j = i; j ;;
val semicolon : 'a -> 'b -> 'b = <fun>
That is to say, it's not semicolon : unit -> 'b -> 'b, and thereby the message we got for the code i; j when i does not have the type unit, is a mere warning, not a type error.
Fixes/workarounds
Two strategies to avoid this warning:
Either ignore it by relying on the ignore function
# ignore;;
- : 'a -> unit = <fun>
# ignore 42; print_string "…";;
…- : unit = ()
Or change/fix the way you compute the left-hand side of the sequence (so its type is unit).
In the particular case of your question example, it would suffice to write this (the only change being indicated with a symbol §):
let matchInf42 list =
let a = ref 0 in
let lstLength = List.length list in
let rec matchInf4242 list =
match list with
|[] -> () (*←§*)
|m::body->
begin
if (m < 42) then a := !a + 1;
matchInf4242 body
end
in matchInf4242 list;
if(!a = lstLength) then -1 else 0
Extra remark
Finally for completeness (even though it was not explicitly part of your question), note that the example function you considered could also be implemented in a more "functional" style (without references nor sequences, avoiding also the need for calling the List.length function beforehand):
let matchInf42 l =
if List.for_all (fun m -> m < 42) l
then -1 else 0
(* or *)
let matchInf42 l =
if List.fold_left (fun r e -> r && e < 42) true l
then -1 else 0
Change
matchInf4242 list
to either
ignore (matchInf4242 list)
or
matchInf4242 list in ().
This makes the statement return () (i.e. a unit), which is what ocaml expects.
I want to define a function check_char_fun: (char -> 'a) -> (char ->' a) -> bool that, given two functions
on char, return true when both functions are the same (ie, when they are exactly the same behavior on every one of the possible values of a char) and false otherwise.
let check_char_fun f1 f2 =
let aux = true
for i=0 to 255 do
if (f1 (char_of_int i))=(f2 (char_of_int i))
then aux=false;
done;
if aux=true
then true
else false;;
I am learning OCaml, so I don't know what can I do.
You're nearly there:
let check_char_fun f1 f2 =
let aux = ref true in
for i = 0 to 255 do
if (f1 (char_of_int i)) = (f2 (char_of_int i)) then aux := false
else ()
done;
!aux
Unlike the variables in imperative languages, bindings in OCaml are immutable by default. To create a real variable, we create a bool ref which is mutable and can be changed from within the loop.
OCaml does not have a distinction between statements and expressions like the imperative languages: There are only expressions! Thats why you always need the else clause to an if; this ways the resulting expression always returns a value (in both if and else case) the type of which must be the same -- in this case of type unit (the type of the value () -- which would be void in C).
Your code is not very OCaml-like, but thats what I personally love about OCaml: The functional style is not forced down your throat and you can implement algorithms in an imperative style without entering the academic ivory tower.
First, you have to have a definition for what a "behavior" is. If your functions can raise exceptions the problem gets harder. Your code assumes the functions always return a value, which seems like a good simplification for a beginning problem.
You're also using the (somewhat out-of-date) definition of character that OCaml uses, in that codes are limited to the range 0 .. 255. This also seems OK.
So the only problem I see in your code is that you're expecting to be able to change the value of the aux variable. Variables in OCaml are immutable: you can't change the value that they're bound to.
If you want to keep your code mostly as it is, you can change aux so its value is a reference to a bool. Then you can change the boolean value inside the reference (while aux remains bound to the same reference).
To make a reference to a bool and change the value:
# let x = ref true;;
val x : bool ref = {contents = true}
# !x;;
- : bool = true
# x := false;;
- : unit = ()
# !x;;
- : bool = false
(One of the reasons to study OCaml is to learn how to work with immutable values. So I'd suggest looking for other ways to solve the problem that don't require the use of references.)
let rec range i j =
if i > j then [] else i :: (range (i+1) j);;
let check_char_fun f1 f2 =
let lc = List.map char_of_int (range 0 255) in
List.for_all (fun c -> (f1 c) = (f2 c)) lc;;
test:
#let id x =x;;
val id : 'a -> 'a = <fun>
# check_char_fun id id;;
- : bool = true
# check_char_fun id (fun x -> 'a');;
- : bool = false
Or:
exception Fails_in of char;;
let check_char_fun f1 f2 =
let lc = List.map char_of_int (range 0 255) in
List.iter (fun c ->
if (f1 c) <> (f2 c) then raise (Fails_in c)
) lc;;
# try (
check_char_fun id id
) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
;;
- : unit = ()
# try (
check_char_fun id (fun x -> 'a')
) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
;;
Diff(0)()- : unit = ()
The following applies each function to each character value in the 0 .. 255 range and compares their results, but it does not check for cases where a function raises an exception or causes a side effect elsewhere:
open Core.Std
let check_char_fun f1 f2 =
let chars = List.map ~f:char_of_int (List.range 0 256) in
List.for_all ~f:(fun c -> (f1 c) = (f2 c)) chars
So I am a little new to OCaml and I am trying to figure out a way for my function to check multiple conditions and modify a variable if any of those conditions are true
rough pseudo code would be
var list = []
if cond1 then 1::list
if cond2 then 2::list
etc
but from what I am able to tell once you enter an if statement you stay in it until it returns a value to the function. Is there a way around this limitation? Thanks for your time, tips or hints are greatly appreciated as I would love to understand the language
OCaml variables are immutable, you can't change their values. So you need to think of this a different way. One reasonable thing would be to have a function whose value is equal to a supplied list with something added to the front:
let f list =
if cond1 then 1 :: list
else if cond2 then 2 :: list
else 3 :: list
Note that if in OCaml is an expression, i.e., it has a value. It's similar to the ?: ternary operator in languages influenced by C.
Here is an OCaml session that shows a function like this. It's just an example, this isn't a useful function:
$ ocaml
OCaml version 4.01.0
# let f list =
if List.length list > 3 then 1 :: list
else if List.length list > 1 then 2 :: list
else 3 :: list ;;
val f : int list -> int list = <fun>
# f [];;
- : int list = [3]
# f [1;2];;
- : int list = [2; 1; 2]
Update
If you want to apply the ifs all the time the code looks like this:
let f list =
let list' = if cond1 then 1 :: list else list in
let list'' = if cond2 then 2 :: list' else list' in
let list''' = if cond3 then 3 :: list'' else list'' in
list'''
You can capture the repeated pattern in its own function:
let f list =
let cpfx cond pfx l = if cond then pfx :: l else l in
cpfx cond3 3 (cpfx cond2 2 (cpfx cond1 1 list))
If you want to have a sequence of if statements, each if must return unit. You can use a reference to your list to make it mutable, put semicolons after each if statement and return the referenced list at the end:
let f list =
let list = ref list in
if cond1 then list := 1 :: !list;
if cond2 then list := 2 :: !list;
[...]
!list
;;
The given list will not be modified, there is just a new variable called list that shadows the original one within the function definition.
Given this following code (which does not work):
fun func() =
val decimal = 0 (* the final result *)
val multiple = 0 (* keeps track of multiples, eg. In XXV, X would be a multiple *)
val current = 0 (* the digit currently being processed *)
val top = 0 (* value of the last element in the list *)
val last_add = 0 (* the last digit that wasn't a multiple, or subtraction operation *)
val last_sub = 0
val problem = 0 (* if value is 1 then there is a problem with the input *)
val myList = [1,2,3,4,5] (* the list has more values *)
val current = tl(myList) (* grab the last element from the list *)
val myList = tl(myList) (* remove the last element from the list *)
val top = tl(myList) (* grab the value at the end of the list *)
while (not(myList = [])) (* run while the list is not empty *)
if ( (not(myList = [])) andalso (current > top))
then
val decimal = decimal + current - top
val last_sub = top;
val myList = tl(myList)
else
if ( (myList = []) andalso (current = top))
then val decimal = decimal + current
val multiple = multiple + 1
else
if (last_sub = current)
then val problem = 1
else
val decimal = decimal + current
val multiple = 0
val last_add = current
This is only a partial code , which doesn't work at the moment , since the val is not
possible within an if statement .
I want to run in a while loop , how can I do that in ML ?
How can I assign and reassign values into variables that were previously declared in ML ?
The val keyword is not possible within the IF condition , so I cannot update the variables , any idea how to solve that ?
Regards
How can I assign and reassign values into variables that were
previously declared in ML ?
You cannot assign to variables after they are declared in ML.
The val keyword is not possible within the IF condition , so I cannot
update the variables , any idea how to solve that ?
Except at the top level, you usually use val and fun inside a let:
let
val x = blah blah
val y = blah blah
fun f x y = blah blah
in
some expression
end
However, note that this creates a new variable (which may hide any existing variable of the same name), which exists inside the scope of the body of the let. As said before, you cannot assign to an existing variable.
I want to run in a while loop , how can I do that in ML ?
You are almost there. The syntax is while condition do ( ... ). But a while loop is useless without mutable state.
If you want mutable state, you can use a mutable data structure. The language provides a simple "mutable cell" called ref: you create it by passing the initial value to the ref function, you get the current value with the ! operator, and you set a new value with the := operator. You also have to remember that if you want to run multiple imperative "statements", you must separate them with the ; operator, and possibly enclose the whole "block" of statements in parentheses due to precedence issues.
But using while loops and mutable state is really not the right way to go here. You are using a functional language, and it would be much better for you to re-write your algorithm to be purely functional. It's not hard to do. You would turn the body of your while loop into a tail-recursive helper function, and the "variables" that change between iterations of the loop would become arguments to this function. Instead of trying to "set" the values of these variables, it would simply recursively call itself with the new values for the next iteration. If it's tail-recursive, it's equivalent to iteration memory-wise.
The doc of Lazy.lazy_from_val states that this function is for special cases:
val lazy_from_val : 'a -> 'a t
lazy_from_val v returns an already-forced suspension of v This is for special purposes only and should not be confused with lazy (v).
Which cases are they talking about?
If I create a pair of suspended computation from a value like:
let l1 = lazy 123
let l2 = Lazy.lazy_from_val 123
What is the difference between these two? Because Lazy.lazy_is_val l1 and Lazy.lazy_is_val l2 both return true saying that the value is already forced!
The special purpose would be if you need a lazy value but you sometimes have an already computed (non-lazy) value. You can use lazy_from_val to turn an already computed value into a (forced) lazy version of your value.
let f lazyint =
Lazy.force lazyint + 42
let li = lazy 4;;
# f li;;
- : int = 46
# f 14;;
^^
Error: This expression has type int but an expression was expected of type
int Lazy.t = int lazy_t
# f (Lazy.lazy_from_val 14);;
- : int = 56
In this (contrived) example, you might wish to call f with an ordinary integer value (14, in this example). You can do it, but you need to use Lazy.lazy_from_val to make it work.
The key difference is that lazy takes an expression of type 'a and creates a suspended computation (in essence, a closure) of type 'a lazy_t. Lazy.lazy_from_val takes a pre-computed value of type 'a and converts it to a (pre-forced) value of type 'a lazy_t. If the expression has side-effects, the difference between the two can be seen.
# let p () = print_string "here\n"; 3 ;;
val p : unit -> int = <fun>
# let l1 = lazy (p ());;
val l1 : int lazy_t = <lazy>
# let l2 = Lazy.lazy_from_val (p ());;
here
val l2 : int Lazy.t = lazy 3
# f l1;;
here
- : int = 45
# f l2;;
- : int = 45
#
You could implement lazy operations directly using explicit closures and references. As Matthias Benkard points out, OCaml's lazy mechanism uses special syntax to make it less cumbersome to work with. I.e., lazy is an OCaml keyword, not a function.
lazy_from_val is a function rather than syntax. Thus,
# let id = fun x -> x;;
val id : 'a -> 'a = <fun>
# Lazy.lazy_is_val (lazy (id 123));;
- : bool = false
# Lazy.lazy_is_val (Lazy.lazy_from_val (id 123));;
- : bool = true