How does this ocaml recursive function work? - list

I'm pretty new to ocaml and I'm having a hard time with this func
I know what it does but not HOW! With a given list, it returns the minimum value of the list and the rest of the list as a pair.
sepmin [2;1;3;4] == (1,[2;3;4])
val sepmin : 'a list -> 'a * 'a list
# let rec sepmin = function
[h] -> h, []
|h::t -> let h1, t1 = sepmin t in
min h h1, (max h h1)::t1;;
Could you guys help me out with the recursive part t.t

First, it is applied to the list's tail recursively. Say, it returns h1 and t1 that are the minimum of the tail and all the other elements of the tail. Next, this element, h, is compared against h1. If it is less than h1, then the pair (h, h1::t1) returned; otherwise the pair (h1, h::t1) is returned. Since the function is called recursively, then probably one of these pairs is returned to the previous recursion point (and its first element is again compared against that point's list head). As far as I can see, the function does not care much about the original order of the elements, i.e. for the list [1; 4; 2; 5; 6] it should return (1, [2; 4; 5; 6]), 2 and 4 are reordered in the result.

A good way to think about recursion is to take it in two pieces. First, what does the function do when the input is trivial? Second (this is the tricky part), assuming the function works for small inputs, how does it transform a bigger intput into a smaller one and use the answer for the smaller case to calculate the correct result for the bigger case.
The trivial case for this function is a list of one element. The answer is obvious in that case.
For a longer list, you can use your recursive power to get the correct answer for the tail of the list (which is a shorter list, hence the recursion will work by assumption). Once you know the answer for the tail of the list, you can construct the correct answer for the full list: the max of the head of the list and the answer for the tail is the overall maximum. You need to add the smaller of these two values back to the list.

Related

Return a list of the odd indices using List.map

If I have a list [1;2;3;4;5;6] and I want to return a list of the odd indices [2;4;6], could I do this with List.map and some function? I'm having difficulty figuring this out.
What List.map does is return a function (call it f say) of each of the elements of the list. For each element x of the input list, it returns f x in the resulting list. Hence, the returned list is always the same length as the one it is passed.
Since you want a shorter list, you can't use List.map.
As #UnholySheep says, you could use List.filteri. It's specifically intended for returning only some of the elements of the list based on their position in the list.

How to count the number of consecutive occurrences in a list of any element type in OCaml?

In OCaml, suppose I have a string list as follows:
let ls : string list = ["A"; "A"; "B"; "B"; "A"; "Y"; "Y"; "Y"] ;;
I'm having trouble writing a function that calculates how many times an element occurs consecutively and also pairs up that element with its frequency. For instance, given the above list as input, the function should return [("A", 2); ("B", 2), ("A", 1), ("Y", 3)].
I've tried looking for some hints elsewhere but almost all other similar operations are done using int lists, where it is easy to simply add numbers up. But here, we cannot add strings.
My intuition was to use something like fold_left in some similar fashion as below:
let lis : int list = [1;2;3;4;5]
let count (lis : int list) = List.fold_left (fun x y -> x + y) (0) (lis)
which is essentially summing all the elements cumulatively from left to right. But, in my case, I don't want to cumulatively sum all the elements, I just need to count how many times an element occurs consecutively. Some advice would be appreciated!
This is obviously a homework assignment, so I will just give a couple of hints.
When you get your code working, it won't be adding strings (or any other type) together. It will be adding ints together. So you might want to look back at those examples on the net again :-)
You can definitely use fold_left to get an answer. First, note that the resultl is a list of pairs. The first element of each pair can be any type, depending on the type of the original list. The second element in each pair is an int. So you have a basic type that you're working with: ('a * int) list.
Imagine that you have a way to "increment" such a list:
let increment (list: ('a * int) list) value =
(* This is one way to think of your problem *)
This function looks for the pair in the list whose first element is equal to value. If it finds it, it returns a new list where the associated int is one larger than before. If it doesn't find it, it returns a new list with an extra element (value, 1).
This is the basic operation you want to fold over your list, rather than the + operation of your example code.

Function that converts a sequence to a list in OCaml

I want to convert a sequence to a list using List.init. I want at each step to retrieve the i th value of s.
let to_list s =
let n = length s in
List.init n
(fun _i ->
match s () with
| Nil -> assert false
| Cons (a, sr) -> a)
This is giving me a list initialized with the first element of s only. Is it possible in OCaml to initialize the list with all the values of s?
It may help to study the definition of List.init.
There are two variations depending on the size of the list: a tail recursive one, init_tailrec_aux, whose result is in reverse order, and a basic one, init_aux. They have identical results, so we need only look at init_aux:
let rec init_aux i n f =
if i >= n then []
else
let r = f i in
r :: init_aux (i+1) n f
This function recursively increments a counter i until it reaches a limit n. For each value of the counter that is strictly less than the limit, it adds the value given by f i to the head of the list being produced.
The question now is, what does your anonymous function do when called with different values of i?:
let f_anon =
(fun _i -> match s () with
|Nil -> assert false
|Cons(a, sr) -> a)
Regardless of _i, it always gives the head of the list produced by s (), and if s () always returns the same list, then f_anon 0 = f_anon 1 = f_anon 2 = f_anon 3 = hd (s ()).
Jeffrey Scofield's answer describes a technique for giving a different value at each _i, and I agree with his suggestion that List.init is not the best solution for this problem.
The essence of the problem is that you're not saving sr, which would let you retrieve the next element of the sequence.
However, the slightly larger problem is that List.init passes only an int as an argument to the initialization function. So even if you did keep track of sr, there's no way it can be passed to your initialization function.
You can do what you want using the impure parts of OCaml. E.g., you could save sr in a global reference variable at each step and retrieve it in the next call to the initialization function. However, this is really quite a cumbersome way to produce your list.
I would suggest not using List.init. You can write a straightforward recursive function to do what you want. (If you care about tail recursion, you can write a slightly less straightforward function.)
using a recursive function will increase the complexity so i think that initializing directly the list (or array) at the corresponding length will be better but i don't really know how to get a different value at each _i like Jeffrey Scofield said i am not really familiar with ocaml especially sequences so i have some difficulties doing that:(

OCaml count consecutive elements in a list

I'm writing OCaml code that reads in a list and removes any char 'i's that appear at the beginning of the list. For instance, the list removeI['i';'i';'a';'c';'i'] should return -: int * char list = ['a';'c';'i'], because there are 2 'i's at the beginning of the list. I believe I know how to implement this properly; however, I want to return a tuple that includes the number of removed 'i's as well as the new list with the 'i's removed. I know that may sound confusing, but an example would be removeI['i';'i';'a';'c';'i'] -: int * char list = (2,['a';'c';'i']) There are 2 'i's removed and the new list with the removed 'i's.
So far, I have the following function:
let rec removeI list = match list with
| [] -> []
| x::[] -> x::[]
| x::y::t1 -> if x='i' then removeI (y::t1)
else list;;
This returns the list with the first 'i's removed, but I keep getting errors when I try to include the number of removed 'i's as part of a tuple. Could anyone push me in the right direction? Thanks!
Your recursive call will return the same type as the function overall. So if you change the function to reuturn (count, list), then the recursive call will return that also.
Generally you want to gather up the returned values and calculate a new value from them.
Right now you have just this:
removeI (y :: t1)
But you need something more like this:
let (count, list) = removeI (y :: t1) in
(* Newly calculated count and list *)
Note that your base cases also have to return a count and a list.
As a side comment, I don't actually understand your second base case. You don't want to remove an 'i' if it's the only thing in the list? That doesn't seem particularly consistent.

More efficient way to update an element in a list in Elm?

Is there a more efficient way to update an element in a list in Elm than maping over each element?
{ model | items = List.indexedMap (\i x -> if i == 2 then "z" else x) model.items }
Maybe Elm's compiler is sophisticated enough to optimize this so that map or indexedMap isn't unnecessarily copying over every element except 1. What about nested lists?
Clojure has assoc-in to update an element inside a nested list or record (can be combined too). Does Elm have an equivalent?
More efficient in terms of amount of code would be (this is similar to #MichaelKohl's answer):
List.take n list ++ newN :: List.drop (n+1) list
PS: if n is < 0 or n > (length of list - 1) then the new item will be added before or at the end of the list.
PPS: I seem to recall that a :: alist is slightly better performing than [a] ++ alist.
If you mean efficient in terms of performance/ number of operations:
As soon as your lists get large, it is more efficient to use an Array (or a Dict) instead of a List as your type.
But there is a trade-off:
Array and Dict are very efficient/ performant when you frequently retrieve/ update/ add items.
List is very performant when you do frequent sorting and filtering and other operations where you actually need to map over the entire set.
That is why in my code, List is what I use a lot in view code. On the data side (in my update functions) I use Dict and Array more.
Basically, an Elm list is not meant for such a use-case. Instead, consider using an Array. Array contains a set function you can use for what is conceptually an in-pace update. Here's an example:
import Html exposing (text)
import Array
type alias Model = { items : Array.Array String }
model =
{ items = Array.fromList ["a", "b", "c"]
}
main =
let
m = { model | items = Array.set 2 "z" model.items }
z = Array.get 2 m.items
output = case z of
Just n -> n
Nothing -> "Nothing"
in
text output -- The output will be "z"
If for some reason you need model.items to be a List, note that you can convert back and forth between Array and List.
I'm not overly familiar with Elm, but given that it's immutable by default, I'd assume it uses structural sharing for its underlying data structures, so your concern re memory may be unfounded.
Personally I think there's nothing wrong with your approach posted above, but if you don't like it, you can try something like this (or List.concat):
List.take n list ++ newN :: List.drop (n+1)
I'm definitely not an Elm expert, but a look at Elm's List documentation did not reveal any function to update the element at a given index in a list.
I like Michael's answer. It's quite elegant. If you prefer a less-elegant, recursive approach, you can do something like the following. (Like I said, I'm not an Elm expert, but hopefully the intention of the code is clear if its not quite right. Also, I don't do any error handling.)
updateListAt :: List a -> Int -> a -> List a
updateListAt (head :: tail) 0 x = x :: tail
updateListAt (head :: tail) i x = head :: (updateListAt tail (i - 1) x)
However, both the runtime and space complexity will be O(n) in both the average and worst cases, regardless of the method used. This is a consequence of Elm's List being a single-linked list.
Regarding assoc-in, if you look at the Clojure source, you'll see that assoc-in is just recursively defined in terms of assoc. However, I think you'd have trouble typing it for arbitrary, dynamic depth in Elm.