Extracting elements from list in SML - list

I'm trying to extract the given elements from a list, but I get an Match exception?
The goal is to make my function behave like:
fun extract [#"a",#"b",#"c"] [0,1,0] = [#"a",#"b",#"a"];
And I'm trying to do it like this:
fun extract [] _ = []
| extract xr (y::yr) = List.nth(xr, y) :: extract xr yr;
But as said, I get an
! Uncaught exception:
! Match
Any ideas?
Maybe theres some more List functions I could use for this?
I've head about the curry function, which should make a function into a higher-order function, but I don't really know how that works?

The reason that you get a match error is that there's no case for when the second list is empty, but the first is not (which will always happen unless the first list is empty to begin with because only the second list gets shorter).
Basically you can change the first line to fun extract _ [] = [] and it will work.
And yes, you can also solve this using higher-order function. You can use curry to turn List.nth into a function of type 'a list -> int -> 'a instead of 'a list * int -> 'a. You can then partially apply that function to xr, which turns it into a function of type int -> 'a, which will return the ith list of xr when given a number i. You can then use List.map to apply the function to each number in the list of indices you're given. So the function becomes:
fun extract xr yr = List.map (curry List.nth xr) yr
But what you came up with works fine, so you should just stick with that.

Related

Using fold_left to search for a list with a specific length in OCaml

I've written a function which search through a list of int-list to return the index of the list with an specific length by using pattern-matching:
let rec search x lst i = match lst with
| [] -> raise(Failure "Not found")
| hd :: tl -> if (List.length hd = x) then i else search x tl (i+1)
;;
For example:
utop # search 2 [ [1;2];[1;2;3] ] 0 ;;
- : int = 0
Is there a way to write a function with the same functionality using fold.left ?
What does List.fold_left actually do?
It takes (in reverse order to the order of arguments) a list, an initial value, and a function that works on that initial value and the first element in the list. If the list is empty, it returns the initial value. Otherwise it uses the function to update the initial value by way of recursion and works on the tail of the list.
let rec fold_left f init lst =
match lst with
| [] -> init
| x::xs -> fold_left f (f init x) xs
Now, what information do you need to keep track of as you iterate? The index. Easy enough.
But, what if you don't actually find a list of that length? You need to keep track of whether you've found one. So let's say we use a tuple of the index and a boolean flag.
Your function you pass to fold_left just needs to determine if a match has been found no update is necessary. Essentially we just no-op over the rest of the list. But, if we haven't found a match, then we need to test the current sublist's length and update the init value accordingly.
#glennsl (in a comment) and #Chris already explained that you may use List.fold_left but that it’s not the right tool for the job, because it processes the whole list whereas you want to stop once an occurrence is found. There are solutions but they are not satisfying:
(#Chris’ solution:) use a folding function that ignores the new elements once an occurrence has been found: you’re just wasting time, walking through the remaining tail for nothing;
evade the loop by throwing and catching an exception: better but hacky, you’re working around the normal functioning of List.fold_left.
I just mention that there is a generic function in the standard library that matches your situation almost perfectly:
val find : ('a -> bool) -> 'a list -> 'a
find f l returns the first element of the list l that satisfies the predicate f.
Raises Not_found if there is no value that satisfies f in the list l.
However it does not return the index, unlike what you are asking for. This is a deliberate design choice in the standard library, because list indexing is inefficient (linear time) and you shouldn’t do it. If, after these cautionary words, you still want the index, it is easy to write a generic function find_with_index.
Another remark on your code: you can avoid computing the lengths of inner lists fully, thanks to the following standard function:
val compare_length_with : 'a list -> int -> int
Compare the length of a list to an integer. compare_length_with l len is equivalent to compare (length l) len, except that the computation stops after at most len iterations on the list.
Since 4.05.0
So instead of if List.length hd = x, you can do if List.compare_length_with hd x = 0.

Pattern matching on rest of list

I'm trying to pattern match on a list of pairs, where I'm trying to return a list from the list of pair, however I'm having trouble figuring out where to make the recursive call. Without the recursive call I have this:
let countriesInChart (cht: chart) =
match cht with
| [] -> []
| (x,y)::tt -> [x;y]
;;
But naturally this only applies to the first pair in the list and simply returns ["countryA"; "countryB"] without the rest of the list.
With the recursive call this simply only returns an empty list:
let rec countriesInChart (cht: chart) =
match cht with
| [] -> []
| (x,y)::tt -> [x;y]::countriesInChart tt
;;
How would I make the recursive call such that all the pairs in the list would return as a list?
You have this:
[x;y] :: countriesInChart tt
This says to add a new list of two elements onto the front of a list of lists.
I don't think you want a list of lists, you just want a list. So you shouldn't be making a list of two elements.
If x and y are the same type (as I suspect they are), what you probably want is this:
x :: y :: countriesInChart tt
This says to add both x and y individually to the front of the recursively generated list.
You can also write this, which is completely equivalent:
[x; y] # countriesInChart tt
However, this constructs a list of two elements only to throw it away. So it's a tiny bit of extra work for no benefit.

F# return list of list lengths

I am to use combinators and no for/while loops, recursion or defined library functions from F#'s List module, except constructors :: and []
Ideally I want to implement map
I am trying to write a function called llength that returns the list of the lengths of the sublists. For example llength [[1;2;3];[1;2];[1;2;3]] should return [3;2,3]. I also have function length that returns the length of a list.
let Tuple f = fun a b -> f (a, b)
let length l : int =
List.fold (Tuple (fst >> (+) 1)) 0 l
currently have
let llength l : int list =
List.map (length inner list) list
Not sure how I should try accessing my sublists with my restraints and should I use my other method on each sublist? any help is greatly appreciated, thanks!
Since this is homework, I don't want to just give you a fully coded solution, but here are some hints:
First, since fold is allowed you could implement map via fold. The folding function would take the list accumulated "so far" and prepend the next element transformed with mapping function. The result will come out reversed though (fold traverses forward, but you prepend at every step), so perhaps that wouldn't work for you if you're not allowed List.rev.
Second - the most obvious, fundamental way: naked recursion. Here's the way to think about it: (1) when the argument is an empty list, result should be an empty list; (2) when the argument is a non-empty list, the result should be length of the argument's head prepended to the list of lengths of the argument's tail, which can be calculated recursively. Try to write that down in F#, and there will be your solution.
Since you can use some functions that basically have a loop (fold, filter ...), there might be some "cheated & dirty" ways to implement map. For example, via filter:
let mymap f xs =
let mutable result = []
xs
|> List.filter (fun x ->
result <- f x :: result
true)
|> ignore
result |> List.rev
Note that List.rev is required as explained in the other answer.

Adding values to an ocaml list based on its existing values

I'm learning about the map and fold functions. I'm trying to write a function that takes a list and returns a list with all of the values in the original, each followed by that value's double.
Example: add_dbls [2;5;8] = [2;4;5;10;8;16]
Everything I try results in a list of lists, instead of a list. I'm struggling to come up with a better approach, using either map or fold (or both).
This is what I came up with originally. I understand why this returns a list of lists, but can't figure out how to fix it. Any ideas would be appreciated!
let add_dbls list =
match list with
| h::t -> map (fun a-> [a;(a*2)]) list
| [] -> []
Also, my map function:
let rec map f list =
match list with
| h::t -> (f h)::(map f t)
| [] -> []
You are nearly there. As you have observed, since we get list of lists, we need to flatten it to get a final list. List.concat function does exactly that:
let add_dbls list =
let l =
match list with
| h::t -> List.map (fun a -> [a;(a*2)]) list
| [] -> []
in
List.concat l
Here is the updated function that that computes the output that you require.
Now the output of add_dbls [2;5;8] = [2;4;5;10;8;16].
Although this works, it probably isn't efficient as it allocates a new list per item in your original list. Below are variations of the same function with different characteristics which depend on the size of l.
(* Safe version - no stack overflow exception. Less efficient(time and size) than add_dbls3 below. *)
let add_dbls2 l =
List.fold_left
(fun acc a -> (a*2)::a::acc)
[]
l
|> List.rev
(* Fastest but unsafe - stack overflow exception possible if 'l' is large - fold_right is not tail-recursive. *)
let add_dbls3 l =
List.fold_right
(fun a acc -> a::(a*2)::acc)
l
[]
It's should be simple to see that List.map always returns a list of the same length as the input list. But you want a list that's twice as long. So List.map cannot work for you.
You can solve this using List.fold_left or List.fold_right. If you're still having trouble after you switch to using a fold, you could update your question with the new information.
Update
The type of your fold function (a left fold) is this:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
So, the folded function takes an accumulated answer and an element of the list, and it returns a new accumulated answer.
Your folded function is like this:
fun a b -> a::b::(b*2)
It attempts to use the :: operator to add new elements to the end of the accumulated list. But that's not what the :: operator does. It adds an element to the beginning of a list.
There's no particularly nice way to add an element to the end of a list. This is intentional, because it's a slow operation.
When using a left fold, you need to reconcile yourself to building up the result in reverse order and possibly reversing it at the end. Or you can use a right fold (which is generally not tail recursive).

SML: How can I pass a function a list and return the list with all negative reals removed?

Here's what I've got so far...
fun positive l1 = positive(l1,[],[])
| positive (l1, p, n) =
if hd(l1) < 0
then positive(tl(l1), p, n # [hd(l1])
else if hd(l1) >= 0
then positive(tl(l1), p # [hd(l1)], n)
else if null (h1(l1))
then p
Yes, this is for my educational purposes. I'm taking an ML class in college and we had to write a program that would return the biggest integer in a list and I want to go above and beyond that to see if I can remove the positives from it as well.
Also, if possible, can anyone point me to a decent ML book or primer? Our class text doesn't explain things well at all.
You fail to mention that your code doesn't type.
Your first function clause just has the variable l1, which is used in the recursive. However here it is used as the first element of the triple, which is given as the argument. This doesn't really go hand in hand with the Hindley–Milner type system that SML uses. This is perhaps better seen by the following informal thoughts:
Lets start by assuming that l1 has the type 'a, and thus the function must take arguments of that type and return something unknown 'a -> .... However on the right hand side you create an argument (l1, [], []) which must have the type 'a * 'b list * 'c list. But since it is passed as an argument to the function, that must also mean that 'a is equal to 'a * 'b list * 'c list, which clearly is not the case.
Clearly this was not your original intent. It seems that your intent was to have a function that takes an list as argument, and then at the same time have a recursive helper function, which takes two extra accumulation arguments, namely a list of positive and negative numbers in the original list.
To do this, you at least need to give your helper function another name, such that its definition won't rebind the definition of the original function.
Then you have some options, as to which scope this helper function should be in. In general if it doesn't make any sense to be calling this helper function other than from the "main" function, then it should not be places in a scope outside the "main" function. This can be done using a let binding like this:
fun positive xs =
let
fun positive' ys p n = ...
in
positive' xs [] []
end
This way the helper function positives' can't be called outside of the positive function.
With this take care of there are some more issues with your original code.
Since you are only returning the list of positive integers, there is no need to keep track of the
negative ones.
You should be using pattern matching to decompose the list elements. This way you eliminate the
use of taking the head and tail of the list, and also the need to verify whether there actually is
a head and tail in the list.
fun foo [] = ... (* input list is empty *)
| foo (x::xs) = ... (* x is now the head, and xs is the tail *)
You should not use the append operator (#), whenever you can avoid it (which you always can).
The problem is that it has a terrible running time when you have a huge list on the left hand
side and a small list on the right hand side (which is often the case for the right hand side, as
it is mostly used to append a single element). Thus it should in general be considered bad
practice to use it.
However there exists a very simple solution to this, which is to always concatenate the element
in front of the list (constructing the list in reverse order), and then just reversing the list
when returning it as the last thing (making it in expected order):
fun foo [] acc = rev acc
| foo (x::xs) acc = foo xs (x::acc)
Given these small notes, we end up with a function that looks something like this
fun positive xs =
let
fun positive' [] p = rev p
| positive' (y::ys) p =
if y < 0 then
positive' ys p
else
positive' ys (y :: p)
in
positive' xs []
end
Have you learned about List.filter? It might be appropriate here - it takes a function (which is a predicate) of type 'a -> bool and a list of type 'a list, and returns a list consisting of only the elements for which the predicate evaluates to true. For example:
List.filter (fn x => Real.>= (x, 0.0)) [1.0, 4.5, ~3.4, 42.0, ~9.0]
Your existing code won't work because you're comparing to integers using the intversion of <. The code hd(l1) < 0 will work over a list of int, not a list of real. Numeric literals are not automatically coerced by Standard ML. One must explicitly write 0.0, and use Real.< (hd(l1), 0.0) for your test.
If you don't want to use filter from the standard library, you could consider how one might implement filter yourself. Here's one way:
fun filter f [] = []
| filter f (h::t) =
if f h
then h :: filter f t
else filter f t