(sml) I want to count the number of corresponding values in the list - sml

I would like to know the number of cases in which 1 dollar can be expressed in 1,5,10,20,50 cents.
For example, the count(100,[50,25]) is:
Because 50 * 1 + 25 * 2, it = 3:int is printed.
However, in my code, only the front part of the list is printed, so even if I count (100,[50,25]), it = 2:int is printed.
In other words, My code is not taking advantage of the whole list.
How do I solve this?
SML coin count function:
fun count(x,[]) = 0
| count (x,y::ys) =
let val cnt = 0
in if y*2 = x then cnt+2
else if y*4 = x then cnt + 4
else if y*10 = x then cnt + 10
else if y*10 = x then cnt + 10
else if y*20 = x then cnt + 20
else count(x-y,ys)
end;

Consider what happens as you evaluate your test expression of count (100, [50, 25]).
cnt is 0, y is 50, and ys is [25].
y times 2 does equal 100, so it returns cnt+2 which is 2. Nothing further happens.
When it comes to recursion, remember than the parameter list to a function is your means of communication. It seems like cnt is something that should be passed as a parameter so you can update it between recursive calls.
With count(x, []) = 0 you already have an exit point that will stop the recursion.
Edit: Based on comments, it looks like you're trying to figure out how many times each value in a list goes into a value x.
So the end result of your recursive function isn't a single integer. It's a list of integers. Or better yet, of tuples containing the value to look for, and the number of times it goes into x.
So if the list is empty, the result is obvious.
fun count(x, []) = []
It's an empty list. Otherwise, we need to append something onto a list.
fun count(x, []) = []
| count(x, y::ys) =
(y, x div y) :: count(x, ys)
Of course, we also have functions like map that basically do this for us.
fun count(x, lst) = List.map (fn y => (y, x div y)) lst

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, How to find number of occurrences of the minimum number in a list?

In SML is it possible to find the number of occurrences of the min number in a list?
I have code to find the number of occurrences of a number but i am stumped on how to find the min and use it to find how many of the minimum num there is.
fun occurrences(nil, n)=0
| occurrences(ls, n) =
if hd(ls)=n then occurrences(tl(ls),n) + 1
else occurrences(tl(ls),n) + 0;
Thank you!
You can write a function that keeps track of the min value and its count as you iterate through the list.
We can do this by implementing a tail-recursive function which helper, which maintains the value of the current minimum and a count of the number of times that item has appeared.
We can then wrap this in another function min_count via a let-in-end block.
For example:
fun min_count [] = 0 (* the empty list has zero items in it *)
| min_count (x :: xs) =
let
(* when we reach the end of the list, return the accumulated count *)
fun helper (_, n) [] = n
| helper (m, n) (y :: ys) =
(* if we find a new minimum, reset the count *)
if y < m then helper (y, 1) ys
(* if the current list item is larger than the min, ignore it *)
else if y > m then helper (m, n) ys
(* if we've found another instance of the min, add one to the count *)
else helper (m, n + 1) ys
in
(* first item appears once *)
helper (x, 1) xs (* first item appears once *)
end;
This problem is a good test for using folds on a list.
Finding the mininum
If we want to find the minimum in a list we need to iterate over the list checking each element against a predetermined starting minimum value. If that element is less than that known minimum, we continue to iterate using that value instead. When we're done, we have the minimum value.
If the list is empty, there is no minimum value. If only one value is in the list, the minimum is obviously that. If there are more values, the starting minimum value is the first element.
We can use foldl to handle the iteration in this last case.
fun min([]) = NONE
| min([x]) = SOME x
| min(first::rest) =
SOME (foldl (fn (x, min) => if x < min then x else min)
first rest)
Finding occurrences
You've already done this, but this can be done in terms of a fold as well.
fun occurrences(lst, v) =
foldl (fn (x, count) => if x = v then count + 1 else count)
0 lst
Putting this together
We could use these two functions to find the number of times the minimum occurs in a list.
let
val numbers = [1, 4, 7, 2, 9, 0, 1, 6, 0]
val min = min(numbers)
val occ = case min of
NONE => NONE
| SOME x => SOME (occurrences(numbers, x))
in
case (min, occ) of
(NONE, NONE) => print("No minimum found.")
| (SOME m, SOME t) => print("Min: " ^ Int.toString(m) ^ "; times: " ^ Int.toString(t))
end
Can we do it in a single pass?
Using the above approach, we have to iterate over the list twice. This is a more general, but less efficient way of getting both pieces of information the minimum and the number of occurrences of it. We can use foldl to get both pieces of information, and it's going to look at lot like the definition of min.
We just need to pass a function to foldl that keeps a running tally of the number of times it has found the minimum value, and we need to pass it a tuple with both an initial minimum value and an initial count of 1.
fun minCount([]) = NONE
| minCount([x]) = SOME (x, 1)
| minCount(first::rest) =
SOME (foldl (fn (x, init as (min, count)) =>
case Int.compare(x, min) of
EQUAL => (min, count + 1)
| LESS => (x, 1)
| _ => init)
(first, 1)
rest)
With this function defined, our previous code can be rewritten as:
let
val numbers = [1, 4, 7, 2, 9, 0, 1, 6, 0]
val mc = minCount(numbers)
in
case mc of
NONE => print("No minimum found.")
| SOME (m, t) => print("Min: " ^ Int.toString(m) ^ "; times: " ^ Int.toString(t))
end
Assuming that you are supposed to use your occurrences function in the solution, write a function that finds the minimum,
fun minimum [x] = x
| minimum (x::xs) = let
val min = minimum xs
in
if x < min then x else min
end
Note that this does not handle the empty list.
You need to decide whether to leave the missing pattern as a runtime error, or add it and handle the error, for instance by raising an exception or by changing the return type to int option.
If you're taking a course, use one of the methods you've learned so far.
Then you can use that function,
occurrences(the_list, minimum the_list)

Smallest sub-list that contains all numbers

I am trying to write a program in sml that takes in the length of a list, the max number that will appear on the list and the list of course. It then calculates the length of the smallest "sub-list" that contains all numbers.
I have tried to use the sliding window approach , with two indexes , front and tail. The front scans first and when it finds a number it writes into a map how many times it has already seen this number. If the program finds all numbers then it calls the tail. The tail scans the list and if it finds that a number has been seen more times than 1 it takes it off.
The code I have tried so far is the following:
structure Key=
struct
type ord_key=int
val compare=Int.compare
end
fun min x y = if x>y then y else x;
structure mymap = BinaryMapFn ( Key );
fun smallest_sub(n,t,listall,map)=
let
val k=0
val front=0
val tail=0
val minimum= n;
val list1=listall;
val list2=listall;
fun increase(list1,front,k,ourmap)=
let
val number= hd list1
val elem=mymap.find(ourmap,number)
val per=getOpt(elem,0)+1
fun decrease(list2,tail,k,ourmap,minimum)=
let
val number=hd list2
val elem=mymap.find(ourmap,number)
val per=getOpt(elem,0)-1
val per1=getOpt(elem,0)
in
if k>t then
if (per1=1) then decrease(tl list2,tail+1,k-1,mymap.insert(ourmap,number,per),min minimum (front-tail))
else decrease(tl list2,tail+1,k,mymap.insert(ourmap,number,per),min minimum (front-tail))
else increase (list1, front,k,ourmap)
end
in
if t>k then
if (elem<>NONE) then increase (tl list1,front+1,k,mymap.insert(ourmap,number,per))
else increase(tl list1,front+1,k+1,mymap.insert(ourmap,number,per))
else (if (n>front) then decrease(list2,tail,k,ourmap,minimum) else minimum)
end
in
increase(list1,front,k,map)
end
fun solve (n,t,acc)= smallest_sub(n,t,acc,mymap.empty)
But when I call it with this smallest_sub(10,3,[1,3,1,3,1,3,3,2,2,1]); it does not work. What have I done wrong??
Example: if input is 1,3,1,3,1,3,3,2,2,1 the program should recognize that the parto of the list that contains all numbers and is the smallest is 1,3,3,2 and 3,2,2,1 so the output should be 4
This problem of "smallest sub-list that contains all values" seems to recur in
new questions without a successful answer. This is because it's not a minimal,
complete, and verifiable example.
Because you use a "sliding window" approach, indexing the front and the back
of your input, a list taking O(n) time to index elements is not ideal. You
really do want to use arrays here. If your input function must have a list, you
can convert it to an array for the purpose of the algorithm.
I'd like to perform a cleanup of the code before answering, because running
your current code by hand is a bit hard because it's so condensed. Here's an
example of how you could abstract out the book-keeping of whether a given
sub-list contains at least one copy of each element in the original list:
Edit: I changed the code below after originally posting it.
structure CountMap = struct
structure IntMap = BinaryMapFn(struct
type ord_key = int
val compare = Int.compare
end)
fun count (m, x) =
Option.getOpt (IntMap.find (m, x), 0)
fun increment (m, x) =
IntMap.insert (m, x, count (m, x) + 1)
fun decrement (m, x) =
let val c' = count (m, x)
in if c' <= 1
then NONE
else SOME (IntMap.insert (m, x, c' - 1))
end
fun flip f (x, y) = f (y, x)
val fromList = List.foldl (flip increment) IntMap.empty
end
That is, a CountMap is an int IntMap.map where the Int represents the
fixed key type of the map, being int, and the int parameter in front of it
represents the value type of the map, being a count of how many times this
value occurred.
When building the initialCountMap below, you use CountMap.increment, and
when you use the "sliding window" approach, you use CountMap.decrement to
produce a new countMap that you can test on recursively.
If you decrement the occurrence below 1, you're looking at a sub-list that
doesn't contain every element at least once; we rule out any solution by
letting CountMap.decrement return NONE.
With all of this machinery abstracted out, the algorithm itself becomes much
easier to express. First, I'd like to convert the list to an array so that
indexing becomes O(1), because we'll be doing a lot of indexing.
fun smallest_sublist_length [] = 0
| smallest_sublist_length (xs : int list) =
let val arr = Array.fromList xs
val initialCountMap = CountMap.fromList xs
fun go countMap i j =
let val xi = Array.sub (arr, i)
val xj = Array.sub (arr, j)
val decrementLeft = CountMap.decrement (countMap, xi)
val decrementRight = CountMap.decrement (countMap, xj)
in
case (decrementLeft, decrementRight) of
(SOME leftCountMap, SOME rightCountMap) =>
Int.min (
go leftCountMap (i+1) j,
go rightCountMap i (j-1)
)
| (SOME leftCountMap, NONE) => go leftCountMap (i+1) j
| (NONE, SOME rightCountMap) => go rightCountMap i (j-1)
| (NONE, NONE) => j - i + 1
end
in
go initialCountMap 0 (Array.length arr - 1)
end
This appears to work, but...
Doing Int.min (go left..., go right...) incurs a cost of O(n^2) stack
memory (in the case where you cannot rule out either being optimal). This is a
good use-case for dynamic programming because your recursive sub-problems have a
common sub-structure, i.e.
go initialCountMap 0 10
|- go leftCountMap 1 10
| |- ...
| `- go rightCountMap 1 9 <-.
`- go rightCountMap 0 9 | possibly same sub-problem!
|- go leftCountMap 1 9 <-'
`- ...
So maybe there's a way to store the recursive sub-problem in a memory array and not
perform a recursive lookup if you know the result to this sub-problem. How to
do memoization in SML is a good question in and of itself. How to do purely
functional memoization in a non-lazy language is an even better one.
Another optimization you could make is that if you ever find a sub-list the
size of the number of unique elements, you need to look no further. This number
is incidentally the number of elements in initialCountMap, and IntMap
probably has a function for finding it.

Haskell - List Error

I'm trying to iterate a list and square all the number and add them together
sumsq (x:xs) =
let total = 0
loop length(x:xs) (x:xs) total
loop 0 (x:xs) = return ()
loop n (x:xs) total =
do
let
sq = ((x:xs)!!n)^2
total = total + sq
loop ((n-1) (x:xs) total)
But I'm getting parse error in loop. Where am I going wrong?
Also is there a better way to do this?
First of all - you miss spaces! It is significant.
Second, you forget in from let ... in. We could not use in in do-notation:
sumsq (x:xs) =
let total = 0 in
loop length(x:xs) (x:xs) total
Third, you do not use x and xs form (x:xs) :
sumsq xs =
let total = 0 in
loop (length xs) xs total
And we unite our length xsin one block. It is fourth.
Fifth, we have 3, not 2 arguments for loop:
loop 0 xs total = return total
Sixth, (!!) work from 0, but you use it from 1, so (xs !! (n -1)) is right
Seventh, you don't need to use monad, just recursion. So, get rid from return and do
Eighth. you have infinite recursive total = total + smth
Ninth, we can't use arguments as tuple, so, you final working result is :
sumsq xs =
let total = 0 in
loop (length xs) xs total
loop 0 xs total = total
loop n xs total = loop (n-1) xs total1
where
sq = (xs !! (n -1)) ^2
total1 = total + sq
UPDATED
If we are talking about complexity, it is not good - O(n^2) as it is mentioned in comments : for each element we seek this element.
We could simplify our loop function and get rid of n argument:
loop [] total = total
loop (x:xs) total = loop xs total1
where
sq = x ^ 2
total1 = total + sq
and our sumsq function we write:
sumsq xs = loop xs 0
P.S.
This is an implementation much easier function sumsq = sum. map (^ 2)
If I understood you correctly, you could simply do this with map and sum:
Prelude> let myFun = sum . map (^2)
Prelude> myFun [1, 2, 3]
14
Or with foldl1 and lambda:
Prelude> let myFun' = foldl1 (\s x -> s + x^2)
Prelude> myFun' [1, 2, 3, 4]
30
Surely something like this would be the usual approach?
sumSquared :: [Integer] -> Integer
sumSquared [] = 0
sumSquared (x:xs) = (x * x) + sumSquared xs
Or you could do this even more succinctly with foldr, or sum and map (like #soon's answer)
The do must be more indented than the word loop.
Apart from that, you don't need do (or return) at all here, unless you can answer the question which monad this is for?
There are more problems with your code. One of the most severe is this:
You don't seem to know what "pattern matching" is, nor what it is good for. You really want to learn about it, otherwise you can't write any good programs.

number_in_month exercise (Why x = x + 1 is considered bool in sml while x is int and how to say x = x + 1 correctly?)

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. :)