Checking elements of a list in SML - sml

Hi I am relatively new to ML/SML and I am trying to write function that takes as input 2 lists. The one list contains 4 random strings ["duck","goose","swan","gull"] and the second takes another 4 strings ["duck","swan","goose","pigeon"].
What I would like to do i check each element in the first list against each element the other. If the strings are in the same position and are equal output a 'yes'. If the elements are not in the same position but are in the list then output 'maybe', and if the element isn't in the second list output 'no'.
So given the 2 examples above it would output ["yes","maybe","maybe","no"].
This is what I have done so far, but I can't figure out how to keep recursively calling the main function, checkEqual, to iterate over the entire first list.
fun buildStringList nil nil = nil
|buildStringList lst appList =
lst # appList
in
fun checkEqual nil nil = nil
| checkEqual code guess =
if hd code = hd guess then
buildStringList ([])(["yes"])
else if hd code = hd(tl guess) then
buildStringList ([])(["maybe"])
else if hd code = hd(tl(tl guess)) then
buildStringList ([])(["maybe"])
else if hd code = hd(tl(tl(tl guess))) then
buildStringList ([])(["maybe"])
else
buildStringList ([])(["no"])
end;
Any help would be greatly appreciated.

There are two code paths, comparing items by index [the "yes" condition] and then comparing them without regard to index [the "maybe" path]. Using recursion and a helper function [or two] allows both code paths to be followed:
val ls1 = ["duck", "goose", "swan", "gull"]
val ls2 = ["duck", "swan", "goose", "pigeon"]
fun checker (list1,list2) =
(* Zipping the two lists together creates
a list of pairs that can be searched
for "yes" values as the first part of the aux function.
It might be worth checking to see if
ListPair.zipEq is more suited to the
needs of a particular appliation. *)
let val zipped = ListPair.zip(list1, list2)
(* find_in_list is called if there is
no "yes" match. It recurses down
list2 with the string from list1
which did not return "yes". *)
fun find_in_list (x, xs) =
case xs
of [] => "no"
| x'::xs' =>
if x' = x
then "maybe"
else find_in_list (x, xs')
(* This function could be the main body
of checker, but instead it trampolines.
First it checks for "yes". Either appends
"yes" onto a recursive call to itself or
otherwise appends a call to find_in_list
onto a recursive call to itself.
The type checker wants an explicit type
for lop because the record is being accessed
with #1 and #2 *)
fun aux (lop : (string * string) list) =
case lop
of [] => []
| x'::xs' =>
if #1 (hd lop) = #2 (hd lop)
then "yes"::aux (tl lop)
else (find_in_list (#1 (hd lop), list2))::(aux (tl lop))
in aux(zipped) end
checker (ls1,ls2) (* returns ["yes", "maybe", "maybe", "no"] *)

Related

Replicate items from list basing on the second list

Write a function that replicates items in a list based on a second list specifying the number of times items are to be duplicated.
Write the function in Ocaml in a functional way of programming using lists.
If library functions - may be used only with O(1) computational complexity.
For example:
duplicate [5;6;7] [0;2;5;3];;
returns:
[6;6;7;7;7;7;7]
Code I've invented so far:
let duplicate (list1, list2)=
let rec read (list2, list1) =
if List.hd list2 = 0 then read (List.tl list2, List.tl list1) else print (List.hd list2, List.hd list1)
let rec print (acc, num) =
num :: (print (acc-1, num));;
First of all, it does not compile, I have "syntax error"...
I do not feel sure about these "nested" functions.
I believe that complexity could be better.
When you are considering an answer to this question, you should examine the most simple case.. i.e. How can I add an element to a list x number of times. Example:
let rec add_elem_num_times num times lst =
match times with
| 0 -> lst
| _ -> add_elem_num_times num (times - 1) (num::lst)
let ans = add_elem_num_times 5 3 (add_elem_num_times 3 8 [])
let () = List.iter (fun x -> Printf.printf "%d\n" x) ans
The rest is just getting it to work for many elements.

Add elements to list in a loop in OCAML

Hi i'm a beginner in OCAML and i would like to create a function to add elements a the end of a list and return this list. Here is my code :
let test () : int list =
let mylist = [] in
for i = 1 to 3 do
mylist#[i];
done;
mylist;;
It says that mylist#[i] should have type unit. When I call this function it returns an empty list. Can anyone help me ? Thanks
Ocaml lists are immutable, i.e., they cannot be changed. The expression
mylist#[i]
creates a new list. However, since you do nothing with the result, it is just thrown away. If you want to build a list like that, you need to store it in a reference.
let l = ref [] in
for i = 0 to 3 do
l := !l # [i]
done;
List.iter (fun item -> print_int item; print_newline ()) !l
I would, however, recommend to do this differently. Appending two lists is a rather expensive operation, because a new list is created and all elements are copied every time. A much more efficient way to do what you want is to create the list in reverse order and use List.cons (the :: operator), which adds new elements to the beginning of the list.
let l = ref [] in
for i = 3 downto 0 do
l := i :: !l
done;
List.iter (fun item -> print_int item; print_newline ()) !l
The cons operation runs in constant time, because it can reuse the already existing list.
Alternatively, you can also create the list using recursion.
let rec l i =
if i <= 3 then i :: l (i+1) else [] in
List.iter (fun item -> print_int item; print_newline ()) (l 0)
This variant also does not need to copy the list, but it is not tail-recursive, i.e., it uses as much stack space as elements in the list.
let rec l acc i =
if i >= 0 then l (i :: acc) (i-1) else acc in
List.iter (fun item -> print_int item; print_newline ()) (l [] 3)
This variant is efficient, tail-recursive, but harder to read (IMHO).
As a final remark, you might want to check out the Queue module or the DynArray module in ExtLib or
in Batteries.
Lists are immutable in OCaml. In particular, the line
mylist#[i];
is equivalent to
mylist#[i]; ()
Or in other words, first append the list [i] at the end of mylist then discard the result of this computation. This is why the compiler is warning you that mylist # [i] should have type unit: unit is the result type used for functions that only perform side-effects and do not return a value.
If you want to create a range function, the idiomatic way is to define a recursive function
let rec range start stop =
if start > stop then
...
else
... range (start+1) stop ...

K out on N implementation - SML

I was trying to implement k-out-of-N at SML so "pick(3,[1,2,3,4])" will return [[1,2,3],[1,3,4]...] (all the K-size picks out of N elements)
I used List.map which I figured it calls the function and apply it on each element.
Really can't figure out why when typing the input "pick(3,[1,2,3,4,5])" ,for example, it return an empty list.
My first thought was that it's because of the initial terms (choose (_,[]) = [])
But changing it didn't work as well.
The signature is ok (val pick = fn : int * 'a list -> 'a list list).
fun pick (_,[]) = []
| pick (0,_) = []
| pick (n,hd::tl) =
let
val with_hd = List.map (fn x => hd::x) (pick(n-1,tl))
val without_hd = pick(n,tl)
in
with_hd#without_hd
end;
The problem is related to your suspicion – the base cases are incorrect in that they always produce the empty list, and mapping fn x => hd::x onto the empty list produces the empty list.
Picking zero elements from anything should succeed, and produce the empty list.
That is, pick (0, _) = [[]] — a list with one element, which is the empty list.
You also need to rearrange the cases since pick(n, []) succeeds for n = 0 but not for any other n.
In summary,
fun pick (0, _) = [[]]
| pick (_, []) = []
with the rest of the function exactly as before.

Pattern matching x::xs not splitting list accordingly in F#?

I'm new to F# and I'm trying to write a method split that splits a list into 2 pieces. It takes a tuple with the first element being the number of elements to split and the second element is the list . For example, split (2, [1;2;3;4;5;6]) should return ([1;2], [3;4;5;6]),
This is what I have so far, but for some reason it is returning the second element of the tuple as the original list without the head. I don't understand this because I thought that x::xs automatically makes x the head element and xs the rest of the list, which would mean that each recursive call is taking the tail of the previous list and chopping off the first term.
let rec split = function
|(n, []) -> ([], [])
|(0, xs) -> ([], xs)
|(n, x::xs) -> let temp = x :: fst (split(n-1, xs))
(temp, xs);;
The problem is on this line:
(temp,xs);;
here in your example, xs will always be [2;3;4;5;6] as long as n>0
You need to get the second element of the list with something like
|(n,x::xs) ->
let a,b = split (n-1,xs)
(x::a,b)

How can I find the index where one list appears as a sublist of another?

I have been working with Haskell for a little over a week now so I am practicing some functions that might be useful for something. I want to compare two lists recursively. When the first list appears in the second list, I simply want to return the index at where the list starts to match. The index would begin at 0. Here is an example of what I want to execute for clarification:
subList [1,2,3] [4,4,1,2,3,5,6]
the result should be 2
I have attempted to code it:
subList :: [a] -> [a] -> a
subList [] = []
subList (x:xs) = x + 1 (subList xs)
subList xs = [ y:zs | (y,ys) <- select xs, zs <- subList ys]
where select [] = []
select (x:xs) = x
I am receiving an "error on input" and I cannot figure out why my syntax is not working. Any suggestions?
Let's first look at the function signature. You want to take in two lists whose contents can be compared for equality and return an index like so
subList :: Eq a => [a] -> [a] -> Int
So now we go through pattern matching on the arguments. First off, when the second list is empty then there is nothing we can do, so we'll return -1 as an error condition
subList _ [] = -1
Then we look at the recursive step
subList as xxs#(x:xs)
| all (uncurry (==)) $ zip as xxs = 0
| otherwise = 1 + subList as xs
You should be familiar with the guard syntax I've used, although you may not be familiar with the # syntax. Essentially it means that xxs is just a sub-in for if we had used (x:xs).
You may not be familiar with all, uncurry, and possibly zip so let me elaborate on those more. zip has the function signature zip :: [a] -> [b] -> [(a,b)], so it takes two lists and pairs up their elements (and if one list is longer than the other, it just chops off the excess). uncurry is weird so lets just look at (uncurry (==)), its signature is (uncurry (==)) :: Eq a => (a, a) -> Bool, it essentially checks if both the first and second element in the pair are equal. Finally, all will walk over the list and see if the first and second of each pair is equal and return true if that is the case.