SML : drop the first n elements of a list - sml

So, I know there is a build in function to drop elements but it works if you wish to drop the last n elements.
I want to drop the first n elements.
An example:
> drop([1,2,3,4], 2)
> [1,2]
I've wrote this piece of code:
exception Subscription;
val counter = 0;
fun drop (l,0) = l
| drop([], n) = raise Subscription
| drop(h::x, n) = if n<0 then raise Subscription
else if(counter <n) then
let
val counter = counter +1
in
(h:: drop(x,n))
end
else nil
;
drop([1,2,3,4],2);
it won't be compiled. The error message I get is :
uncaught exception Subscription
raised at: dropper.ml:6.23-6.35
Any thoughts and help appreciated.

You are misunderstanding the meaning of a val declaration. It does
not declare a variable of which you can change the content afterwards
as in imperative programming languages. Basically:
as mentioned by #kopec, your test if(counter < n) is pointless
since it reduces to if(0 < n) as counter as been set to 0, i.e.,
the val counter = counter + 1 placed after has no effect on that
test
the declaration val counter = counter + 1 is useless. It
basically means "now counters is set to counters + 1 (so 1) only in
the in ... end block following" where it's not used at all.
Your code is thus equivalent to:
exception Subscription;
val counter = 0;
fun drop (l,0) = l
| drop([], n) = raise Subscription
| drop(h::x, n) = if n<0 then raise Subscription
else if(0 <n) then (h:: drop(x,n))
else nil
;
drop([1,2,3,4],2);
Hence, it's clear that with your example list you'll keep performing
recursive call ((h:: drop(x,n))) until reaching the third clause of
your function that raises the exception.
In this kind of situation, a proper way to solve your problem is to
use the arguments of your recursive function:
exception Subscription;
fun drop(l, 0) = l
| drop([], n) = raise Subscription
| drop(h :: x, n) =
if n < 0 then raise Subscription
else (h :: drop(x, n - 1))
;
drop([1,2,3,4],2);
Hence, if n is greater or equal to the length of the input list, you
will eventually fall in the first clause of the function.
(Happy to see that you are getting familiar with pattern matching :))

Related

OCaml: pell function with int lists

I am trying to write a simple function in OCaml
let rec pell (i: int) =
(if i <= 2 then i (*if given n is less tahn 2 then return 2, else return previous n-1 th term and n-2 nd term recursively*)
else if i>2 then
2 * pell i - 1 + pell i - 2
else failwith "unimplemented" (*else fail with unimplemented message*)
);;
Write an infinite precision version of the pell function from before
pell2 0 = []
pell2 1 = [1]
pell2 7 = [9; 6; 1]
pell2 50 = [2; 2; 5; 3; 5; 1; 4; 2; 9; 2; 4; 6; 2; 5; 7; 6; 6; 8; 4]
I have written below code for this:
let rec pell2 i =
(if i <= 2 then
[] -> i;
else if i=0 then [];
else if i>2 then (*finding pell number and using sum function to
output list with infinite precision...*)
[] -> pell2 i-1 + pell2 i-2;
else failwith "unimplemented"
);;
but still has some syntax errors. Can someone help me with this please.
if i <= 2 then
[] -> i
In snippets like this, the -> is invalid. It looks like you might be mixing pattern matching with match ... with ... and if/else up.
Also, you're first checking if i is less than or equal to 2, but then you have an else to test for i being equal to zero. The first check means the second is never going to happen.
First, let's look at the examples for the output of pell2. We see that pell2 has a single integer parameter, and returns a list of integers. So, we know that the function we want to create has the following type signature:
pell2: int -> int list
Fixing (some but not all of) the syntax errors and trying to maintain your logic,
let rec pell2 i =
if i=0 then []
else if i <= 2 then i
else if i>2 then pell2 i-1 + pell2 i-2
Note that I removed the semicolons at the end of each expression since OCaml's use of a semicolon in its syntax is specifically for dealing with expressions that evaluate to unit (). See ivg's excellent explanation on this. The major flaw with this code is that it does not type check. We see that we conditionally return a list, and otherwise return an int. Notice how above we defined that pell2 should return an int list. So, we can begin fixing this by wrapping our int results in a list:
let rec pell2 n =
if n = 0 then []
else if n <= 2 then [n]
else ... something that will return the Pell number as a list ...
As you have already written, the else branch can be written using recursive calls to the pell2 function. However, we can't write it as you did previously, because pell2 evaluates to a list, and the binary operator + only works on two integers. So, we will have to define our own way of summing lists. Calling this sum_lists, we are left with the following code:
We can now fully define our function pell2:
let rec pell2 n =
if n = 0 then []
else if n <= 2 then [n]
else (* Pell(n) = (2 * Pell(n-1)) + Pell(n-2) *)
let half_of_first_term = pell2 n-1 in
let first_term = sum_lists half_of_first_term half_of_first_term in
let second_term = pell2 n-2 in
sum_lists first_term second_term
So, all that is left is to define sum_lists, so that we are properly summing together two lists of the same format as the return type of pell2. The signature for sum_lists would be
sum_lists: int list -> int list -> int list
I'll give a basic outline of the implementation, but will leave the rest for you to figure out, as this is the main crux of the assignment problem.
let sum_lists lst1 lst2 =
let rec sum_lists_helper lst1 lst2 carry =
match lst1, lst2 with
| [], [] -> if carry = 1 then [1] else []
| h::t, []
| [], h::t -> ...
| h1::t1, h2::t2 -> ...
in
sum_lists_helper lst1 lst2 0

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.

SML - Get specific Element out of List without using List.nth

im trying to learn the basics of SML atm and stumbled across a task I can't find the answer for.
It is to write a function which takes in an int and a list, returns a specific element in the list on the index of that given int. As you see, it's exactly like the List.nth()-function.
Now I'm curious. This is how far I came, but I just can't think of a way to target a specific index manually.
fun nth(nil, _) = 0
| nth(x::xs, 0) = x;
| nth(x::xs, y) =
val list = [1, 2, 3];
nth(list, 0);
As John suggested, indexing an empty list could raise an exception instead of returning 0. This makes nth work for any type of list, not just the subset of int lists for which 0 can reasonably be considered "no result". It seems that the function lacks recursion to work for any index beyond 0. Here's a template to work with:
fun nth ([], _) = raise Empty
| nth (x::_, 0) = x
| nth (_::xs, n) = ...
Here an exception is added, and the variables that will not be used in each case of the function have been blanked out with the pseudo-variable _. You might want a more informative error message, too.
fun nth ([], n) = raise Fail "Failed to find the appropriate index!"
| nth (x::_, 0) = x
| nth (_::xs, n) = ...
A "safer" version of nth has the type 'a list * int -> 'a option, i.e. for nth (xs, i), if xs has an ith element x, it returns SOME x, and if it doesn't, it returns NONE:
fun nth_safe ([], _) = NONE
| nth_safe (x::_, 0) = SOME x
| nth_safe (_::xs, n) = ...
It's "safer" because it doesn't throw an exception if the list is not long enough. An adversarial example: nth ([0,1,2], 3)
But it still doesn't handle if the index is negative. An adversarial example: nth ([0,1,2], ~1)
You could address that concern inside the ... of the third function body with if n < 0 then ..., but then that would get executed on every recursive step, even though you would most likely only need to check it once.
A robust version of this function raises an error when you pass it a negative index. Otherwise your function might cause you to loop negatively until you run out of memory, since the recursive case (the 3rd case) does not converge towards the two base cases (case 1 and 2). For the exception-based version, you can write:
exception IndexError of int
fun nth (xs, n) =
let fun go ([], _) = raise IndexError n
| go (x::_, 0) = x
| go (_::ys, i) = ...
in if n < 0 then raise IndexError n else go (xs, n)
end
A robust version using error-aware data types could instead look like:
fun nth (xs, n) =
let fun go ([], _) = NONE
| go (x::_, 0) = SOME x
| go (_::ys, i) = ...
in if n < 0 then NONE else go (xs, n)
end
And a robust version using error-aware data types that capture the index error just like the exception-based version with the custom IndexError exception looks like:
datatype ('a, 'b) either = Left of 'a | Right of 'b
fun nth (xs, n) =
let fun go ([], _) = Left n
| go (x::_, 0) = Right x
| go (_::ys, i) = ...
in if n < 0 then Left n else go (xs, n)
end
val example_1 = nth ([2,3,5], 5) (* gives: Left 5 *)
val example_2 = nth ([2,3,5], ~1) (* gives: Left ~1 *)
val example_3 = nth ([2,3,5], 2) (* gives: Right 5 *)
A simple approach:
fun nth (nil,0) = raise Fail "You are out of bounds with nth element"
| nth ((x::xr),n) = if n=0 then x else nth (xr,(n-1))

OCaml variable counting

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.

Returning an index of an element in OCaml

The x is a list and v is an element that is in the list. Need to return the index of that element, v else should return -1.
The code below works fine when the element is in the list but it doesn't return -1 when not found.
The error is else let j = 1+index t v in j because it keeps adding 1 and when the empty list is passed it does total = total - 1 and thus return the index of the very last element.
I am a new OCaml learner, don't know how to solve this issue.
let rec index x v =
match x with
[] -> -1
| h::t ->
if h == v then 0
else let j = 1+ index t v in j
First of all, you can direct say else 1 + index t v instead of else let j ...
Second, the logic of your code is not wrong as long as the desired element does exist in the list, as you told. You basically keep increasing by one as the iteration continues.
However, it is hard to deal with the case where the element is not in the list, because the previous counting won't be stopped.
To deal with this, it is better to keep the counting in our own hand, so if not find but still in middle of list, then increase the count; if do find, then return the count; if not find and reach the end, then return -1, not the count.
So, the count must be a parameter of our recursive function.
let index v l =
let rec aux c = function
| [] -> None
| h::t ->
if h = v then Some c
else aux (c+1) t
in
aux 0 l
The above logic happens to transform to tail-recursive (which sooner or later you will learn).
p.s., normally you use h = v as it is the value check. h == v is a physical equality check and normally we don't want that.