Updating a list of 2-tuples in SML - sml

I'm trying to update a running list of 2-tuples in SML. This is the same problem as: How can I update lists in SML using functions?
Unfortunately, the answer doesn't help. First, here is my code:
fun member(a, []) = false
| member((a, b), (c, d)::cds) = a = c orelse member((a, b), cds);
fun update([], (loc, v)) = [(loc, v)]
| update((y, z)::yzs, (loc, v)) =
if member((loc, v), (y, z)::yzs) then
if loc = y then (loc, v)::yzs
else (y, z)::update(yzs, (loc, v))
else (y, z)::yzs#[(loc, v)];
I am able to call the update function on FLR to create new values, but can only update the last value. In addition, when the last value is added and I call the update function again, it has not appended to FLR. Here's my example:
- val FLR = [(1,1),(2,4),(3,9),(4,16),(5,25)];
val FLR = [(1,1),(2,4),(3,9),(4,16),(5,25)] : (int * int) list
- update(FLR, (6,36));
val it = [(1,1),(2,4),(3,9),(4,16),(5,25),(6,36)] : (int * int) list
- update(FLR, (7,42));
val it = [(1,1),(2,4),(3,9),(4,16),(5,25),(7,42)] : (int * int) list
Instead of assigning the value to "it," is there a way for me to assign the value of the new list to FLR? In addition, I'm not able to add new values to an empty list? Any suggestions on that?

As Yawar pointed out, your code seems to work, but the idea of mutating variables to see updates must be replaced with shadowing bindings with newly created values that slightly different.
Your code can be simplified:
fun member ((x,_), xs) = List.exists (fn (y,_) => x = y) xs
fun update ([], (x,v)) = [(x,v)]
| update ((y,w)::pairs, (x,v)) =
if x = y
then (x,v) :: pairs (* replace (y,w) with (x,v), stop *)
else (y,w) :: update (pairs, (x,v)) (* keep (y,w), continue *)
That is, you don't need memberinside update to tell you whether the list needs updating or not, since that will require member to recurse through the list and return true or false with not much else to show for where the insert/replace should occur.
It seems a little asymmetric that member takes the pair first and the list second, while update takes the list first and the pair second. When designing APIs, try and make things consistent.
Doing yzs#[(loc, v)] is bad and probably, in your case, unnecessary. This insertion of a single element will loop through the entire list with the effect of the new pair ending at the end of the list. Instead of (y, z)::yzs#[(loc, v)] you could do (loc, v)::(y, z)::yzs to reduce this to a constant-time operation.

Related

Insert number into sorted list using List.fold_right

I am trying to insert a number x into a sorted list l using Ocaml's List.fold_right and return the list with the inserted element. I have figured out a way to insert it if the element is to go at the front of the list or in the middle of the list, however I cannot figure out how to code the case where the element is larger than every element in the list and thus must go at the end.
Here is what I have so far:
let insert_number (x: int) (l: int list): int list =
List.fold_right l ~f:(
fun cur -> fun acc ->
if x < cur then cur::x::accum
else cur::accum
) ~init: []
Using this with a test case like:
insert_number (3) ([1; 2; 4]);;
- : int list = [1; 2; 3; 4]
gives the correct answer. However, with a test case like this:
insert_number (3) ([1; 2]);;
- : int list = [1; 2]
the number is not inserted because it should be added to the end of the list.
Could someone help me understand how I am supposed to integrate this case into the function used with List.fold_right.
A fold works by passing along a set of state as it iterates over each element in a list (or other foldable data structure). The function passed in takes both the current element and that state.
I think you're really really close, but you need as Jeffrey suggests a boolean flag to indicate whether or not the value has been inserted. This will prevent multiple insertions and if the flag is still false when the fold is done, we can detect that and add the value to insert.
This match also serves the purpose of giving us an opportunity to discard the no longer needed boolean flag.
let insert v lst =
match List.fold_right
(fun x (inserted, acc) ->
if v > x && not inserted then (true, x::v::acc)
else (inserted, x::acc))
lst
(false, []) with
| (true, lst) -> lst
| (_, lst) -> v::lst
One way to look at List.fold_right is that it looks at each element of the list in turn, but in reverse order. For each element it transforms the current accumulated result to a new one.
Thinking backward from the end of the list, what you want to do, in essence, is look for the first element of the list that's less than x, then insert x at that point.
So the core of the code might look something like this:
if element < x then element :: x :: accum else element :: accum
However, all the earlier elements of the list will also be less than x. So (it seems to me) you need to keep track of whether you've inserted x into the list or not. This makes the accumulated state a little more complicated.
I coded this up and it works for me after fixing up the case where x goes at the front of the list.
Perhaps there is a simpler way to get it to work, but I couldn't come up with one.
As I alluded to in a comment, it's possible to avoid the extra state and post-processing by always inserting the element and effectively doing a "local sort" of the last two elements:
let insert_number x l =
List.fold_right (
fun cur -> function
| [] when x > cur -> [cur; x]
| [] -> [x; cur]
| x::rest when x > cur -> cur::x::rest
| x::rest -> x::cur::rest
) l []
Also, since folding doesn't seem to actually be a requirement, here's a version using simple recursion instead, which I think is far more comprehensible:
let rec insert_number x = function
| [] -> [x]
| cur::rest when cur > x -> x::cur::rest
| cur::rest -> cur::insert_number x rest

Using monad for cumulative sum on list of pairs (haskell)

I have a list of pairs structure [("oct",1),("nov",1),("dec",1)]
I want to calculate sum within pairs: [("oct",1),("nov",2),("dec",3)]. I think this is a good case for monadic implementation, but can't figure out how to preserve containers.
I tried to make function on lists (I already know about scanl1, just showing effort here :)
csm (x:[]) = [x]
csm (x:y:xs) = x : csm ((x + y) : xs)
And then try something like:
sumOnPairs l = do
pair <- l
return (csm (snd pair))
My solution is not working, please point me in the right direction
The list monad models nondetermism: do the same thing to each element of the list, then collect the results in a new list.
For the type of sequential traversal you want (do something to an element, then use the result to do something to the next element, etc), you can use the State monad to do something like
import Control.Monad.Trans.State
import Data.Bifunctor
type Pair = (String, Int)
foo :: Pair -> State Pair Pair
foo (month, y) = do
-- bimap f g (x,y) == (f x, g y)
-- The new month replaces the old month,
-- and y is added to the sum.
modify (bimap (const month) (+y))
-- Return a snapshot of the state
get
sumOnPairs :: [Pair] -> [Pair]
sumOnPairs = flip evalState ("", 0) . traverse foo
At each step, the new state is the current month and the sum
of the old state's number and the current number. traverse accumulates
those states in a list while traversing the original list.
> sumOnPairs [("oct",1),("nov",1),("dec",1)]
[("oct",1),("nov",2),("dec",3)]
You can also keep only the sum in the state, rather than a month that just gets replaced and the sum.
foo' :: Pair -> State Int Pair
foo' x#(_, count) = do
modify (+ count)
fmap (<$ x) get
sumOnPairs' :: [Pair] -> [Pair]
sumOnPairs' = flip evalState 0 . traverse bar
In this case, only the current sum is kept in the state; the new pair is generated by using the <$ operator, which the Functor instance of (,) String to replace the number in the current pair with the sum in the state
> 6 <$ ("foo", 3)
("foo", 6)
I think using Data.Functor.($>) (the flipped version of <$) might be more readable, if you choose this route.
foo' x#(_, count) = do
modify (+ count)
fmap (x $>) get
Visually, it's more similar to what you could write if you didn't need to map over get: x $> y == (fst x, y).

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.

Flip Alternate Elements in a List ML

I have written a function that will flip alternate elements in a list, however I have to call it, then call its methods (I'm new to ML so I apologize if I'm using the incorrect terms). I would prefer to just call the function without having to call the methods inside it. This is what I have to do now:
(*3. Flip alternate elements in a list, if n = odd, element n remains at end*)
fun flip nil x = x
| flip x nil = x
| flip (x::xs) (y::ys) = x::y::flip xs ys;
fun take l =
if l = nil then nil
else hd l::skip (tl l)
and skip l =
if l = nil then nil
else take (tl l);
but when I call it to reverse the elements, I have to call it :
flip (skip d) (take d);
flip (skip e) (take e);
Is there any way to call the function as :
flip (d);
If I call flip (d); now, it just prints
val take = fn : ''a list -> ''a list
val skip = fn : ''a list -> ''a list
Thank you all in advance!
EDIT: I should mention d is just a list of ints:
val d = [1,2,3,4];
Assuming "flipping alternate elements in a list" means turning [1,2,3,4,5,6] into [2,1,4,3,6,5], and throwing away the last element if the length is odd, then you can achieve this simply by pattern matching in a single function:
fun flip (x::y::xs) = y::x::flip xs
| flip _ = []
Some feedback on your code snippets:
Many of your parentheses are unnecessary.
Don't use hd / tl, but rather use pattern matching.
The actual flipping takes place in your take and skip.
Your flip could appropriately be called merge.
If this were the case, in order to fix flip so it only takes one argument:
fun flip xs = merge (skip xs) (take xs)
It is very useful to be able to make helper functions with more arguments and call these.

Less than function in SML

I've come across 2 confusing problems in SML and was hoping someone could help me out:
The first is a function which takes an element and a list and decides whether that element exists in the list or not, here is the code I've attempted to write:
fun member (e,L) = foldl (fn(a,b) => if (e = b) then true else false) false L;
But I get bool * 'a list --> bool but what I need is ''a * ''a list --> bool
As for the second, it also requires an element and a list but returns a list of elements less than the passed one. I'm not sure whether this should be done via map or foldr/foldl.
Any suggestions?
Thanks in advance :)
Regarding the first question, in fn (a, b) => ... a is the next element and b is the accumulator. Since you compare e with b, e is infered to have type bool. You should compare e with a, and never override b when it becomes true:
fun exists (e, L) =
foldl (fn (a, b) => e = a orelse b) false L
For the second question, you can use foldr/foldl to do so. It's similar to the first example; you start with empty list as the accumulator and prepend an element to it whenever that element is smaller than a threshold.
As a tradeoff, foldr gives you the right order but it isn't tail-recursive. On the other hand, foldl is tail-recursive but gives resulting lists in a reverse order.
to see if an element is in list or not try this:
fun elementExist(e, nil) = false
| elementExist(e, x::xs) = if e = x orelse elementExist(e, xs) then true else false;
for the second one to remove the existing element from the list:
fun elFromList(e, nil) = []
| elFromList(e, x::xs) = if e = x then elFromList(e, xs) else x::elFromList(e, xs);
Good Luck!!