I'm trying to determine if my hd(tl list) is nothing or not. hd(tl list) = ? What would I use on the other side of the equality symbol?
You can express the question 'is hd(tl list) nothing or not' as the equivalent question, 'does the list have less than two elements'. The latter question is easy to answer with SML in an elegant way using pattern matching on the list. Here is an interactive session:
$ poly
Poly/ML 5.7.1 Release
> fun isNothing [] = true
# | isNothing [_] = true
# | isNothing _ = false;
val isNothing = fn: 'a list -> bool
This function is saying, 'an empty list evaluates to true', 'a list with a single element evaluates to true', any other list evaluates to false. Tests:
> isNothing [];
val it = true: bool
> isNothing [1];
val it = true: bool
> isNothing [1, 2];
val it = false: bool
> isNothing [1, 2, 3];
val it = false: bool
Related
Like the title says, I'm trying to see if two unordered lists include the same values and if these values appear the same amount of times in these lists. The assignment given asks not to order the lists.
Here's what I've done so far:
my logic was to compare recursively if the second list (from now on l2 ) includes the hd (= first element) of the first list ( from now on l1 ) if it does, compare the tl of l1. And as long as I call this isEqual function I would remove the hd of l1 and the first position in which the same value appears in l2. My base case would be that the 2 lists have different lengths then I would know for sure they are not equal.
Here's the code:
fun doesExist l =
List.exists (fn x => x = true) l
; (* returns true if there's at least one 'true' in the list of bool *)
fun getFirstIndex target (a::b) index =
if (a::b) = []
then index
else
if target = a
then index
else getFirstIndex target b index+1
; (* returns the index of the first element = to 'target', in this case 'true',
looking into the list (a::b) *)
fun delete (_, nil) = nil
| delete (0, _::xs) = xs
| delete (i, x::xs) = x::delete(i-1,xs)
; (* should delete an element from a list, given the index gotten with the function above *)
fun isEqual [] [] = true
| isEqual [] _ = false
| isEqual _ [] = false
| isEqual _ _ = false
| isEqual l1 l2 =
if List.length l1 <> List.length l2
then false
else
if doesExist(List.map (fn n => n = hd l1) l2)
then
isEqual(tl l1, delete(getFirstIndex(true, l2, 0), l2))
else
false
; (* this function puts altogether and should return either false or true *)
Below the output this function should return based on the lists passed:
isEqual [] []; (* true *)
isEqual [1] [1]; (* true *)
isEqual [1,4,2,8] [8,1,4,2]; (* true *)
isEqual [1,2,4,3] [11,24,56,7]; (* false *)
isEqual [7,5,12,88] [7,88,12,5,5]; (* false *)
isEqual [7,5,12,88,88] [7,88,12,5,5]; (* false *)
isEqual [7,5,12,88] [7,5,12,88,13,15]; (* false *)
The error in which I encounter is the following:
error: Type error in function application.
Function: delete : int * 'a list -> 'a list
Argument: (getFirstIndex (true, l2, 0), l2) :
((bool * ''a list * int) list -> int -> int) * ''a list
Reason:
Can't unify int to (bool * ''a list * int) list -> int -> int
(Incompatible types)
Found near
if doesExist (List.map (fn ... => ...) l2) then
isEqual (tl l1, delete (...)) else false
es13.sml:24: error: Type of function does not match type of recursive application.
Function:
fun
isEqual [] [...] = true |
isEqual [...] ... = false |
isEqual ... = false |
isEqual ... = ... |
... : ''a list -> ''a list -> bool
Variable: isEqual : ''a list * 'b list -> bool
Reason: Can't unify ''a list to ''a list * 'b list (Incompatible types)
Found near
fun
isEqual [] [...] = true |
isEqual [...] ... = false |
isEqual ... = false |
isEqual ... = ... |
...
Exception- Fail "Static Errors" raised
I think you're overthinking this problem.
fun isEqual [] [] = true
| isEqual [] _ = false
| isEqual _ [] = false
This is good so far, and makes sense.
Now, if neither of the lists are empty, then let's pattern match that so that we can get to the head and tail of the first list.
fun isEqual [] [] = true
| isEqual [] _ = false
| isEqual _ [] = false
| isEqual (x::xs) lst2 = ...
Now, if we remove the value x from lst2 and run the same function recursively on xs and what's left of lst2, we should be able to reduce down to a result.
So let's write a helper remove function. Your delete is on the right track, but it's reliant on an index, and indexes aren't really a natural fit with lists.
The option type is a good choice to represent a case where we try to remove a value that is not in a list. Getting NONE would tell us pretty handily that the two are not equal.
fun remove _ [] = NONE
| remove v (x::xs) =
if v = x then SOME xs
else
case remove v xs of
NONE => NONE
| SOME xs => SOME (x::xs)
I'll let you use this to complete isEqual.
Of course, you could also just sort both lists, and then this becomes much more straightforward.
Question:
What is the logic behind comparing int lists using <, >, =? What about 'a lists?
Code:
# let x = [1] > [1]
val x : bool = false
# let x = [1;2] > [1]
val x : bool = true
# let x = [1;2] > [2;1]
val x : bool = false
# let x = [true;false] < [true;true]
val x : bool = true
Follow up questions:
when comparing two lists, how does the comparison work if the lists are not the same length? if the lists don't contain elements of the same type?
An ocaml list is represented by
type 'a my_list = Nil | Cons of 'a * 'a my_list
The Nil constructor is represented as an integer of value 0 while the Cons is a pointer to a block with tag 0 and 2 fields.
The < > = operators consider Nil < Cons. So if the lists are not the same length then the shorter list is smaller.
Comparison is always between the same types so lists of different types can't be compared (without Obj.magic).
I'm just a begginer in Ocaml, and I wanted to study the graph theory, but with implementations in Ocaml. And I've got a trouble to do something : I just wanted to list the connected components of a graph by using a Depth first search. So, I did :
#open "stack" ;;
let non_empty pile =
try push (pop pile) pile ; true with Empty -> false ;;
let connected_comp g =
let already_seen = make_vect (vect_length g) false in
let comp = [] in
let dfs s lst =
let totreat = new () in
already_seen.(s) <- true; push s totreat;
let rec add_neighbour l = match l with
| [] -> ()
| q::r when already_seen.(q) = false -> push q totreat; already_seen.(q) <- true; add_neighbour r
| q::r -> add_neighbour r
in
while non_empty totreat do
let s = pop totreat in
already_seen.(s) <- true;
(* we want to add s to the list lst *) s::lst;
add_neighbour g.(s);
done
in
let rec head_list l = match l with
| [] -> failwith "Empty list"
| p::q -> p
in
let rec aux comp t = match t with
| t when t = vect_length g -> comp
| t when already_seen.(t) = true -> aux comp (t+1)
| t -> aux ((dfs t [])::comp) (t+1) (* we want that dfs t [] return the list lst modified *)
in aux comp 0;;
And I obtain :
> | t -> (dfs t [])::comp ; aux comp (t+1) (* we want that dfs t [] return the list lst modified *)
> ^^^^^^^^^^^^^^^^
Warning : this expression is of type unit list,
but is used with the type unit.
connected_comp : int list vect -> unit list = <fun>
- : unit list = []
- : unit = ()
Of course, I'm not surprised. But what I want to do is that the function dfs return the list sent on argument (the lst list) but modified, and here it's not the case as the function is of type unit, cause it return nothing. But in Ocaml, as the language is made for returning the last expression I think, I don't know how to do. I could as well use recursive algorithm for the dfs function, as, through filtering, it would permit me to return the list, but I just wanted to learn about Ocaml, and so modified (even if it's not optimal) my algorithm.
Someone could help me, please ?
Edit : As we ask me, I will try to reduce my code and get to the point. So, I have the function dfs which correspond to a Depth first search (for a graph)
let dfs s lst =
let totreat = new () in
already_seen.(s) <- true; push s totreat;
let rec add_neighbour l = match l with
| [] -> ()
| q::r when already_seen.(q) = false -> push q totreat; already_seen.(q) <- true; add_neighbour r
| q::r -> add_neighbour r
in
while non_empty totreat do
let s = pop totreat in
already_seen.(s) <- true;
(* we want to add s to the list lst *) s::lst;
add_neighbour g.(s);
done
in
(alreadyseen is a vector of boolean, defined previously)
And my only problem is that I want that the function return the list lst modified (in the loop while), when, at this point, it's a unit function.
I tried to define lst as a reference, but then I don't know how to return it...
I hope it's more clear, I'm not familiar with all of this at the moment...
Thank you !
Here is a degraded version of your code that demonstrate one way to do what you want.
let non_empty _ = false
let dfs s lst =
let local_lst = ref lst in
while non_empty () do
(*do stuff here*)
let s = 1 in
local_lst := s::!local_lst;
(*do stuff here*)
done;
!local_lst
I first initialize a local mutable value local_lst to the list lst given as an argument. I then update this value in the while loop. And finally I return the value stored in local_lst.
I need to write an SML function that takes in as input a list of tuples (x and y coordinates) and an integer value. The function needs to return true if the integer is an x value in the list and false otherwise. For example if the list was:
val list = [(1,1),(2,4),(3,9),(4,16)];
The function would behave as follows:
memberOf(2, list) = true
memberOf(4, list) = true
memberOf(9, list) = false
Can somebody help me write a function that accomplishes this? I only need to test if the x value is in the list, the y value of the tuple is unimportant.
Thank you!
fun member_of (item, list) = List.exists (fn (x,y) => x = item) list
You can access the first argument of your tuple using #1 tuple and the second one with #2 tuple. So you check if the item exists either as the first argument or the second of the tuple list until you reach the end of your list.
(* fn : int * (int * int) list -> bool *)
fun exists_in (item: int, mylist: (int*int) list) =
if null mylist
then false
else if #1 (hd mylist) = item orelse #2 (hd mylist) = item
then true
else exists_in (item, tl mylist)
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)