OCaml map on a tuple - ocaml

I have several places in my code which look like this:
let (a,b,c) = (f "a", f "b", f "c")
It would be nice if I can write something like:
let (a,b,c) = map f ("a", "b", "c")
If there is way to do something like this in OCaml?

You can easily write map for triples of one type of element:
let map_triple f (a, b, c) = (f a, f b, f c)
let a, b, c = map_triple String.length ("foo", "bar", "quux")
It will only work for one length of tuple, however.
It would be possible to write a GADTified tuple type and write a map over that type that is polymorphic in the length of the tuple, but that kind of trickery is best avoided unless the advantage is large, which does not seem to be the case here.

The best answer is that you can't do this, if you want it to work for tuples of different sizes. Each tuple size is a different type in OCaml. So there's no OCaml type representing the idea of "a tuple of any size whose elements are strings."
But in fact this sounds like a list more than a tuple. If you can use lists instead of tuples, you can use the plain old List.map function.

Related

Interleaving in OCaml

I am trying to create a function which interleaves a pair of triples such as ((6, 3, 2), ( 4, 5 ,1)) and create a 6-tuple out of this interleaving.
I made some research but could understand how interleaving is supposed to work so I tried something on my own end ended up with a code that is creating a 6-tuple but not in the right interleaved way. This is my code
let interleave ((a, b, c), (a', b', c')) =
let sort2 (a, b) = if a > b then (a, b) else (b, a) in
let sort3 (a, b, c) =
let (a, b) = sort2 (a, b) in
let (b, c) = sort2 (b, c) in
let (a, b) = sort2 (a, b) in
(a, b, c) in
let touch ((x), (y)) =
let (x) = sort3 (x) in
let (y) = sort3 (y) in
((x),(y)) in
let ((a, b, c), (a', b', c')) = touch ((a, b, c), (a', b', c')) in
(a, b', a', b, c, c');;
Can someone please explain to me how with what functions I can achieve a proper form of interleaving. I haven't learned about recursions and lists in case you would ask why I am trying to do it this way.
Thank you already.
The problem statement uses the word "max" without defining it. If you use the built-in compare function of OCaml as your definition, it uses lexicographic order. So you want the largest value (of the 6 values) in the first position in the 6-tuple, the second largest value next, and so on.
This should be pretty easy given your previously established skill with the sorting of tuples.
For what it's worth, there doesn't seem to be much value in preserving the identities of the two 3-tuples. Once inside the outermost function you can just work with the 6 values as a 6-tuple. Or so it would seem to me.
Update
From your example (should probably have given it at the beginning :-) it's pretty clear what you're being asked to do. You want to end up with a sequence in which the elements of the original tuples are in their original order, but they can be interleaved arbitrarily. This is often called a "shuffle" (or a merge). You have to find the shuffle that has the maximum value lexicographically.
If you reason this out, it amounts to taking whichever value is largest from the front of the two tuples and putting it next in the output.
This is much easier to do with lists.
Now that I understand what your end-goal is . . .
Since tuples of n elements are different types for different n's, you need to define helper functions for manipulating different sizes of tuples.
One approach, that basically mimics a recursive function over lists (but requires many extra functions because of tuples all having different types), is to have two sets of helper functions:
functions that prepend a value to an existing tuple: prepend_to_2, up through prepend_to_5. For example,
let prepend_to_3 (a, (b, c, d)) = (a, b, c, d)
functions that interleave two tuples of each possible size up to 3: interleave_1_1, interleave_1_2, interleave_1_3, interleave_2_2, interleave_2_3, and interleave_3_3. (Note that we don't need e.g. interleave_2_1, because we can just call interleave_1_2 with the arguments in the opposite order.) For example,
let interleave_2_2 ((a, b), (a', b')) =
if a > a'
then prepend_to_3 (a, interleave_1_2 (b, (a', b')))
else prepend_to_3 (a', interleave_1_2 (b', (a, b)))
(Do you see how that works?)
Then interleave is just interleave_3_3.
With lists and recursion this would be much simpler, since a single function can operate on lists of any length, so you don't need multiple different copies of the same logic.

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.

Zipping same value over a list of tuples Haskell

I would like to transform the following tuple list
a = [(1,()),(2,())]
into a nested tuple list by the same value
b = [(False,(1,())),(False,(2,()))]
Using the zip function in this format
zip [False] a
only gives me
[(False,(1,()))]
Any suggestions or advice would be much appreciated.
If you zip two lists of different lengths, you get the length of the shortest list.
You can fix this by zipping against an infinitely long list:
zip (repeat False) a
should do the trick.
Alternatively, instead of using zip you can use map:
map (\x -> (False, x)) a
This would more appropriately express your intent (in my opinion) since you want to do the same thing to every element of the list. If you want to do different things to each element, then zip or zipWith may be more appropriate.
If you wanted to avoid the lambda, you can write it pointfree using &&& from Control.Arrow:
map (const False &&& id) a
which basically says "apply the functions const False and id to the input, then construct a tuple of both of their outputs". There is the TupleSections extension which would allow you to write this as
map (False,) a
(tip provided by #thoferon), but I personally find this less clear, since you have to know that the extension is enabled and notice the , after False. You could write it as
map ((,) False) a
without the extension since (,) acts as a function of type a -> b -> (a, b), and while a bit more verbose it doesn't require enabling a language extension.
In addition to others answers it is also possible to write a generic function for any Functor, not just for lists:
strengthL :: Functor f => a -> f b -> f (a, b)
strengthL = fmap . (,)
strengthR :: Functor f => a -> f b -> f (b, a)
strengthR = fmap . flip (,)
Then strengthL can be applied to False and the original list:
Prelude> strengthL False [(1,()),(2,())]
[(False,(1,())),(False,(2,()))]

In Scala, is there a way to take convert two lists into a Map?

I have a two lists, a List[A] and a List[B]. What I want is a Map[A,B] but I want the semantics of zip. So started out like so:
var tuplesOfAB = listOfA zip listOfB
Now I'm not sure how to construct a Map from my tuplesOfAB.
As a follow-up question, I also want to invert my map so that from a Map[A,B] I can create a Map[B,A]. Can anyone hit me with a clue-stick?
In 2.8 this is really simple using the CanBuildFrom functionality (as described by Daniel) and using breakOut with a type instruction to the compiler as to what the result type should be:
import scala.collection.breakOut
val m = (listA zip listB)(breakOut): Map[A,B]
The following would also work:
val n: Map[A,B] = (listA zip listB)(breakOut)
And (as EastSun, below, has pointed out) this has been added to the library as toMap
val o = (listA zip listB).toMap
As for reversing the map, you can do:
val r = m.map(_.swap)(breakOut): Map[B, A]
Now that you've got a list of tuples it is easy to make it into a map by writing Map(tuplesOfAB: _*). The : _* notation means to call the varargs overload with the arguments taken from the sequence. This seems like a funny bit of syntax, but it helps to think that varargs are declared like Map[A,B](pairs: (A,B)*) and the : _* is a type annotation to convert to varargs because of the common * part.
To reverse a map m use Map(m.map(_.swap): _*). In scala a map is also a collection of pairs. This transforms those pairs by swapping the elements and passing them to the Map constructor.
There's yet another way to do it, beyond those already shown. Here:
Map() ++ tuplesOfAB
scala> List( "a", "f", "d") zip List(7, 5, 4, 8) toMap
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 7, f -> 5, d -> 4)

How can I avoid warnings when I apply function to a known list of arguments in OCaml?

How can I transform several values a,b,c etc. to a',b',c' etc, such that x'=f(x)? The values are bound to specific names and their quantity is known at compile-time.
I tried to apply a function to a list in the following way:
let [a';b'] = List.map f [a;b] in ...
But it yields warning:
Warning P: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
[]
Any way to avoid it?
You can write a few functions for mapping on to uniform tuples, i.e.:
let map4 f (x,y,z,w) = (f x, f y, f z, f w)
let map3 f (x,y,z) = (f x, f y, f z)
let map2 f (x,y) = (f x, f y)
and then you can just use them whenever the need arises.
let (x',y') = map2 f (x,y)
Unfortunately not. You can silence the compiler by writing
match List.map f [a;b] with
[a';b'] -> ...
| _ -> assert false
but that's all.
The compiler is trying to help you here. It tells you that you are trying to assign an unknown list to [a';b'] . What if one year later you change this code so that the first list, [a;b], is refactored to a different place in the code so you don't see it, and the function f is changed so that it sometimes returns a different list? You will then sometimes get a run-time exception trying to match [a';b'] with a wrong list. The compiler cannot check that the code is correct, hence the warning.
Why not write
let (a', b', c') = ( f a, f b, f c);;
It's not so much more work to write this, but completely safe against any future changes in the code.