Are tuples comparable in SML? - tuples

Suppose we needed to compare values inside tuples (to give context, let's say a tuple of 3 values represents a data dd/mm/yy) & we want to check which if date1< date2.
Is it possible to compare tuples?
fun is_older(date1:int*int*int, date2:int*int*int) =
(#3 date1, #2 date1, #1 date1) < (#3 date2, #2 date2, #1 date2);
This answer was generated by chatGPT & gave an error. I correctly implemented a similar function using if statements, but was wondering if tuples are actually comparable.

Again, I suggest pattern matching. It's cleaner.
fun is_older((a, b, c), (x, y, z)) =
(c, b, a) < (z, y, x);
Second, no. The type of op< is int * int → bool.

Related

How can I maintain a counter when using map on a list? [duplicate]

Horner's rule is used to simplify the process of evaluating a polynomial at specific variable values. https://rosettacode.org/wiki/Horner%27s_rule_for_polynomial_evaluation#Standard_ML
I've easily applied the method using SML, to a one variable polynomial, represented as an int list:
fun horner coeffList x = foldr (fn (a, b) => a + b * x) (0.0) coeffList
This works fine. We can then call it using:
- val test = horner [1.0, 2.0, 3.0] 2.0;
> val test = 17.0 : real
Where [1.0, 2.0, 3.0] is the list representing the polynomial coefficients, 2.0 is the value of the variable x, and 17.0 is the result of evaluating the polynomial.
My problem is as such: We have a two variable polynomial represented by an (int list list). The nth item in a high-level list will represent all the polynomial terms containing y^n, and the mth item in a low-level list will represent all the polynomial terms containing x^m.
For example: [[2],[3,0,0,3],[1,2]] is the polynomial
( 2(x^0)(y^0) ) +
( 3(x^0)(y^1) + 0(x^1)(y^1) + 0(x^2)(y^1) + 3(x^3)(y^1) ) +
( 1(x^0)(y^2) + 2(x^1)(y^2) )
The function needs to return the value of the polynomial at the specified x and y.
I've tried various methods using the mlton compiler.
First I tried a nested foldr function:
fun evalXY (z::zs) x y =
foldr
(fn (s, li:list) =>
s + ((foldr (fn(a, b) => a + b*x) 0 li)*y)
)
0
z:zs
You can see that I'm trying to use "s" as an accumulator, like "a" was used in the single variable example. Since each element being processed by foldr needs to be "foldr'ed" itself, i call foldr again in the function describing the outer foldr. I know hat this inner foldr works fine, I proved it above. *My problem seems to be that I cant access the element of the list that the outer foldr is on to pass that list into the inner foldr. >See where I use li in the inner foldr, thats my issue. *
Then i tried applying my single variable function to map. I came across the same issue:
fun evalXY (z::zs) x y =
map
(foldr (fn(a, b) => a + b*x) 0 ???)
z:zs
*With this attempt, i know that im getting back a list of ints. I put in an int list list, in which the inner lists were processed and returned to the outer list as ints by foldr. After this i would foldr again to apply the y value to the polynomial.
The function here should look like :: fn evalXY : (int list list) * int * int) -> ... -> int list *
I am new to SML, so maybe i'm missing something fundamental here. I know this is a functional programming language, so I'm trying to accumulate values instead of altering different variables,
You're very close. Let's begin by formalizing the problem. Given coefficients C as a nested list like you indicated, you want to evaluate
Notice that you can pull out the s from the inner sum, to get
Look closely at the inner sum. This is just a polynomial on variable x with coefficients given by . In SML, we can write the inner sum in terms of your horner function as
fun sumj Ci = horner Ci x
Let's go a step further and define
In SML, this is val D = map sumj C. We can now write the original polynomial in terms of D:
It should be clear that this is just another instance of horner, since we have a polynomial with coefficients . In SML, the value of this polynomial is
horner D y
...and we're done!
Here's the final code:
fun horner2 C x y =
let
fun sumj Ci = horner Ci x
val D = map sumj C
in
horner D y
end
Isn't that nice? All we need is multiple applications of Horner's method, and map.
Your second approach seems to be on the right track. If you have already defined horner, what you need to do is to apply horner to the result of mapping horner applied to inner list x over the outer list, something like:
fun evalXY coeffLists x y = horner (map (fn coeffList => horner coeffList x) coeffLists) y
You could replace the two calls to horner by the corresponding folds, but it would be much less readable.
Note that if you reverse the order of the two parameters in horner then you can shorted evalXY:
fun horner x coeffList = foldr (fn (a, b) => a + b * x) (0.0) coeffList
fun evalXY x y coeffLists = horner y (map (horner x) coeffLists)
The point being that the way currying works, if you use this second order then horner x is already a function of coeffList so you no longer need the anonymous function fn coeffList => horner coeffList x. The moral of the story is that when defining a curried function, you should think carefully about the order of the parameters since it will make some partial applications easier to create than others.
By the way, SML is fussy. In your discussion of horner you said that you would call it like horner list 2. It would need to be horner list 2.0. Similarly, in your second attempt, using 0 rather than 0.0 is problematic.

Flatten a list of tuples in Scala?

I would have thought that a list of tuples could easily be flattened:
scala> val p = "abcde".toList
p: List[Char] = List(a, b, c, d, e)
scala> val q = "pqrst".toList
q: List[Char] = List(p, q, r, s, t)
scala> val pq = p zip q
pq: List[(Char, Char)] = List((a,p), (b,q), (c,r), (d,s), (e,t))
scala> pq.flatten
But instead, this happens:
<console>:15: error: No implicit view available from (Char, Char) => scala.collection.GenTraversableOnce[B].
pq.flatten
^
I can get the job done with:
scala> (for (x <- pq) yield List(x._1, x._2)).flatten
res1: List[Char] = List(a, p, b, q, c, r, d, s, e, t)
But I'm not understanding the error message. And my alternative solution seems convoluted and inefficient.
What does that error message mean and why can't I simply flatten a List of tuples?
If the implicit conversion can't be found you can supply it explicitly.
pq.flatten {case (a,b) => List(a,b)}
If this is done multiple times throughout the code then you can save some boilerplate by making it implicit.
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> implicit def flatTup[T](t:(T,T)): List[T]= t match {case (a,b)=>List(a,b)}
flatTup: [T](t: (T, T))List[T]
scala> pq.flatten
res179: List[Char] = List(a, p, b, q, c, r, d, s, e, t)
jwvh's answer covers the "coding" solution to your problem perfectly well, so I am not going to go into any more detail about that. The only thing I wanted to add was clarifying why the solution that both you and jwvh found is needed.
As stated in the Scala library, Tuple2 (which (,) translates to) is:
A tuple of 2 elements; the canonical representation of a Product2.
And following up on that:
Product2 is a cartesian product of 2 components.
...which means that Tuple2[T1,T2] represents:
The set of all possible pairs of elements whose components are members of two sets (all elements in T1 and T2 respectively).
A List[T], on the other hand, represents an ordered collections of T elements.
What all this means practically is that there is no absolute way to translate any possible Tuple2[T1,T2] to a List[T], simply because T1 and T2 could be different. For example, take the following tuple:
val tuple = ("hi", 5)
How could such tuple be flattened? Should the 5 be made a String? Or maybe just flatten to a List[Any]? While both of these solutions could be used, they are working around the type system, so they are not encoded in the Tuple API by design.
All this comes down to the fact that there is no default implicit view for this case and you have to supply one yourself, as both jwvh and you already figured out.
We needed to do this recently. Allow me to explain the use case briefly before noting our solution.
Use case
Given a pool of items (which I'll call type T), we want to do an evaluation of each one against all others in the pool. The result of these comparisons is a Set of failed evaluations, which we represent as a tuple of the left item and the right item in said evaluation: (T, T).
Once these evaluations are complete, it becomes useful for us to flatten the Set[(T, T)] into another Set[T] that highlights all the items that have failed any comparisons.
Solution
Our solution for this was a fold:
val flattenedSet =
set.foldLeft(Set[T]())
{ case (acc, (x, y)) => acc + x + y }
This starts with an empty set (the initial parameter to foldLeft) as the accumulator.
Then, for each element in the consumed Set[(T, T)] (named set) here, the fold function is passed:
the last value of the accumulator (acc), and
the (T, T) tuple for that element, which the case deconstructs into x and y.
Our fold function then returns acc + x + y, which returns a set containing all the elements in the accumulator in addition to x and y. That result is passed to the next iteration as the accumulator—thus, it accumulates all the values inside each of the tuples.
Why not Lists?
I appreciated this solution in particular since it avoided creating intermediate Lists while doing the flattening—instead, it directly deconstructs each tuple while building the new Set[T].
We could also have changed our evaluation code to return List[T]s containing the left and right items in each failed evaluation—then flatten would Just Work™. But we thought the tuple more accurately represented what we were going for with the evaluation—specifically one item against another, rather than an open-ended type which could conceivably represent any number of items.

Confused about workings of a Haskell list comprehension

I'm a new programmer and using Haskell. I've found a line of code called find that matches up a String with its corresponding pair in a list. Like so
find a b = [x|(y,x) <- b, a==y]
I don't understand fully what this program is saying, for the list comprehension, as I've never seen the x|(y,x) used in such a way before, I've mainly seen it used as x|x or x|x^2. So, does this mean that find the string A, from your input list B = a list comprehension of x, where x is a pair of (String, Char) from your B, and for which the y equals your inputted a? A little confused here.
I would pronounce that comprehension
The list of all x such that (y, x) is drawn from b and a == y.
Another way to read it, more sequentially:
Draw pairs (y, x) from b. For each such pair, check whether a == y. If so, produce x; otherwise, move on to the next one.
I should also note that the variable names are a bit confusing. It's idiomatic in Haskell to give lists or other containers plural names. So something more like
find a abs = [x | (y, x) <- abs, a == y]
You seem to view "x|x" as a thing. Rather, list comprehensions work like this:
[ expression to return | stuff to iterate over ]
What your example basically says is "draw (x, y) from b, throw away anything which doesn't satisfy a == y, and then return x".
Lets give you an example in order to visualize it:
find a b = [x|(y,x) <- b, a==y]
Let a=2, b=[(1,3),(2,4),(3,5),(2,7)]
(y,x) will get each of (1,3),(2,4),(3,5),(2,7) as a couple and check if the first element equals 2 (we said that a equals 2). If True, the function will return the second element of that couple - x, and put it in a list with the rest of the answers.
So the output for that function would be [4,7]

Prolog list of transitive pairs

I've been trying to solve the following problem for a while now, but can't seem to find the right solution.
Lets say there is a function test(X,Y,Z) such that X is a single pair of numbers, Y is a list of pairs, and Z is the resulting list of transitive pairs.
For example:
test((1,5), [(7,3),(5,2),(5,9)], Z).
Z = [(1,2),(1,9)]
(because of transitivity 1->5->2 and 1->5->9)
So far I've managed to create the following code:
test(_,[],_):- false.
test((X1,C),[(C,Y2)|_],(X1,Y2)).
test((X1,X2),[_|YT],Result) :- test((X1,X2),YT,Result).
It returns each individual result pair like so:
Z = (1, 2) ;
Z = (1, 9) ;
But I can't seem to return them all into a single list like in the example above:
Z = [(1,2),(1,9)]
Any help would be greatly appreciated.
I think the problem is that you're not building the list of transitive pairs. You're just returning a single pair as the third argument of test/3.
Here's one possible solution:
I made a predicate to handle comparing pairs and describing their transitive marriage, so that i didn't have to juggle those tuples in the subsequent rules:
transit((X,T), (T,Y), (X,Y)).
Then it's just a matter of standard list processing with recursive predicates:
t(_, [], []).
t(X, [T|ToTransit], [Y|Transited]) :-
transit(X,T,Y),
t(X,ToTransit,Transited).
t(X, [T|ToTransit], Transited) :-
\+ transit(X,T,_),
t(X,ToTransit, Transited).
Of course, once you have a predicate like transit/3 that defines the relation, you can also do something like
findall( TP,
( member(T, [(2,2), (2,5), (1,5)]), transit((1,2), T, TP) ),
Tps).

How can we denote list of tuples in argument

In sml, we define lists of integers or strings as arguments by l::ls which helps us to define lists of arbitrary length and then we can compare with = or > or <. How can we denote tuples in similar manner?
e.g.
I can write,
fun delete(x,l::ls)=if x=l then delete(x,ls) else l::delete(x,ls)
how can I write similarly for tuples?
Note, I even need to compare the individual elements of the tuple: i.e. (a1,b1)>(a2,b2) if b1>b2 so some sortcut that can merely delete like above will not be sufficient.
Tons of Thank You.
You can do pattern matching directly on tuples using the usual form (x, y).
Your delete function works on any 'a list so it is correct for lists of tuples as well. Here is an example which filters a list based on the first values in tuples:
fun deleteByFirst(x0, []) = []
| deleteByFirst(x0, (x, y)::ls) =
if x = x0
then deleteByFirst(x0, ls)
else (x, y)::deleteByFirst(x0, ls)