SML - changing the value of multiple tuples in the list - sml

I'm new to SML. I'm writing a function which accepts 2 int (x,y) and a list of tuples (named boxes) as input. The length of my list can change. I want to find 2 tuples in the list whose elements depends on x and y. for example I want to check whether there is a tuple like box1=(x,y) and another tuple like box2=(x-2,y-3) and if both of them are available in the list then their values should be changed and returned simultaneously. I know how to find a tuple and change it's value using List.map . but how about updating multiple tuples?
fun move(x,y,boxes:(int * int)list) =
if List.exists (fn s => s = (x,y)) boxes andalso
List.exists (fn p => p = (x-1,y-2)) boxes
then ... (then for example how to change their value to box1=(x-1,y-2)
and box2=(x-3,y-4) at the same time and update them in the list)

List.map (fn p =>
if p = (x, y) then (x-1, y-2)
else if p = (x-2, y-3) then (x-3, y-4)
else p
) boxes

Related

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).

Updating a list of 2-tuples in 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.

SML - Finding an element in the list and changing it's value

I'm new to SML. I'm writing a function which accepts 2 int and a list of tuples as input:
fun moveBoxL(Xw,Yw,boxes:(int * int)list) =
The length of my list(boxes) can change. I want to find a tuple in the list whose elements are equal to Xw,Yw. For example I want a tuple like box1 whose elements are like this: box1=(Xw,Yw) and if there was such a tuple, I want to change it's value => box1(Xw-1,Yw-1) .
Is there a way?
fun moveBox (x, y, boxes) = List.map (fn p => if p = (x,y) then (x-1,y-1) else p) boxes

How to compare each element separately of two char lists Standard ML

I am very new to SML and i am trying to write a function where it compares two char lists, in a way that it takes one character from list1 and compares it with all the characters from list2, for example
val list1 = explode("abcdefghijklmnopqrstuvwxyz")
val list2 = explode("bcdaghklfeijonmtrqpsvuwyzx!-232=,./;'[]{}:?<")
so from list1 it takes the element 'a', and then compares it with each element of list2 and it keeps checking all elements, if the jumbled list2 is equal to to the non jumbled list1 then it returns true
This sounds like an XY problem,
The XY problem is asking about your attempted solution rather than your actual problem. This leads to enormous amounts of wasted time and energy, both on the part of people asking for help, and on the part of those providing help.
Are you testing if list1 is a subset, sub-multiset, sub-string, sub-sequence, or a permutation of list2? Or if they are set-equivalent? Try and express your actual problem and then describe your attempted solution. :-)
You probably want to use a combination of List.exists and List.all.
For example, if you were to test if list1 is a subset of list2:
fun contains (ys, x) = List.exists (fn y => x = y) ys
fun isSubsetOf (xs, ys) = List.all (fn x => contains (ys, x)) xs
Which says: For all x ∈ xs, there must exist a y ∈ ys such that x = y.

SML - Find occurences in lists to form ordered pairs

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