I'm trying to make a function in SML that takes a list and an int and returns a list of all elements that are less than the int int * int list -> int list I wrote the following code:
- fun less (e, L) =
= map (fn a => if a < e then a else []) L;
also with the following code it doesnt work also:
- fun less (e, L) =
= map (fn a => if a < e then a) L;
and the error im getting is :
stdIn:22.15-22.38 Error: types of if branches do not agree [overload]
then branch: 'Z
else branch: 'Y list
in expression:
if a < e then a else nil
I think the problem is with the else part but I dont know what to put in it to work, anybody have any suggestion? I should use either map, foldl, or foldr functions.
EDIT:
- fun less (e, L) =
= let
= val acc = []
= in
= foldr (fn a => if a < e then a::acc else acc) acc L
= end;
still gives me error, the following error :
stdIn:241.3-241.54 Error: operator and operand don't agree [overload]
operator domain: 'Z * 'Y -> 'Y
operand: 'X -> 'X list
in expression:
foldr (fn a => if <exp> < <exp> then <exp> :: <exp> else acc)
The error message is clear; since a has type int and [] has type 'a list, their types are mismatched.
The problem is you chose the wrong high-order function for the task. The filter on List structure is best suited here:
fun less (e, L) = filter (fn a => a < e) L
You could use recursion to implement less explicitly, or use foldl/foldr to accumulate filtered lists. However, map seems irrelevant here.
EDIT:
I will give a hint about using foldl/foldr. You start with empty list as the accumulator. Prepend an element to the accumulator whenever that element is smaller than e; otherwise, return the accumulator.
EDIT 2:
You forgot to pass acc as an argument in the lambda function:
fun less (e, L) = foldr (fn (a, acc) => if a < e then a::acc else acc) [] L
And the let..in..end part is redundant because you use [] as the accumulator only.
Related
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.)
I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.
I am trying to retrieve the last element of a list using foldl in SML, and not getting a lot of correct answers from what i have done already, the following is one of my bad tries, any help!
fun last p = foldr ( fn (x, y) => if ( p y ) then x else y ) [];
You could use List.last even though you should be careful, as it will raise an exception if you use it on an empty list.
For the MosML implementation, you can find the documentation at http://mosml.org/mosmllib/List.html#last-val
As RasmusWL mentioned, List.last is the appropriate tool for general use.
It can be recreated using foldl:
fun last(alist, init) = List.foldl (fn(x,y) => x) init alist
This produces a signature: fn : 'a list * 'a -> 'a
To write it with foldr use:
fun last(alist, init) = List.foldr (fn(x,y) => x) init (List.rev alist)
An advantage of using foldl is that it does not require a check for an empty list:
List.foldl (fn(x,y) => x) 0 [];
(* val it = 0 : int *)
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
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 .