I am new to SML.I got this sorting algo to implement where in each iteration,I have to pick minimum element from the list, remove it and create sorted list.
I did below coding to solve the problem.
I wrote 2 helper functions to pickup minimum element from the list and remove one element from the list.
fun minList(x::xs) =List.foldl (fn (x,y)=> if x<y then x else y) x (x::xs);
fun remElem(x, l) =
case l of
[] => []
| (x1::x2::xs) => if x1=x then (x2::xs) else (x1::xs)
;
Above two programs ran successfully.
Below is my sorting code.
fun simpSort(xs)=
let fun aux(xs,acc)=
case xs of
[] =>acc
| [x] => [x]
| (x::xs) => let val m = minList(xs)
in
aux(remElem(m,xs),acc#[m])
end
in aux(xs,[])
end;
This sorting program is giving error.
simpSort([3,1]);
uncaught exception Match [nonexhaustive match failure]
raised at: stdIn:433.59
Please advise.
Since you've solved your problem, here are some hints for improving a working version of your code:
Find the minimum of a list in a way that supports empty lists:
fun minimum [] = NONE
| minimum (x::xs) = SOME (foldl Int.min x xs)
Simplify pattern matching in the function that removes the first occurrence of an element from a list:
fun remove (_, []) = []
| remove (y, x::xs) =
if x = y
then xs
else x :: remove (y, xs)
Use those in combination to write simpSort:
fun simpSort xs =
case minimum xs of
NONE => []
| SOME x => x :: simpSort (remove (x, xs))
I shouldn't have to say that this sorting algorithm is terribly inefficient. :-P
Related
I just started learning functional programming in SML and I want to know how I can combine the following two functions into a single function. The function isolate deletes the duplicates of a list of any type ('a) using the helper function 'removes'.
fun isolate [] = []
| isolate (l as x::xs) = x::isolate(remove(x,xs))
fun remove (x,[]) = []
| remove (x,l as y::ys) = if x = y then remove(x,ys) else y::remove(x,ys)
So, for the purpose of better understanding the constructs in the SML, how would you include the function remove within isolate? This may seem trivial, but I have thinking about it and can't figure it out. Thank you for your help!
One method would be to just define remove inside isolate.
fun isolate [] = []
| isolate (l as x::xs) =
let fun remove (x,[]) = []
| remove (x,l as y::ys) = if x = y
then remove(x,ys)
else y::remove(x,ys)
in
x::isolate(remove(x,xs))
end
Alternately, to make deduplication one function, though all this really does is use the library function List.filter to do the same thing that remove does.
fun isolate [] = []
| isolate (x::xs) = x::isolate(List.filter (fn y => y <> x) xs)
My idea: define a nested function to check if there are duplicated elements in the list:
fun set(nums:int list)=
let fun duplicate(x:int, l:int list)=
if null l
then false
else hd l=x orelse duplicate(x,tl l)
in
if null nums
then []
else
let val s=set(tl nums)
in if duplicate(hd nums,s)
then s
else hd nums::s
end
end
But it will give a list that only remains the last one for every duplicated elements.
I want to propound the following solutions of this problem:
fun remove_duplicates(xs: int list) =
let
fun check(xs: int list, item: int) =
if null xs
then false
else if hd xs = item
then true
else check (tl xs, item)
fun go_through_list(xs: int list) =
if null xs
then []
else if check(tl xs, hd xs)
then go_through_list(tl xs)
else hd xs :: go_through_list(tl xs)
in
go_through_list(xs)
end
It's more lines of code than in the solution propounded by #qaphla
My idea is to first sort the list, then recursively return a new list without duplicates:
fun remove_duplicates(l: int list) =
if null(l)
then []
else if null(tl l)
then l
else
let
fun compare(x: int, y: int) = x > y
fun sort(l: int list) = ListMergeSort.sort(compare) l
val l_sorted = sort(l)
in
if (hd l_sorted) = (hd (tl l_sorted))
then remove_duplicates(tl l_sorted)
else (hd l_sorted)::remove_duplicates(tl l_sorted)
end
I have two lists of equal length. I want to filter the elements of the first list by looking, if the element, with the same index in the second list, has a true boolean value.
Example:
[1,2,3,4,5]:int list
[true,false,false,true,false]:bool list
Expected result: [1,4]
I know two ways I could achieve this:
1) Write a function that takes two lists. For every element in the first list, that I want to append, check if the current(head) element of the second list is true.
2) Zip the two lists and filter it according to the boolean value.
There should be an easier to go about this, right?
Not really. The cleanest way to do this is probably
List.map (fn (x,y) => x) (List.filter (fn (x,y) => y) (ListPair.zip (L1,L2)))
or
List.map Option.valOf (List.filter Option.isSome (ListPair.map(fn (x,y) => if y then SOME x else NONE) (L1,L2)))
The recursive function isn't too bad, either:
fun foo ([],[]) = []
| foo ([],L) = raise Fail "Different lengths"
| foo (L,[]) = raise Fail "Different lengths"
| foo (x::xs, b::bs) = if b then x::foo(xs,bs) else foo(xs,bs)
Those are pretty much the two options you have; either recurse two lists at once, or combine them into one list of tuples and recurse that. There are several combinators you could use to achieve the latter.
val foo = [1,2,3,4,5];
val bar = [true,false,true,true,false];
val pairs = ListPair.zip (foo, bar)
Once zipped, here are two other ways you can do it:
val result = List.foldr (fn ((n,b), res) => if b then n::res else res) [] pairs
val result = List.mapPartial (fn (n,b) => if b then SOME n else NONE) pairs
The simplest is probably
ListPair.foldr (fn (x,y,z) => if y then x :: z else z) [] (L1, L2)
Don't know if ML has list comprehension, but if your language has it:
[ x | (x, True) <- zip xs ys ]
I'm trying to figure out how to return a list of the indexes of occurrences of a specific value in another list.
i.e.
indexes(1, [1,2,1,1,2,2,1]);
val it = [1,3,4,7] int list
I'm trying to figure out how lists work and trying to get better at recursion so I don't want to use List.nth (or any library functions) and I don't want to move into pattern matching quiet yet.
This is what I have so far
fun index(x, L) =
if null L then 0
else if x=hd(L) then
1
else
1 + index(x,tl L);
fun inde(x, L) =
if null L then []
else if x=hd(L) then
index(x, tl L) :: inde(x, tl L)
else
inde(x, tl L);
index(4, [4,2,1,3,1,1]);
inde(1,[1,2,1,1,2,2,1]);
This gives me something like [2, 1, 3, 0]. I guess I'm just having a hard time incrementing things properly to get the index. The index function itself works correctly though.
Instead you could also make two passes over the list: first add an index to each element in the list, and second grap the index of the right elements:
fun addIndex (xs, i) =
if null xs then []
else (hd xs, i) :: addIndex(tl xs, i+1)
fun fst (x,y) = x
fun snd (x,y) = y
fun indexi(n, xs) =
if fst(hd xs) = n then ... :: indexi(n, tl xs)
else indexi(n, tl xs)
(I left out part of indexi for the exercise.)
Where addIndex([10,20,30],0) gives you [(10,0),(20,1),(30,2)]. Now you can use addIndex and indexi to implement your original index function:
fun index(n, xs) = indexi(n, addIndex(xs, 0))
When you get that to work, you can try to merge addIndex and indexi into one function that does both.
However, you really want to write this with pattern matching, see for instance addIndex written using patterns:
fun addIndex ([], _) = []
| addIndex (x::xs, i) = (x,i) :: addIndex(xs, i+1)
If you do index(1,[2]), it gives 1, which is not correct. When the list is empty, it gives you zero. In a function like this, you'd probably want to use SOME/NONE feature.
Define a function which computes the sum of all the integers in a
given list of lists of integers. No 'if-then-else' or any auxiliary
function.
I'm new to to functional programming and am having trouble with the correct syntax with SML. To begin the problem I tried to create a function using pattern matching that just adds the first two elements of the list. After I got this working, I was going to use recursion to add the rest of the elements. Though, I can't even seem to get this simple function to compile.
fun listAdd [_,[]] = 0
| listAnd [[],_] = 0
| listAnd [[x::xs],[y::ys]] = x + y;
fun listAdd [] = 0
| listAdd ([]::L) = listAdd L
| listAdd ((x::xs)::L) = x + listAdd (xs::L)
should do what it looks like you want.
Also, it looks like part of the problem with your function is that you give the function different names (listAdd and listAnd) in different clauses.
For the sake of simplicity, I'd say you probably want this :
fun listAdd : (int * int) list -> int list
Now, I would simply define this as an abstraction of the unzip function :
fun listAdd ls :
case ls of
[] => 0
| (x,y) :: ls' => (x + y) + (listAdd ls')
I think there is no point in taking two separate lists. Simply take a list that has a product of ints. If you have to build this, you can call the zip function :
fun zip xs ys :
case xs, ys of
[], [] => []
| xs, _ => []
| _, ys => []
| x::xs', y::ys' => (x,y) :: (zip xs' ys')
In general, if you really wanted, you can write a far more abstract function that is of the general type :
fun absProdList : ((`a * `b) -> `c) -> (`a * `b) list -> `c list
This function is simply :
fun absProdList f ls =
case l of
[] => []
| (x,y) :: ls' => (f (x,y)) :: (absProdList f ls')
This function is a supertype of the addList function you mentioned. Simply define an anonymous function to recreate your addList as :
fun addList' ls =
absProdList (fn (x,y) => x + y) ls
As you can see, defining the generic type-functions makes specific calls to functions that are type-substitutions to the general one far easier and much more elegant with the appropriate combination of : Currying, Higher-Order Functions and Anonymous Functions.
You probably don't want an int list list as input, but simply an int list * int list (pair of int lists). Besides this, your function seems to returns numbers rather than a list of numbers. For this you would use recursion.
fun listAdd (x::xs, y::ys) = (x + y) :: listAdd (xs, ys)
| listAdd ([], _) = []
| listAdd (_, []) = [] (* The last two cases can be merged *)
You probably want to read a book on functional programming fron the first page and on. Pick for example Notes on Programming in SML/NJ by Riccardo Pucella if you want a free one.
I'm creating sum of list and using option in it. When I pass an empty list, I should get NONE or else SOME value.
I'm able to do that in the following way:
fun sum_list xs =
case xs of
[] => NONE
| x =>
let
fun slist x =
case x of
[] => 0
| x::xs' => x + slist xs'
in
SOME (slist x)
end
But I want to do it in the other way round using pattern matching, in which I want to eval the result of sum_list to see whether it is NONE or contains some other value.
I have tried in various ways but I cannot get a hang of how to do in that way.
I think what you currently have is very clear and easy to understand.
If you want to avoid using slist, you have to call sum_list recursively on the tail of the list, pattern-match on that option value and return appropriate results:
fun sum_list xs =
case xs of
[] => NONE
| x::xs' => (case (sum_list xs') of
NONE => SOME x
| SOME y => SOME (x+y))