SML Combing two functions (min, max) into one (range) - list

Anyway to combine these two functions which take a list and return the highest and lowest element. Want to output both at same time. Cheers
fun max[] = raise Empty
max[x] = x
max(x::xs) =
let
val y = max xs
in
if x > y then x else y
end;
fun min[] = raise Empty
min[x] = x
min(x::xs) =
let
val y = min xs
in
if x < y then x else y
end;

Here is a hint. Use the same basic logic. Write a function minmax to return a pair of values of the form (min,max) and then in the recursive step, use pattern-matching to extract the two values. A template would be:
fun minmax [] = raise Empty
| minmax [x] = (x,x)
| minmax (x::xs) =
let
val (a, b) = minmax xs
in
<fill in the code>
end;
In the above a will be the min and b the max. Given a and b and a third value x, return either (x,b) or (a,x) or (a,b), depending on how the inequalities play out. You will need more than one if.

Here is a different hint: Use a helper function that stores the current (min, max) and return those when finished iterating. A template for that would be:
fun minmax [] = raise Empty
| minmax (y::ys) =
let fun helper [] (min, max) = ...
| helper (x::xs) (min, max) = ...
in helper ys (y, y) end

Related

Generate a Real list from a Int list in SML

Hello every body im training some SMLs and im creating a code to get deviation of a int list . in the process of it , i need to get a Real list out of some numbers in a int list , which it doesnt let me get them. heres my code :
fun mean [] = 0.0
| mean (first::rest) =
let
fun sum [] = 0
| sum (x::xs) = x + sum xs
fun counter [] = 0
| counter (y::ys) = 1 + counter ys
in
Real.fromInt (sum (first::rest)) / Real.fromInt (counter (first::rest))
end;
fun deviation [] = 0.0
| deviation (first::rest) =
let
fun diff (x::xs) = (x - mean (x::xs)) :: diff xs;
in
diff (first , first::rest) + deviation rest
end;
the problem is here :
fun diff (x::xs) = (x - mean (x::xs) ) :: diff xs;
diff is a recursive function, but the base case is never defined. When you try to run diff on an empty list, you will get a pattern match error.
You also define diff to accept a list, but you call it with a tuple.
You define diff as returning a list, given that you are using ::, but then you use addition on the result of that function, which will not work.
Improving mean
You can simplify your sum and counter functions with folds.
fun mean [] = 0.0
| mean lst =
let
val sum = foldl op+ 0 lst
val counter = foldl (fn (_, c) => c + 1) 0 lst
in
Real.fromInt sum / Real.fromInt counter
end;
But this requires iterating the entire list twice, when both pieces of information can be ascertained at the same time.
fun sumLen(lst) =
foldl (fn (x, (sum, len)) => (sum+x, len+1)) (0, 0) lst
mean can now be implemented as:
fun mean(lst) =
let
val (sum, len) = sumLen(lst)
in
Real.fromInt sum / Real.fromInt len
end
Deviation
To get the differences from the mean for a list, you need only use map.
fun diffs(lst) =
let
val m = mean(lst)
in
map (fn x => Real.fromInt x - m) lst
end
Consider evaluating the following.
diffs [1, 2, 3, 4, 5, 6, 7, 8]
The result is:
[~3.5, ~2.5, ~1.5, ~0.5, 0.5, 1.5, 2.5, 3.5]
From there you can use map and Math.pow to square those differences, foldl to sum them, divide by the length of the list, and then Math.sqrt to get the standard deviation.

SML: Comparing every element of two lists without storing state info?

I have an SML assignment, and the general idea is that I shouldn't store state info, should not used built in library functions, etc and just solve in a functional way. Not sure how to do it:
The question requires comparing every element of two lists together:
input
list1: [(3,3,5),(5,4,7),(2,3,4)];
list2: [3, 6];
output
newList: [(3,3,5), (2,3,5)]
Essentially, when the second element in list1's tuple arg matches an item in list 2, then I should add the list1 item to the new output list.
The way I went about implementing it:
fun thing(x, y) =
if null x then []
else if #2 (hd x) = (hd y) then hd x # thing(tl x, y)
else thing(tl x, y);
Obviously the issue with this is that I lose state information: how would you match every element in list1 against every element in list2?
when the second element in list1's tuple arg matches an item in list 2,
then I should add the list1 item to the new output list.
fun thing(x, y) =
if null x then []
else if #2 (hd x) = (hd y) then hd x # thing(tl x, y)
else thing(tl x, y);
Instead of if null x then ..., hd x and tl x, use pattern matching:
fun thing ([], _) = ...
| thing ((x,y,z)::haystack, needles) = ...
To find out if y is a member of needles, build a membership function:
fun elem (p, []) = false
| elem (p, q::qs) = p = q orelse elem (p, qs)
Check if elem (y, needles) to determine whether to include (x,y,z) as part of your result.
Apply thing recursively to haystack and needles.
Compose the recursive result using the :: (cons) operator rather than # (append).
Here's how one could solve this exercise with library functions:
fun curry f x y = f (x, y)
fun thing (haystack, needles) =
List.filter (fn (x,y,z) =>
List.exists (curry op= y) needles) haystack

Find the largest value of a list of lists

Is there a way to find the largest value of a list of lists?
For example
[[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]]
Will ouput: 3
I was thinking of using pattern matching but it seems like it would be nightmareish
let rec lmax list = match list with
| [] -> None
| x :: xs -> Pervasives.max (Some x) (lmax xs)
But the function is not tail-recursive.
The order of evaluation among function arguments is undefined, but basically you compute things like this:
-> Evaluate (Some x)
-> Evaluate (lmax xs)
...recursion...
<- Then, compute max
We have to compute and remember intermediate values for each call to lmax.
Another approach, is to use an auxiliary recursive function aux, which takes an accumulator value acc:
let lmax list =
let rec aux list acc = match list with
| [] -> acc
| x :: xs -> (aux xs (Pervasives.max acc (Some x)))
in (aux list None)
Then, we don't need to store intermediate values:
-> Evaluate xs
-> Compute max of current acc with (Some x)
-> ...recursion...
The recursive call is going to compute the result for current values, there is no need to remember intermediate values, which makes the recursive call iterative.
Fold
The above is a common pattern that can be abstracted away with higher-order functions, known as fold (or reduce). There are two kinds of fold: the first one above is a right fold, the one with an accumulator is a left fold.
They take a reducing function, which computes a new result based on a previous result and a value, as well as an initial result (for empty lists).
Both kinds of fold compute the same result when the reducing function is associative, and due to its tail-recursive implementation, the left fold is recommended whenever possible.
The right fold is used when the reducing function is right associative, like cons. Here is a reimplementation of List.map:
let my_map fn list = List.fold_right (fun x xs -> (fn x) :: xs) list []
Lmax
And so, you can compute the maximum of a list using a left fold:
let lmax list =
List.fold_left
(fun max x -> Pervasives.max max (Some x))
None
list
The option type is necessary because there is no maximum for empty lists (you could return the most negative integer too).
LLmax
Now, you can also compute the maximum of a list of lists using a fold:
let llmax list =
List.fold_left
(fun max list -> Pervasives.max max (lmax list))
None
list;;
For each element of the list of lists, we compute the maximum thanks to lmax and produce the maximum value seen so far.
llmax [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]]
- : int option = Some 3
LL...max
If you want to generalize, you can write a foldmax function which is parameterized by a function which computes the maximum value of an element of a list:
let foldmax fn list =
List.fold_left
(fun max x -> Pervasives.max max (fn x))
None
list
val foldmax : ('a -> 'b option) -> 'a list -> 'b option = <fun>
Finally, you can rewrite lmax, llmax (lllmax, and so on) using this auxiliary function:
let lmax list = foldmax (fun x -> Some x) list
let llmax list = foldmax lmax list
let lllmax list = foldmax llmax list
In an imperative/procedural language you might loop through the list and compare to a maximum number, i.e.
def max(lst):
max = None
for l in lst:
for x in l:
if max is None or x > max:
max = x
return max
(Clearly not idiomatic, just making this as clear a possible)
In OCaml, you would do something similar, but using something called a "fold" (a function), which is sort of an abstraction over the above idea.
let max list =
let f max x =
match max with
| None -> Some x
| Some m -> if m > x then Some m else Some x
in
List.fold_left f None (List.flatten list)
let max l =
List.fold_left (fun max x ->
Pervasives.max max (Some x)
) None (List.flatten l)
Test
# max [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int option = Some 3
# max [];;
- : 'a option = None
Comments
Pervasives.max found the max of two options :
# Pervasives.max None (Some (-1));;
- : int option = Some (-1)
List.flatten : Concatenate a list of lists
# List.flatten [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int list = [1; 2; 3; -4; -2; 0; 1; 2; -5; -3; -1]

building a list of ints in ocaml

I want to write a function that does builds a list between two ints, inclusive
rec myFunc x y would build a list with all the ints between x and y, including x and y
For the logic right now I have something like this:
let rec buildList i n = let x = i+1 in if i <= n then i::(buildList x n)
But this gives me an error "Expression has type 'a list but but an expression was expected of type unit.
I thought buildList is returning a list of ints, and i as an int, so the cons operator would be valid, but its saying it should be void?
Why does this happen, and how do I fix it?
If the condition is true, you return the list i::(buildList x n). If it's not true, what do you return ?
Add else [] to your function to return the empty list when the condition is not met.
When you don't have any else, the compiler supposes it is else () (hence the error message).
Your if is missing an else condition
I suggest that you use a tail recursive function:
let buildList x y =
let (x,y) = if x<y then (x,y) else (y,x) in
let rec aux cpt acc =
if cpt < x then acc
else aux (cpt-1) (cpt::acc)
in aux y []
First, make sure that you ordered your boundaries correctly (idiot-proof), and then construct the list thank to a local recursive function which takes an accumulator.
Two alternatives relying on batteries' package,
Using unfold, which purpose is to build list,
let range ~from:f ~until:u =
BatList.unfold f (function | n when n <= u -> Some (n, succ n) | _ -> None)
Using Enum, allowing to work with lazy datastructure,
# BatList.of_enum ## BatEnum.(1--9);;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
My suggestion, this respects the ordering of the arguments.
let rec iota n m =
let oper = if n < m then succ else pred in
if n = m then [n] else n :: iota (oper n) m
Edit:
The operator selection is inside the recursive part, it should better be outside like this:
let iota n m =
let oper = if n < m then succ else pred in
let rec f1 n m = if n = m then [n] else n :: f1 (oper n) m in
f1 n m
At more than 200000 elements I get a stack overflow (so here we are)
# iota 0 250000;;
Stack overflow during evaluation (looping recursion?).
Todo: tail recursion
let buildList i n =
let rec aux acc i =
if i <= n then
aux (i::acc) (i+1)
else (List.rev acc)
in
aux [] i
Test:
# buildList 1 3;;
- : int list = [1; 2; 3]
# buildList 2 1;;
- : int list = []
# buildList 0 250000;;
- : int list =
[0; 1; 2; 3; .... 296; 297; 298; ...]

Checking the contents of a char list list in sml

My question is like the one here.
I'm working on a char list list and I need to check that 1-9 are used once in every list, but also once in every position in the list.
My code looks like this:
infix member
fun x member [] = false
| x member (y::ys) = x = y orelse x member ys;
fun rscheck xs =
let
val ys = [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]
in
ys member xs
end;
but this only checks if 1-9 are members of the lists, not if they're on the same position in different lists.
I had the idea to use this function:
fun poslist xs n = map (fn x => List.nth (x , n)) xs;
(the function poslist is supposed to return whatever is in position n of the list xs, so I can isolate the individual lists in the char list list), but since poslist returns a char list rscheck can't work with it as it needs a char list list.
1) Can I improve poslist?
2) How do I fix rscheck?
Edit
infix member
fun x member [] = false
| x member (y::ys) = x = y orelse x member ys;
fun samelist (x::xs) ys = x member ys andalso samelist xs ys
| samelist [] _ = true;
fun takelist xs n = map (fn x => List.nth (x , n)) xs;
fun reverse xs = List.tabulate (9 , fn x => takelist xs x);
fun rscheck xs =
let
val s = [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]
in
List.all (fn x => samelist s x) xs
end andalso rscheck (reverse xs);
Your rscheck method just checks whether one of the rows is equal to [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]. What it should do is check that all the rows contain the numbers in any order. Once you fix that you can solve the rest of the problem as follows:
The easiest way to check whether a matrix is a valid sudoku solution is to use your rscheck function on it, then transpose it (i.e. switch its rows and columns) and then use your rscheck on the transposed matrix. If it returns true both times, it's a valid sudoku solution.
To transpose the matrix you can either translate this OCaml code to SML, or simply use your poslist function for all indices from 0 to 8.