I have this function that takes a list of lists of strings and a string and then return a list of all the elements in each list that contains the string passed but without the string passed.
myfilter([["a","b"],["c","d"],["e","a","x"]], "a") -> ["b","e","x"]
fun myfilter(list : string list list, s : string) =
case list of
[] => []
|xs::xs' => case all_except_option(s, xs) of (* helper function that does it for a string and a list of strings *)
NONE => []
|SOME n => if n = xs
then myfilter(xs',s)
else n#myfilter(xs',s)
Now this is as you can see is a recursive function and I want to convert it to a tail recursive function. I am familiar with the examples of tail recursion but I am failing to see how I can do it in the function above
When you think tail recursive, the next thing you think should be "accumulator".
The reason a function is not tail recursive is that it has to call itself to obtain some result, and then do something with that result. If we can move that calculation into the recursive call, then it's tail recursive.
In this case, the calculation you're making is that you're putting two lists together. So the solution would be a function declared inside a let ... in ... end, that takes a third parameter - an accumulator. Then you can add items to the accumulator as you go.
A good example is a tail-recursive factorial function. Here's the normal factorial function:
fun fact 0 = 1
| fact x = x * fact (x-1)
To make it tail-recursive, we define a local function which takes an accumulator, and do the multiplication there.
fun fact x =
let
fun fact' 0 acc = acc
| fact' x acc = fact (x-1) (x*acc)
in
fact' x 1
end
We use 1 as the starting value for the accumulator, because multiplying with 1 has no effect.
Okay, so other than that, there is a little thing you can do to improve your code. I've noticed a lot of people here that do this:
fun foo xs =
case xs of
[] => ...
| (x::xs) => ...
Where it would be much nicer to just do:
fun foo [] = ...
| foo (x::xs) = ...
Related
Important: I am only allowed to use List.head, List.tail and List.length
No List.map List.rev ...........etc
Only List.hd, List.tl and List.length
How to duplicate the elements of a list in a list of lists only if the length of the list is odd
Here is the code I tried:
let rec listes_paires x =
if x=[] then []
else [List.hd (List.hd x)]
# (List.tl (List.hd x))
# listes_paires (List.tl x);;
(* editor's note: I don't know where this line is supposed to go*)
if List.length mod 2 = 1 then []
For exemple:
lists_odd [[]; [1];[1;2];[1;2;3];[];[5;4;3;2;1]];;
returns
[[]; [1; 1]; [1; 2]; [1; 2; 3; 1; 2; 3]; []; [5; 4; 3; 2; 1; 5; 4; 3; 2; 1]]
Any help would be very appreciated
thank you all
It looks like that your exercise is about writing recursive functions on lists so that you can learn how to write functions like List.length, List.filter, and so on.
Start with the most simple recursive function, the one that computes the length to the list. Recall, that you can pattern match on the input list structure and make decisions on it, e.g.,
let rec length xs = match xs with
| [] -> 0 (* the empty list has size zero *)
| hd :: tl ->
(* here you can call `length` and it will return you
the length of the list hing how you can use it to
compute the length of the list that is made of `tl`
prepended with `hd` *)
???
The trick is to first write the simple cases and then write the complex cases assuming that your recursive function already works. Don't overthink it and don't try to compute how recursion will work in your head. It will make it hurt :) Just write correctly the base cases (the simple cases) and make sure that you call your function recursively and correctly combine the results while assuming that it works correctly. It is called the induction principle and it works, believe me :)
The above length function was easy as it was producing an integer as output and it was very easy to build it, e.g., you can use + to build a new integer from other integers, something that we have learned very early in our lives so it doesn't surprise us. But what if we want to build something more complex (in fact it is not more complex but just less common to us), e.g., a list data structure? Well, it is the same, we can just use :: instead of + to add things to our result.
So, lets try writing the filter function that will recurse over the input list and build a new list from the elements that satisfy the given predicate,
let rec filter xs keep = match xs with
| [] -> (* the simple case - no elements nothing to filter *)
[]
| x :: xs ->
(* we call filter and it returns the correctly filtered list *)
let filtered = filter xs keep in
(* now we need to decide what to do with `x` *)
if keep x then (* how to build a list from `x` and `filtered`?*)
else filtered (* keep filtering *)
The next trick to learn with recursive functions is how to employ helper functions that add an extra state (also called an accumulator). For example, the rev function, which reverses a list, is much better to define with an extra accumulator. Yes, we can easily define it without it,
let rec rev xs = match xs with
| [] -> []
| x :: xs -> rev xs # [x]
But this is an extremely bad idea as # operator will have to go to the end of the first list and build a completely new list on the road to add only one element. That is our rev implementation will have quadratic performance, i.e., for a list of n elements it will build n list each having n elements in it, only to drop most of them. So a more efficient implementation will employ a helper function that will have an extra parameter, an accumulator,
let rev xs =
(* we will pump elements from xs to ys *)
let rec loop xs ys = match xs with
| [] -> ys (* nothing more to pump *)
| x :: xs ->
let ys = (* push y to ys *) in
(* continue pumping *) in
loop xs []
This trick will also help you in implementing your tasks, as you need to filter by the position of the element. That means that your recursive function needs an extra state that counts the position (increments by one on each recursive step through the list elements). So you will need a helper function with an extra parameter for that counter.
The question might sound confusing but basically
I want to make a function that takes in a list and another function. Now going through that list I want to get the count of elements that return true when inputted into this parameter function. Im new to sml so my mistake was that I intended to add a count to a helper function and increment that alongside If statements but I learned soon enough that you can't really increment values in ml. Can someone please explain the more sml way of doing this? I'm just looking to understand what I'm missing.
fun helper f nil counter = false
| helper f xs 1 = true
| helper f (x::xs) counter =
if (f x) = true then
counter = counter + 1
else
counter = counter + 0
fun numberExisting f alist = (helper f alist 0);
The function should not return a boolean, so neither should your helper.
"Incrementing" is also a concept that doesn't make much sense in a language without mutation.
(counter = counter + 1is a comparison that will never be true.)
You don't need the helper, but you need to think recursively:
If the list is empty, the result is zero.
If the list is not empty:
If the given predicate is true for the head of the list, the result is one more than the result of recursing over the tail of the list.
If the given predicate is false for the head of the list, the result is the same as the result of recursing over the tail of the list.
In ML:
fun numberExisting _ [] = 0
| numberExisting f (x::xs) = if f x
then 1 + numberExisting f xs
else numberExisting f xs
So, I've written this quicksort function in SML to exploit the high order function folding, but it's getting hung up in an infinite loop, and I can't pin down the faulty logic that's causing it. Any suggestions on where to look?
(* takes in a list of numbers and an arbitrary binary relation function f *)
fun quicksort nil f = []
| quicksort [x] f = [x]
| quicksort list f =
let
(* simply choose pivot as first item in the list *)
val pivot = hd list
(* lists iterated by folding for numbers pertaining to the relation f
or its converse *)
fun test a = List.foldr (fn (x,y) => if f (pivot, x) then x::y else y) [] a
fun testC a = List.foldr (fn (x,y) => if f (pivot, x) then y else x::y) [] a
in
(* my notion is the function is looping here, since the functions test
and testC work fine on their own *)
quicksort (test list) op f # [pivot] # quicksort (testC list) op f
end;
Thanks for any suggestions.
The problem is that the sublists on which you invoke quicksort can be as long as the initial list. You must ensure that the pivot element cannot be in those lists.
The easiest way to do that is to use matching to split the incoming list into pivot and a list of remaining elements, and then pass that list to the test functions.
I need to write a function that takes a list of strings and finds the largest string in the list. The catch is it needs to iterate through the list using List.foldl and cannot use recursive calls except for those in the library function of List,foldl.
I wrote
fun longest_string1(xs)=
case xs of
[] => ""
| x::xs' => List.foldl((fn (s,x) => if String.size s > String.size x then s else x) "" x,)
with my interpretation being as follows:
-take in xs, if xs is empty return an empty string
-otherwise for the first item of xs call List.foldl
-List.foldl passes in an anonymous function that checks the length of s, which should represent the accumulator against the head item of the list. -Set the initial accumulator to be the empty string and the initial compare value to be the head of the initial list passed in by the higher order function
However, it does not type check.
I think my issue is in the understanding of the List.foldl function itself and how exactly it reads in its parameters. Can someone please provide some clarification?
So, for the code you posted:
You don't need the case for the empty list. foldl will take care of that for you. Just pass xs to foldl instead of x.
foldl is curried, so you shouldn't have parentheses around the parameters.
Other than that, it actually looks correct. Anyway, if you're still not sure how foldl works, here's a really long and thorough explanation ;)
Okay, let's start with List.foldl.
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
So, there are three parameters. One is a function which we'll worry about later, the second is a value of the same type as the return type, and the last is the list.
So, let's take a simple example - say we have a list of ints, and we want to sum all the numbers. We could do this:
fun sum [] = 0
| sum (x::xs) = x + sum xs
Or, we can use foldl (I'll write foldl instead of List.foldl from now, because I'm lazy).
So, we know that the list is the third parameter. The second should be some sort of starting value, or accumulator, something that would make sense if the list was empty. For a sum, that would be 0.
The first parameter is a function, and this is the tricky part. The type is:
fn : 'a * 'b -> 'b
Okay, so 'a is also the type of the elements in the list, so it makes sense if this is an item from the list. 'b is the type of the starting value and the return value.
What actually happens is that foldl calls the function with the first element in the list, and the accumulator. It then calls itself with the result as the new accumulator, and the rest of the list. So if we do this:
foldl foo 0 [1,2,3]
It'll do
foo (1,0)
And then
foldl foo (foo (1,0)) [2,3]
And so on.
So for summing a list, we'll make the following function:
fn (x,acc) => x + acc
So we can do this:
fun sum xs = foldl (fn (x,acc) => x + acc) 0 xs
Or, even simpler
val sum = foldl op+ 0
(op+ does the same as the anonymous function I used earlier)
Let's walk through it with the list [1,2,3]
foldl op+ 0 [1,2,3]
foldl op+ (op+ (1,0)) [2,3] -> foldl op+ 1 [2,3]
foldl op+ (op+ (2,1)) [3] -> foldl op+ 3 [3]
foldl op+ (op+ (3,3)) [] -> foldl op+ 6 []
6
I'm very new to SML and I am trying a list exercise. The goal is sum up the previous numbers of a list and create a new list. For example, an input list [1, 4, 6, 9] would return [1, 5, 11, 20].
This is my solution so far, but I think the issue is with how I'm defining the function.
fun rec sum:int list -> int list =
if tl(list) = nil then
hd(list)
else
hd :: sum((hd(tail) + hd(tl(list)))::tl(tl(list)));
Besides that you are using rec as a function name, then you have some minor issues to work on.
The explicit type annotation you have made is treated as an annotation of the function result.
Thus, according to what you have written, then it should return a function and not the expected
list. This is clearly seen from the below example:
- fun rec_ sum : int list -> int list = raise Domain;
val rec_ = fn : 'a -> int list -> int list
Your should be careful of using the head and tail functions, when you don't do any checks on the
number of elements in the list. This could be done with either the length function, or (even
easier and often better) by pattern matching the number of elements.
Your code contains sum as a function call and tail as an variable. The variable tail has never
been defined, and using sum as a function call, makes me believe that you are actually using rec
as a keyword, but don't know what it means.
The keyword rec is used, when defining functions using the val keyword. In this case, rec is
needed to be able to define recursive functions (not a big surprise). In reality, the keyword fun
is syntactic sugar (a derived form) of val rec.
The following 3 are examples of how it could have been made:
The first is a simple, straight forward solution.
fun sumList1 (x::y::xs) = x :: sumList1 (x+y::xs)
| sumList1 xs = xs
This second example, uses a helper function, with an added argument (an accumulator). The list is constructed in the reverse order, to avoid using the slow append (#) operator. Thus we reverse the list before returning it:
fun sumList2 xs =
let
fun sumList' [] acc = rev acc
| sumList' [x] acc = rev (x::acc)
| sumList' (x :: y :: xs) acc = sumList' (y+x :: xs) (x :: acc)
in
sumList' xs []
end
The last example, show how small and easy it can be, if you use the standard list functions. Here the fold left is used, to go through all elements. Again note that the list is constructed in the reverse order, thus it is reversed as the last step:
fun sumList3 [] = []
| sumList3 (x::xs) = rev (foldl (fn (a, b) => hd b + a :: b) [x] xs)
try this -
fun recList ([], index, sum) = []
| recList (li, index, sum) =
if index=0 then
hd li :: recList (tl li, index+1, hd li)
else
sum + hd li :: recList (tl li, index+1, sum + hd li)
fun recSum li = recList (li, 0, 0)
In your case -
recSum([1,4,6,9]) ;
will give
val it = [1,5,11,20] : int list
also don't use rec as fun name -it keyword .