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).
Related
I am a beginner in OCaml and I'm trying to understand functors, I'm developing a "general sort function" with functors that can takes array, list, string and return an ordered list, array, string.
Can someone help me with this?
I've done this
module type Comparable= sig
type t
val compare : t -> t -> int
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
end;;
module Make_sort(S: Comparable)= struct
type t= S.t
type et= S.t list
let order t= function
|[] -> 0
|a::b -> S.fold_left (S.compare (a t)(b t)) ;;
end;;
First of all, I think that your intuition is correct but there is small confusion between the value level and the type level, ie: S.compare (a t)(b t) this expression is not valid (a and b) must be functions, this why I think that you try to give the sense of 'a t.
But, I understand what you try to do, so here is a small primer on functor (function from module to module), using a small subset of your example.
First, in order to sort we need to define how to order
Exactly as you did, we can start with a signature (COMPARABLE) which handle the "notion of comparison". For example:
module type COMPARABLE = sig
(** something which is comparable. *)
type t
(** [compare x y] returns 1 if x > y, 0 if x = 0 and -1 if x < 0 *)
val compare : t -> t -> int
end
With this signature, it is easy to define module which are comparable, for example, for Int:
module Int_comparable :
COMPARABLE with type t = int =
struct
type t = int
let compare x y =
if x > y then 1
else if x = 0 then 0
else -1
end
Note that module are candidate for a signature only if the module match the signature so de anotation : COMPARABLE with type t = int is not very necessary. And, since Int (the module from the stdlib) already implement compare and a type t, it is not necessary to define it. You can just pass Int when you need a comparable.
Now, we can define somethign "sortable"
In this very small example, something which is comparable seems to be sortable. In other words, if I have a COMPARABLE, I can sort. This relation (If I have X, I can have Y) seems quite suitable for using a functor (so, I give you a COMPARABLE and you give me something sortable). Here is a proposition:
module Sortable (C : COMPARABLE) : sig
(** if something is comparable, it is sortable. *)
type t = C.t
(** [max_of x y] returns the greater between x and y. *)
val max_of : t -> t -> t
(** [min_of x y] returns the lower between x and y. *)
val min_of : t -> t -> t
(** [sort x y] returns an ordered tuple [(max_of x y, min_of x y)]. *)
val sort : t -> t -> (t * t)
end = struct
type t = C.t
let max_of x y =
let value = C.compare x y in
if value > 0 then x
else y
let min_of x y =
let value = C.compare x y in
if value < 0 then x
else y
let sort x y =
if (C.compare x y) >= 0 then (y, x) else (x, y)
end
It is probably possible to add more helpers in the module, but I'll keep the implementation as simple as possible. So now, if I want have sortable capabilities for Int.t I can just use the module Int (from stdlib: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Int.html) which has a type t and compare like this
module Sortable_int = Sortable (Int)
Now, you have the basis. For traversing using Sort, you can implement a signature (Foldable for example) and I think you have all the bricks in your hands to generalize the logic of sorting collections (modulo a little algorithmic!)
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
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)
I want to check if a matrix of type [[a,b,c][d,e,f]] contains a specific number.
I'm having trouble accessing the list inside the list.
let matrix = [[1;2;3]; [4;5;6]];;
let rec contains mat x = match mat with
| [] -> false
| h::t -> if (h=x) then true else contains t x;;
This work on a one-dimensional list, but I'm just too much of a newbie to get it to work on a two-dimensional.
First off, your function contains is List.mem in the standard library (not that there is anything wrong with reimplementing it to learn OCaml).
Also, if (h=x) then true else contains t x is usually written (h=x) || contains t x.
As for your problem, you need to iterate over each sublist of the matrix (presumably representing a row), and for each row check if it contains the number you're looking for :
# let rec mat_contains mat x = match mat with
| [] -> false
| row::tl -> contains row x || mat_contains tl x;;
val mat_contains : 'a list list -> 'a -> bool = <fun>
# mat_contains matrix 4;;
- : bool = true
As an aside, here it is written using functions in the standard library :
# let mat_contains2 mat x = List.exists (List.mem x) mat;;
val mat_contains2 : 'a list list -> 'a -> bool = <fun>
# mat_contains2 matrix 4;;
- : bool = true