I need to
Write a function separate of type int * 'a * 'a list -> 'a lst such that
separate (k, x, l) returns the list that inserts element x after each k elements of list l (counting from
the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4] and
separate (3, 0, [1,2,3,4]) should return [1,0,2,3,4].
So far, this is what I have, but it is causing an error. Can anyone help me?
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let val count:int = k
in foldr(
(fn (h, t) =>
if count = 0
then count := 1 in
x::h::t
else count = count + 1 : int
h::t
)
Actually the logic is quite right, but it should be implemented by passing changed state into another iteration of foldr due to immutability:
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
#2 (foldr (fn (h, (count, t)) =>
if count = 0
then (k - 1, h::x::t)
else (count - 1, h::t)
) (k, []) l);
Thus, instead of initiating count as a variable, we initiate foldr with tuple (k, []) (where k is the initial value of count and [] is the resulting list) and then decrease the count every step of the iteration.
Related
I want to search in with searchingElements list inside each second element in tuple list and count if there are months in the list inside tuple lists as it shown in the test, I don't know if it should done by recursion, which I have no clue how to use here.
fun number_in_months(months : (int * int * int) list, months2 : (int * int * int) list,
months3 : (int * int * int) list, searchingElements : int list) =
if #2 (hd (tl months)) = (hd searchingElements)
then
1
else
0
val test3 = number_in_months ([(2012, 2, 28), (2013, 12, 1), (2011, 3, 31), (2011, 4, 28)], [2, 3, 4]) = 3
I get these 2 errors that I understood later I can't compare between list and tuple list
(fn {1=1,...} => 1) (hd number)
main.sml:30.2-30.30 Error: operator and operand do not agree [overload - bad instantiation]
stdIn:2.1-2.5 Error: unbound variable or constructor: fun3
It's really misleading if we read the function code and the test as they both are not type consistent in the very first place.
If I follow the test function which is
val test3 = number_in_months ([(2012,2,28),(2013,12,1),(2011,3,31),(2011,4,28)],[2,3,4]) = 3
then the type of number_in_months should be
val number_in_months = fn: ('a * ''b * 'c) list * ''b list -> int
which is a pair(2-tuple) and the function which is supposed to implement the logic
fun fun3 (months :(int*int*int) list, months2: (int*int*int) list, months3:
(int*int*int) list, searchingElements: int list)
is actually a function with a parameter which is a 4-tuple and a mismatch is evident. Also the parameters months2 and months3 are not used anywhere. Plus, each of the so called months parameters are of type list in themselves. Furthermore, except for the test3 line, there isn't anything which is quite meaningful to come-up with an answer or even a reply.
However, following the test3 line, I have attempted to write a function that at least gets the thing done and is as follows:
fun number_in_months (date_triples, months) =
let
fun is_second_of_any_triple ele = List.exists (fn (_, x, _) => x = ele)
in
List.foldl (fn (curr, acc) => if is_second_of_any_triple curr date_triples then acc + 1 else acc) 0 months
end
A version with explicit recursion:
Suppose we had a function that counted the occurrences of a single number in a list of tuples;
month_occurrences: ((int * int * int) list * int) -> int
Then we could recurse over the list of numbers, just adding as we go along:
fun number_in_months(dates, []) = 0
| number_in_months(dates, m::ms) = month_occurrences(dates, m) + number_in_months(dates, ms)
And month_occurrences with a straight recursion might look like
fun month_occurrences([], _) = 0
| month_occurrences((_, m, _)::ds, m') = (if m = m' then 1 else 0) + month_occurrences(ds, m')
I’m trying to create a function that takes an int list as an argument and returns the sum of the product between an int and its position in the list. To put in an example this : multSum [5; 11; 15] should return (5 * 1 + 11 * 2 + 15 * 3) = 72.
It should be written recursively and I’m trying while avoiding List.map or List.filter or any other prefabricated functions.
By dividing and reigning the query above, I have so far started by trying the following :
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t ;;
val tir : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
then I moved to this :
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto";;
val carto : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
with the final idea to be able to do that :
let prod arg1 arg2 =
tir (+) 1 (carto ( * ) arg1 arg2);;
val prod : int list -> int list -> int = <fun>
But I am stuck now and I’m not sure of my orientation from here forward. I thought of trying to search for the index in a "l" and replace each index int in the acc, in order to make it work but I'm afraid I'm rather complicating things... Any help please ?
Edit 1 :
let rec multSum l =
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t)in
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t in
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto" in
let prod arg1 arg2 =
tir (+) 0 (carto ( * ) arg1 arg2) in
prod l (indices 1 l);;
val multSum : int list -> int = <fun>
Building on your replies, surely these are 'fold' and 'map' rewritten. At least, I'm sure now that I was on the right track. I have come to put together the whole code as signaled above in Edit 1.
It seems to be working well... I know that I want a recursive function and here it is. But, do you think it could be done even shorter recursively of course?
#coredump is quite right about this looking like an ideal scenario for a fold, but the extra functions aren't really that necessary. We can just use a tuple to pass the index and sum information around, then when we're done, discard the index information from the tuple.
let sum_list_prod lst =
let (_, result) = List.fold_left
(fun (i, sum) x -> (i + 1, sum + i * x))
(1, 0)
lst
in
result
Edit: A simple implementation of a left fold to demonstrate the recursion going on here.
let rec foldl f init lst =
match lst with
| [] -> init
| first :: rest -> foldl f (f init first) rest
So working through a simple example with sum_list_prod:
sum_list_prod [2; 3; 4]
Calls the fold like so:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
And as that evaluates:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (2, 2) [3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (3, 8) [4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (4, 20) []
(4, 20)
And then we throw away the 4 because we don't need it anymore and are just left with 20.
Your tir functions looks like a fold; in fact has the exact same type as List.fold_left:
# List.fold_left;;
- : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
In the following snippets the prod function looks like a map2
# List.map2;;
- : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
You can use a fold and a map to compute the function you want, but you also need first to build a list of indices from the list of values. You could do this as follows:
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t);;
For example:
# indices 1 [5;1;3];;
- : int list = [1; 2; 3]
This is not recursive terminal, if you first computed the length of the list, how would you build the list in a recursive terminal way?
Then you should be able to call prod on a list xs and on a secondary list indices 1 xs. It is a bit wasteful because you need to build an auxiliary list, but it looks quite simple to me to understand, higher-order functions like map or fold do work on whole lists so there are fewer corner cases to consider.
But, it might be better to first write a direct recursive function for your particular problem before going the more abstract route.
The direct recursive function also requires no additional memory allocation. If you write a recursive terminal function you'll carry additional accumulator values:
the current position in the list, initially 1
the current sum of products, initially 0
Then, your function has the following skeleton:
let rec f xs index product = match xs with
| [] -> ...
| h::t -> ...
You can wrap it in a main function g:
let g xs = f xs 1 0;;
I'm trying to make a function which can return the specific nth element of lazylist.
Here is what I made:
datatype 'a lazyList = nullList
| cons of 'a * (unit -> 'a lazyList)
fun Nth(lazyListVal, n) = (* lazyList * int -> 'a option *)
let fun iterator (laztListVal, cur, target) =
case lazyListVal of
nullList => NONE
| cons(value, tail) => if cur = target
then SOME value
else iterator (tail(), cur+1, target)
in
iterator(lazyListVal,1,n)
end
I expected the result that as recusing proceeds, eventually the variable cur gets same as the variable target, and then the function iterator returns SOME value so it will return the final nth element.
But when I compile it and run, it only returns the very first element however I test with the lazylist objects.
Please figure what is the problem. I have no idea...
cf) I made another function which is relevant to this problem, the function that transforms lazylist into SML original list containing the first N values. Codes above:
fun firstN (lazyListVal, n) = (* lazyList * int -> 'a list *)
let fun iterator (lazyListVal, cur, last) =
case lazyListVal of
nullList => []
| cons(value, tail) => if cur = last
then []
else value::iterator(tail(),cur+1,last)
in
iterator(lazyListVal,0,n)
end
The strange thing is the function firstN is properly working.
The problem is that your iterator function does case lazyListVal of ..., but the recursive tail is called laztListVal, so for every iteration, it keeps looking at the first list. Use better variable names to avoid this kind of "invisible" bug.
For a simpler definition of nth:
datatype 'a lazyList = NullList | Cons of 'a * (unit -> 'a lazyList)
fun nth (NullList, _) = NONE
| nth (Cons (x, xs), 0) = SOME x
| nth (Cons (_, xs), n) = nth (xs (), n-1)
val nats = let fun nat n = Cons (n, fn () => nat (n+1)) in nat 0 end
val ten = nth (nats, 10)
Edit: While function pattern matching is ideal here, you could also have used a case ... of ... here. A helper function seems unnecessary, though, since you can simply use the input argument n as the iterator:
fun nth (L, n) =
case (L, n) of
(NullList, _) => NONE
| (Cons (x, xs), 0) => SOME x
| (Cons (_, xs), n) => nth (xs (), n-1)
You may however want to make the function more robust:
fun nth (L, n) =
let fun nth' (NullList, _) = NONE
| nth' (Cons (x, xs), 0) = SOME x
| nth' (Cons (_, xs), n) = nth' (xs (), n-1)
in if n < 0 then NONE else nth' (L, n) end
Here having a helper function ensures that n < 0 is only checked once.
(You could also raise Domain, since negative indices are not well-defined.)
Im having an issue with my separate function. Separate returns a list that inserts element x after each k elements of list l (counting from
the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4] and separate (3, 0, [1,2,3,4]) should return [1,0,2,3,4]. Whenever I run any tests on it i get the error:
! Unbound value identifier: separate
This is the code i'm using:
(*Function returns length of lst *)
fun length(lst: int list): int =
case lst of
[] => 0
| h::t => 1 + length(t)
(*Insert element x at the kth position in the list
and return the new list*)
fun kinsert [] x k = [x]
| kinsert ls x 0 = x::ls
| kinsert (l::ls) x k = l::(kinsert ls x (k - 1))
(* c: keeps track of where we are in the list
n: determines if we insert element at given position
z: holds length of the list *)
fun sep_help k x l c n z=
if c = z then l
else if n = k then (sep_help k x (kinsert l x c) (c+2) 0 z )
else (sep_help k x l (c+2) (n+1) z) ;
(*Returns list l with x inserted after each k element *)
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
| separate k x l = (sep_help k x l 0 0 (length l));
Anyone know what might be causing the error?
Your separate looks like its a merge of two different definitions - first an uncurried version that has no definition, and then a curried version that has one.
You probably meant
fun separate (k: int, x: 'a, l: 'a list) : 'a list = sep_help k x l 0 0 (length l);
But working backwards through a list complicates things quite a bit.
It's much easier to work from the head towards the tail, and reverse the list before and after processing.
Then "all" you need is a helper that inserts an element in every k:th place in a list.
Something like this, perhaps:
(*Returns list l with x inserted after each k element *)
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let
fun kinsert [] _ = []
| kinsert ls 0 = x::(kinsert ls k)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
I'm trying to write a function in SML that takes in a list of ints and will output a list of ordered pairs of ints. The ordered pairs first int is the int that occurred in the input list and the second int in the ordered pair is the number of times it occurred in the input list. Also the list returned should be in ascending order according to the first int in the ordered pairs.
For example input list [1, 1, 1, 2, 3, 3, 5] would output as [(1,3), (2, 1), (3, 2), (5, 1)].
So far I have a function that uses foldl
UPDATED the code since original post.
fun turnIntoPairs l = foldl (fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)]) [] l;
I'm having trouble updating the list where I find the ordered pair that is already in the list - I want to add one to the second int in the ordered pair that was found while it's still in the list.
Any help would be greatly appreciated!
C:\Program Files (x86)\SMLNJ\\bin\.run\run.x86-win32.exe: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
[autoloading done]
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.87 Error: unbound variable or constructor: x
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.44-1.110 Error: types of if branches do not agree [literal]
then branch: int
else branch: (''Z * int) list
in expression:
if (List.exists (fn <pat> => <exp>)) a
then <errorvar> + 1
else a # (e,1) :: nil
[Finished in 0.5s with exit code 1]
Not really sure how to fix your current program, but you can solve this problem by splitting it in two: grouping equal elements and then ordering the list.
(* Groups successive equal elements into a tuples (value, count) *)
fun group (l as (x :: _)) =
let val (firstGroup, rest) = List.partition (fn y => x = y) l
in
(x, List.length firstGroup) :: (group rest)
end
| group [] = []
(* Now that we have our elements grouped, what's left is to order
them as required. *)
fun turnIntoPairs xs =
ListMergeSort.sort (fn ((x, _), (y, _)) => x >= y) (group xs)
Let's just look at the function you're passing to foldl:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)])
The first problem (which the type-checker is complaining about) is that your if expression returns either x + 1, or a # [(e, 1)], which seems problematic on account of the former being a value of type int and the latter being of type (int * int) list.
Let's rewrite your code using some helper functions that I won't define and see if it gets clearer:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then increment a e else a # [(e, 1)])
Where increment has the type (int * int) list -> int -> (int * int) list.
Can you implement increment?
Like Gian, I would prefer to divide this into two functions: One that folds and one helper function that inserts. Incidentally, the insert function would take an element and an existing (int * int) list just as the accumulator function that fold accepts these two arguments.
Normally I would write an insert function curried (i.e. insert x xs) but if I write it uncurried (i.e. insert (x, xs)), I can pass it directly to foldl:
fun insert (x, []) = [(x,1)]
| insert (x, ((y,c)::xs)) =
if x = y then (y,c+1)::xs else (y,c)::insert (x, xs)
fun turnIntoPairs xs = foldl insert [] xs