I want to make a if condition like this:
if
((head(c) = 1) or (head(c) = ~1) or (head(c) = ~5) or (head(c) = ~17) or (head(c) = 0))
count +1
else..
the function head return 'a;
It gives me the next error: operator is not a function [tycon dismatch]
operator: bool
in expression
What is the problem? thank you.
I think it's called orelse in SML.
It's called orelse, not just or and andalso instead of and. But orelse and andalso are not functions. Citation from Programming in Standard ML '97:
Note in particular that andalso and orelse are not infix functions because they are not strict in their second argument—that is, they do not always force the evaluation of their second argument—and such functions cannot be defined in a strict programming language such as Standard ML. Thus we cannot apply the op keyword to andalso or orelse.
For this example, you could also write:
let val h = head c in
if List.exists (fn x => x = h) [1, ~1, ~5, ~17, 0]
then count + 1
else ...
end
Related
I am new to SML. I am trying to check whether a given value exist in the binary tree or not. Below is the snippet of the code. Upon execution it gives
Warning : match nonexhaustive (n,Node (t1, j, t2)) => ...
I cannot understand why it is showing this way. I guess I have covered all possible case. Can anyone give me hint or link which will be helpful to remove this warning.
datatype inttree = Empty | Node of inttree * int * inttree;
(*find(n,K) here n is the key that we have to find in inttree K*)
val rec find = fn(n, Node(t1,j,t2)) =>
let
val t = Node(t1, j, t2)
val compare = fn(i,j) => i = j
val find' =
fn (n,Empty) => false (* if we have reached the empty node then we are not able to find the key therefore return false *)
| (n,Node(t1,j,t2)) =>
if compare(n,j)
then true (* if value n and j are equal we have found the key n in the tree*)
else find(n,t1) orelse find(n,t2) (* if the value is not equal check in left subtree if found return true else check in the right subtree*)
in
find'(n,t)
end;
Given your datatype declaration, a fairly direct recursive approach is possible. Since this seems to be homework, I don't want to give a complete solution, but here is a function which has a similar flavor:
fun allEven Empty = true
| allEven (Node(t1,i,t2)) =
if i mod 2 = 1 then false
else allEven t1 andalso allEven t2;
This function returns true or false depending on whether or not all integers in the tree are even. It has a basis case
allEven Empty = true
(true since there are no odd numbers in an empty tree to serve as counter-examples) and a recursive case
allEven (Node(t1,i,t2)) =
if i mod 2 = 1 then false
else allEven t1 andalso allEven t2;
If the integer at the node is odd, return false -- otherwise return true if the recursive call to both branches evaluate to true.
Typical runs:
- allEven (Node(Node(Empty,3,Empty),5,Node(Node(Empty,6,Empty),7,Empty)));
val it = false : bool
- allEven (Node(Node(Empty,4,Empty),2,Node(Node(Empty,6,Empty),8,Empty)));
val it = true : bool
Your function should be about this long and follow the same basic recursive pattern.
Besides val rec, you can also write fun and specify the arguments on the left-hand side of the =.
The helper function compare is largely redundant. You might as well use =. Also, what one would call a compare function in ML is usually one that returns the type order, having the values LESS, EQUALS and GREATER:
- Int.compare (3, 5);
> val it = LESS : order
When writing an if ... then true else ... or similar statement that returns the type bool, you might as well just use the combinators orelse and andalso. For example, you can replace the following:
if compare(n,j)
then true
else find(n,t1) orelse find(n,t2)
with:
n = j orelse find (n, t1) orelse find (n, t2)
Much like the built-in functions List.exists and List.all take a function as predicate and scans a list in the attempt to prove either that at least one element exists for which this is true, or that it is true for all elements, you can make functions treeExists and treeForall:
datatype intTree = Empty | Node of inttree * int * inttree;
fun treeExists f Empty = false
| treeExists f (Node (leftTree, x, rightTree)) =
f x orelse treeExists f leftTree orelse treeExists f rightTree
fun treeForall f Empty = true
| treeForall f (Node (leftTree, x, rightTree)) =
f x andalso treeForall f leftTree andalso treeExists f rightTree
Making functions find and allEven has now become simpler:
fun find (x, tree) = treeExists (fn y => x = y) tree
fun allEven tree = treeForall (fn x => x mod 2 = 0) tree
since all the recursion has been left to new library functions.
In a similar way, you can make treeMap and treeFold:
fun treeMap f Empty = Empty
| treeMap f (Node (leftTree, x, rightTree)) = ...
fun treeFold f e Empty = e
| treeFold f e (Node (leftTree, x, rightTree)) = ...
They could be used to find the largest absolute value in a tree:
fun maxAbsTree tree =
treeFold Int.max 0 (treeMap Int.abs tree)
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 far I have
let flipeven(listname)=
let newlist= [] in
let first=0 in
let second=1 in
let stop= List.length(listname)-1 in
let rec flipevenhelper (x,y)=
if (second<= stop) then
insert((List.nth(listname) x), newList) in
insert((List.nth(listname) y), newList) in
let second=second+2 in
let first=first+2 in
flipevenhelper (first, second)
else
newList;;
But just receive a syntax error at the else statement. What exactly am i doing wrong?
edit:
Here is the insert function
let rec insert (x,y) = match (x, y) with
| (x,[ ]) -> x::[]
| (x,y::ys) -> if (x>y) then (y:: insert(x, ys))
else (x::y::ys);;
The in keyword is always paired with a let keyword. It's not a general way of joining two expressions, which is what you seem to want.
The ; operator in OCaml does join two expressions into a single expression. The first expression is evaluated but then ignored (it should have unit type). The second expression is evaluated, and its value is the value of the combined expression.
Note that ; has lower precedence than if/then/else (in some sense). So you should parenthesize the expression after then if you use the ; operator.
Here's a small example:
# if 3 > 2 then Printf.printf "yes\n"; 4 else 5;;
Error: Syntax error
# if 3 > 2 then (Printf.printf "yes\n"; 4) else 5;;
yes
- : int = 4
After fixing the syntax, you still have many things to fix. In particular, you should realize that variables and lists in OCaml are immutable. You can't insert into your list newList just by calling insert.
I am trying to achieve the following: Finding the element at a specific index.
So if I had a list of [5; 2; 3; 6] and ask for the element at index 2, it would return 3.
let counter = 0;;
let increase_counter c = c + 1;;
let rec get_val x n = match x with
[] -> -1
| (h::t) ->
if (counter = n) then
h
else
increase_counter counter ; get_val t n
;;
But this code is giving me a bug saying that -1 is not of type 'unit'?
As Jeffrey Scofield said, you should write let counter = ref 0 to make counter mutable. Now, you can use the built in incr function to increment it (equivalent to counter := !counter + 1), and you'll get its value with !counter.
There is also a problem in your algorithm : if the counter is equal to n, you return the head of the list... you mean : if the head of the list is equal to n, you return the counter.
Your program is then :
let counter = ref 0;;
let rec get_val x n = match x with
[] -> -1
| (h::t) ->
if (h = n) then
!counter
else
begin incr counter ; get_val t n end
;;
Note that I've added begin and end around the else block so it can be interpreted as a sequence of instructions.
Your program now works, but it is not the best way to solve this problem with ocaml.
You should write something like
let get_val x n =
let rec get_val_aux x n counter = match x with
| [] -> -1
| h :: _ when h = n -> counter
| _ :: t -> get_val_aux t n (succ counter)
in
get_val_aux x n 0
;;
Here, we add a parameter to the get_val_aux function which we increment at each call. This function is nested within the get_val function to hide this additional parameter which is initialized with 0 on the first call.
Instead of using an if statement, we use the when condition to know when the element has been found, and add a new case to match the last case (not found). Note the use of the _ wildcard to avoid an unused variable.
The succ function (for successor) only adds 1 to its parameter. It is equivalent to counter + 1.
There are many problems with this code. If you ignore your immediate problem for a moment, you are treating OCaml variables like the variables of an imperative language. However, OCaml variables are immutable. This function
let increase_counter c = c + 1
Doesn't change the value of any variable. It just returns a number 1 bigger than what you give it.
The only error I get from the toplevel when I enter your code is for this expression:
increase_counter counter ; get_val t n
The compiler is warning you that the expression before ; is supposed to be executed for its side effects. I.e., it should almost always have type unit. Since (as I say) your function increase_counter returns an int, the compiler is warning you about this.
Update: What I want to do with this code is to get a list of dates, year/month/day and a given number as a month, and check to see how many of the dates in the given list are in the same month as that given month. What I meant of x = x + 1 was x++ such as in java or C or C#. As the output I want x. if there is no match, 0 and for any match x = x + 1
So this is my code,
fun number_in_month (Dlist : (int * int * int) list, Month : int, x : int) =
if null Dlist then x
else if #2 (hd Dlist) = Month then x = x + 1 andalso number_in_month (tl(Dlist), Month, x)
else number_in_month ((tl(Dlist)), Month, x)
and it gives me error:
Error: types of if branches do not agree [tycon mismatch]
then branch: int
else branch: bool
in expression:
if null Dlist
then x
else if (fn <rule>) (hd <exp>) = Month
then (x = <exp> + <exp>)
andalso (number_in_month (<exp>,<exp>,<exp>))
else number_in_month (tl <exp>,Month,x)
I really don't get it why sml is considering x = x + 1 of type bool. I'd be really happy if someone could tell me how can I correctly say x = x + 1 in sml.
Thanks a lot in advance.
Saying x = x + 1 in Standard ML, you need to clarify what you intend to say, because clearly x = x + 1 means something you don't intend. What it means is "Compare x with x + 1 and say if they are equal" (which they never will be of any integer).
What I suppose you want to achieve is "update x to its successor", which is not possible without the use of reference types, which I discourage since they are not immutable and functional. The way you usually update something functionally is by passing an updated value to a function that eventually returns it. (Using function arguments as accumulating variables, so it feels as if it's the same variables that update their value e.g. upon each recursive call.)
Another thing I recommend that you do is use pattern matching instead of if-then-else. For example, you know that the list is empty if it matches []. Since the result of your computation is not a boolean, you cannot use "... andalso ..." -- I suspect you do this because you "want to do two things at once, and andalso smells like "doing something and also doing something else", but this would be a misconception. You can do this (using e.g. ; or before), but you would lose your result because these operators deal with side-effects and discard the main effect of one of their operands, so it is not what you want at this point.
Here is my stab in the dark at what you intended, written using pattern matching:
fun number_in_month ([], _, x) = x
| number_in_month ((one,two,three)::dlist, month, x) =
if two = month then number_in_month(dlist, month, x+1)
else number_in_month(dlist, month, x)
Modified: You can also do this without tail-recursion
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
if month1 = month2 then 1 + number_in_month(dlist, month2)
else number_in_month(dlist, month2)
Or written differently:
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
(if month1 = month2 then 1 else 0) + number_in_month(dlist, month2)
Or using list combinators:
fun counter(n1,n2) = if n1 = n2 then 1 else 0
fun number_in_month(dlist, month2) =
foldl (fn ((_,month1,_),count) => counter(month1,month2) + count) 0 dlist
Or using reference, as you asked for, even though I discourage this:
fun number_in_month (dlist, month2) =
let val count = ref 0
fun loop [] = !count (* the value inside the ref-cell *)
| loop ((_,month1,_)::dlist) =
if month1 = month2 then (count := !count + 1 ; loop dlist)
else loop dlist
in loop dlist end
As you can see, some complexity is added because I wish to create the ref-cell within the function, but I cannot create a new ref-cell upon every recursive call. So I create a helper function that is recursive and let it have the argument that changes during recursion (it can just inherit month2 and count from the parent scope of number_in_month. When recursion ends (base case), I choose to return the value within the ref-cell (using Standard ML's slightly obscure syntax for dereferencing).
Don't make it a habit of using ref-cells before you master the functional way. Otherwise you are back to coding imperatively in a language that makes this habit ugly. :)