ZipList with Scalaz - list

Suppose I have a list of numbers and list of functions:
val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)
Now I would like to use an Applicative to apply f1 to 1, f2 to 2, etc.
val ys: List[Int] = xs <*> fs // expect List(f1(1), f2(2), f3(3))
How can I do it with Scalaz ?

pure for zip lists repeats the value forever, so it's not possible to define a zippy applicative instance for Scala's List (or for anything like lists). Scalaz does provide a Zip tag for Stream and the appropriate zippy applicative instance, but as far as I know it's still pretty broken. For example, this won't work (but should):
import scalaz._, Scalaz._
val xs = Tags.Zip(Stream(1, 2, 3))
val fs = Tags.Zip(Stream[Int => Int](_ + 3, _ + 2, _ + 1))
xs <*> fs
You can use the applicative instance directly (as in the other answer), but it's nice to have the syntax, and it's not too hard to write a "real" (i.e. not tagged) wrapper. Here's the workaround I've used, for example:
case class ZipList[A](s: Stream[A])
import scalaz._, Scalaz._, Isomorphism._
implicit val zipListApplicative: Applicative[ZipList] =
new IsomorphismApplicative[ZipList, ({ type L[x] = Stream[x] ## Tags.Zip })#L] {
val iso =
new IsoFunctorTemplate[ZipList, ({ type L[x] = Stream[x] ## Tags.Zip })#L] {
def to[A](fa: ZipList[A]) = Tags.Zip(fa.s)
def from[A](ga: Stream[A] ## Tags.Zip) = ZipList(Tag.unwrap(ga))
}
val G = streamZipApplicative
}
And then:
scala> val xs = ZipList(Stream(1, 2, 3))
xs: ZipList[Int] = ZipList(Stream(1, ?))
scala> val fs = ZipList(Stream[Int => Int](_ + 10, _ + 11, _ + 12))
fs: ZipList[Int => Int] = ZipList(Stream(<function1>, ?))
scala> xs <*> fs
res0: ZipList[Int] = ZipList(Stream(11, ?))
scala> res0.s.toList
res1: List[Int] = List(11, 13, 15)
For what it's worth, it looks like this has been broken for at least a couple of years.

I see a solution with streamZipApplicative :
import scalaz.std.stream._
import scalaz.Tags
val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)
val zippedLists = streamZipApplicative.ap(Tags.Zip(xs.toStream)) (Tags.Zip(fs.toStream))
val result = Tag.unwrap(zippedLists).toList

Learning Scalaz spends a few paragraphs on this topic in their introduction to Applicatives. They quote LYAHFGG:
However, [(+3),(2)] <> [1,2] could also work in such a way that the first function in the left list gets applied to the first value in the right one, the second function gets applied to the second value, and so on. That would result in a list with two values, namely [4,4]. You could look at it as [1 + 3, 2 * 2].
But then adds:
This can be done in Scalaz, but not easily.
The "not easily" part uses streamZipApplicative like in #n1r3's answer:
scala> streamZipApplicative.ap(Tags.Zip(Stream(1, 2)))(Tags.Zip(Stream({(_: Int) + 3}, {(_: Int) * 2})))
res32: scala.collection.immutable.Stream[Int] with Object{type Tag = scalaz.Tags.Zip} = Stream(4, ?)
scala> res32.toList
res33: List[Int] = List(4, 4)
The "not easily" is the part that bothers me. I'd like to borrow from #Travis Brown fantastic answer. He is comparing the use of monads and applicatives (i.e. why use applicatives when you have a monad?):
Second (and relatedly), it's just a solid development practice to use the least powerful abstraction that will get the job done.
So, I would say that until a framework provides an applicative that works like your first use-case:
val ys: List[Int] = xs <*> fs
To use zip and map here instead:
xs.zip(fs).map(p=>p._2.apply(p._1))
To me, this code is much clearer and simpler than the alternatives in scalaz. This is the least powerful abstraction that gets the job done.

Related

How to merge two types of for comprehension in Scala?

I have seen for being used different ways in Scala, to take some value out of a wrapper like Option or on list or other collections. If I have to pull a List[Int] out of an Option and then iterate on it, can this be done in one for block?
eg.
val l: Option[List[Int]] = Some(List(1,2,3,4))
l: Option[List[Int]] = Some(List(1, 2, 3, 4))
for{
li <- l // li taken out from Option wrapper
number <- li // numbers pulled from li
} yield number*2
cmd7.scala:3: type mismatch;
found : List[Int]
required: Option[?]
number <- li
^
If I understand correctly it wants each entry to be an Option. Is there some way to achieve this effect without two for loops?
Is there some way to achieve this effect without two for loops?
You can do this by calling toList on the Option[List[Int]], turning it into a List[List[Int]] which the for comprehension will flatMap over:
for {
| o <- l.toList
| num <- o
| } yield num * 2
res8: List[Int] = List(2, 4, 6, 8)
This will yield an empty list for the None type:
scala> val l: Option[List[Int]] = None
scala> for {
| o <- l.toList
| num <- o
| } yield num * 2
res3: List[Int] = List()
You can also use Option[T].getOrElse with an empty List[T] as fallback if the option is empty:
scala> for {
| o <- l.getOrElse(List())
| } yield o * 2
res13: List[Int] = List(2, 4, 6, 8)
Personally, I like the explicit map call:
scala> l.map(_.map(_ * 2))
res7: Option[List[Int]] = Some(List(2, 4, 6, 8))
For comprehensions expand to flatMaps, maps and lazy version of filter. flatMap for Option does not accept function A => List[A]. In general you can use only one type of monad in for comprehension.
Obvious solution here are monad transformers. If you have two monads, one in another, it allows you to access the values inside the deeper monad by creating another monad that combines behavior of two.
Note that this works for any two monads, not just Option and List.
Using scalaz:
import scalaz._
import Scalaz._
val list: Option[List[Int]] = Some(List(1, 2, 3, 4))
(for {
number <- ListT(list)
} yield number * 2).run
res0: Option[List[Int]] = Some(List(2, 4, 6, 8))
You need to call run to unwrap the value from transformer.
you can then use more than one list like this:
val xs = List(1, 2, 3).some
val ys = List(0, 2).some
(for {
x <- ListT(xs)
y <- ListT(ys)
} yield x * y).run
res0: Option[List[Int]] = Some(List(0, 2, 0, 4, 0, 6))
If any Option would be None the result would be None as well
(for {
x <- ListT(xs)
y <- ListT(ys)
z <- ListT(none[List[Int]])
} yield x * y).run
res0: Option[List[Int]] = None

Convert a Scala list to a tuple?

How can I convert a list with (say) 3 elements into a tuple of size 3?
For example, let's say I have val x = List(1, 2, 3) and I want to convert this into (1, 2, 3). How can I do this?
You can do it using scala extractors and pattern matching (link):
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
Which returns a tuple
t: (Int, Int, Int) = (1,2,3)
Also, you can use a wildcard operator if not sure about a size of the List
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
You can't do this in a typesafe way. Why? Because in general we can't know the length of a list until runtime. But the "length" of a tuple must be encoded in its type, and hence known at compile time. For example, (1,'a',true) has the type (Int, Char, Boolean), which is sugar for Tuple3[Int, Char, Boolean]. The reason tuples have this restriction is that they need to be able to handle a non-homogeneous types.
an example using shapeless :
import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled
Note: the compiler need some type informations to convert the List in the HList that the reason why you need to pass type informations to the toHList method
Shapeless 2.0 changed some syntax. Here's the updated solution using shapeless.
import shapeless._
import HList._
import syntax.std.traversable._
val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled
The main issue being that the type for .toHList has to be specified ahead of time. More generally, since tuples are limited in their arity, the design of your software might be better served by a different solution.
Still, if you are creating a list statically, consider a solution like this one, also using shapeless. Here, we create an HList directly and the type is available at compile time. Remember that an HList has features from both List and Tuple types. i.e. it can have elements with different types like a Tuple and can be mapped over among other operations like standard collections. HLists take a little while to get used to though so tread slowly if you are new.
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil
scala> val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)
scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)
Despite the simplicity and being not for lists of any length, it is type-safe and the answer in most cases:
val list = List('a','b')
val tuple = list(0) -> list(1)
val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))
Another possibility, when you don't want to name the list nor to repeat it (I hope someone can show a way to avoid the Seq/head parts):
val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head
FWIW, I wanted a tuple to initalise a number of fields and wanted to use the syntactic sugar of tuple assignment.
EG:
val (c1, c2, c3) = listToTuple(myList)
It turns out that there is syntactic sugar for assigning the contents of a list too...
val c1 :: c2 :: c3 :: Nil = myList
So no need for tuples if you've got the same problem.
If you are very sure that your list.size<23 use it:
def listToTuple[A <: Object](list:List[A]):Product = {
val class = Class.forName("scala.Tuple" + list.size)
class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product
scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)
You can't do this in a type-safe way. In Scala, lists are arbitrary-length sequences of elements of some type. As far as the type system knows, x could be a list of arbitrary length.
In contrast, the arity of a tuple must be known at compile time. It would violate the safety guarantees of the type system to allow assigning x to a tuple type.
In fact, for technical reasons, Scala tuples were limited to 22 elements, but the limit no longer exists in 2.11 The case class limit has been lifted in 2.11 https://github.com/scala/scala/pull/2305
It would be possible to manually code a function that converts lists of up to 22 elements, and throws an exception for larger lists. Scala's template support, an upcoming feature, would make this more concise. But this would be an ugly hack.
This can also be done in shapeless with less boilerplate using Sized:
scala> import shapeless._
scala> import shapeless.syntax.sized._
scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))
It's type-safe: you get None, if the tuple size is incorrect, but the tuple size must be a literal or final val (to be convertible to shapeless.Nat).
Using Pattern Matching:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
2015 post.
For the Tom Crockett's answer to be more clarifying, here is a real example.
At first, I got confused about it. Because I come from Python, where you can just do tuple(list(1,2,3)).
Is it short of Scala language ? (the answer is -- it's not about Scala or Python, it's about static-type and dynamic-type.)
That's causes me trying to find the crux why Scala can't do this .
The following code example implements a toTuple method, which has type-safe toTupleN and type-unsafe toTuple.
The toTuple method get the type-length information at run-time, i.e no type-length information at compile-time, so the return type is Product which is very like the Python's tuple indeed (no type at each position, and no length of types).
That way is proned to runtime error like type-mismatch or IndexOutOfBoundException. (so Python's convenient list-to-tuple is not free lunch. )
Contrarily , it is the length information user provided that makes toTupleN compile-time safe.
implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple: Product = elements.length match {
case 2 => toTuple2
case 3 => toTuple3
}
def toTuple2 = elements match {case Seq(a, b) => (a, b) }
def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}
val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad !
val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!
you can do this either
via pattern-matching (what you do not want) or
by iterating through the list and applying each element one by one.
val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String)
val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({
case (f,x) => f.asInstanceOf[Any=>Any](x)
}).asInstanceOf[(Int,Double,String)]
In scala 3, you can do something like this:
def totuple[A](as: List[A]): Tuple = as match
case Nil => EmptyTuple
case h :: t => h *: totuple(t)
but as has been said already, without giving the compiler any more hard-coded type information, you aren't going to know the length of the tuple or the types of its elements, so this is likely hardly any better than the original list.
as far as you have the type:
val x: List[Int] = List(1, 2, 3)
def doSomething(a:Int *)
doSomething(x:_*)

Arithmetic operations on list with missing values

I'm trying to do some arithmetic on a list that may contain missing values.
So far, I'm representing my list with Option[Int]:
val mylist=List( Option(4), Option(8), None )
With this representation, I can easily apply a function over the list (say, multiply by 2):
scala> mylist.map(_.map(_*2))
res2: List[Option[Int]] = List(Some(8), Some(16), None)
However, this looks more complicated than it needs be, so I'm wondering if I'm missing something.
Also, I can't figure out how to write things like the sum. I guess it should be possible with a (big) reduce expression...
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
Well, it's not a pattern I've used myself, but if values can be "missing" then an Option is appropriate. But a List probably isn't. In a List the position isn't usually something you should be relying on, since it's not random-access. Maybe a Vector would be better, or you need to think of a better way of modelling your problem, i.e. not as a list with missing values.
You can deal with Option nicely using for-expressions:
for (o <- mylist; x <- o) yield x * 2
or flatten the list:
mylist.flatten.map(_ * 2)
To sum it:
mylist.flatten.sum
List[Option[Int]] is a good representation for this use case
Is it possible to flatten it earlier with flatMap? For example, if you are creating this list using map, you could use flatMap instead and not have missing values. My suggestion is to not even represent the missing values if possible. If you need to represent them, Option is ideal.
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
The nested map is probably preferable. You can foldLeft also.
foldLeft is also helpful if you need to do something besides sum/product.
scala> val mylist=List( Option(4), Option(8), None )
mylist: List[Option[Int]] = List(Some(4), Some(8), None)
scala> mylist.foldLeft(0){
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res7: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res8: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc - (i * 2)
| case (acc, _) => acc
| }
res16: Int = -24
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
Option is definitely the preferable way to express missing values. You could also think about changing it into a List[(Int, Int)] where the first element indicates the position in your original list and the second element represents the value.
mylist.map(_.map(_*2)) is the best way to map
In my opinion there is no shorter or cleaner way to express that. (You have two "levels" that's why you need two maps!) With my suggested data structure this would turn into mylist.map(t => (t._1, t._2*2)).
is there a simple way to do a sum?
No easier way than om-nom-nom suggested. With my data structure it would be mylist.map(_._2).sum
The most general and most concise way to do this is with Scalaz's semigroup type class. That way, you're not restricted to List[Option[Int]] but can apply the same function to List[Int].
import scalaz._
import Scalaz._
object S {
def double[A:Semigroup](l:List[A]) = l.map(x => x |+| x)
def sum[A:Semigroup](l:List[A]) = l.reduce(_ |+| _)
def main(a:Array[String]) {
val l = List(Some(1), None, Some(2))
val l2 = List(1,2)
println(double(l))
println(sum(l))
println(double(l2))
println(sum(l2))
}
}
This prints
List(Some(2), None, Some(4))
Some(3)
List(2, 4)
3
i'm not sure what it is you are trying to achieve, but this does'nt seem like the right approach. if you need to determine if a value exists in your "list", then perhapse a Set would suit your needs better:
scala> val s = Set(4,8)
s: scala.collection.immutable.Set[Int] = Set(4, 8)
scala> s(4)
res0: Boolean = true
scala> s(5)
res1: Boolean = false
scala> s map (_ * 2)
res2: scala.collection.immutable.Set[Int] = Set(8, 16)
scala> s reduceLeft((a,b) => a+b)
res3: Int = 12
or even easier:
scala> s sum
res4: Int = 12
if you need something more sophisticated, and the index of the element in your list is important, you may use a Map where the keys simulate the index, and missing values can be mapped to some default value:
scala> val m = Map(1 -> 4, 2 -> 8) withDefault(n => 0)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 2 -> 8)
scala> m(1)
res5: Int = 4
scala> m(3)
res6: Int = 0
scala> m map {case (k,v) => (k,2*v)}
res7: scala.collection.immutable.Map[Int,Int] = Map(1 -> 8, 2 -> 16)
scala> m.foldLeft(0){case (sum,(_,v)) => sum+v}
res8: Int = 12
again, not sure what your needs are, but it feels like you are going the wrong way...
Option is a type i would think twice before using. ask yourself if it's realy necessary. there might be solutions that would achieve what you are trying to do in a more elegant way.

Scala list concatenation, ::: vs ++

Is there any difference between ::: and ++ for concatenating lists in Scala?
scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> res0 == res1
res2: Boolean = true
From the documentation it looks like ++ is more general whereas ::: is List-specific. Is the latter provided because it's used in other functional languages?
Legacy. List was originally defined to be functional-languages-looking:
1 :: 2 :: Nil // a list
list1 ::: list2 // concatenation of two lists
list match {
case head :: tail => "non-empty"
case Nil => "empty"
}
Of course, Scala evolved other collections, in an ad-hoc manner. When 2.8 came out, the collections were redesigned for maximum code reuse and consistent API, so that you can use ++ to concatenate any two collections -- and even iterators. List, however, got to keep its original operators, aside from one or two which got deprecated.
Always use :::. There are two reasons: efficiency and type safety.
Efficiency
x ::: y ::: z is faster than x ++ y ++ z, because ::: is right associative. x ::: y ::: z is parsed as x ::: (y ::: z), which is algorithmically faster than (x ::: y) ::: z (the latter requires O(|x|) more steps).
Type safety
With ::: you can only concatenate two Lists. With ++ you can append any collection to List, which is terrible:
scala> List(1, 2, 3) ++ "ab"
res0: List[AnyVal] = List(1, 2, 3, a, b)
++ is also easy to mix up with +:
scala> List(1, 2, 3) + "ab"
res1: String = List(1, 2, 3)ab
::: works only with lists, while ++ can be used with any traversable. In the current implementation (2.9.0), ++ falls back on ::: if the argument is also a List.
A different point is that the first sentence is parsed as:
scala> List(1,2,3).++(List(4,5))
res0: List[Int] = List(1, 2, 3, 4, 5)
Whereas the second example is parsed as:
scala> List(4,5).:::(List(1,2,3))
res1: List[Int] = List(1, 2, 3, 4, 5)
So if you are using macros, you should take care.
Besides, ++ for two lists is calling ::: but with more overhead because it is asking for an implicit value to have a builder from List to List. But microbenchmarks did not prove anything useful in that sense, I guess that the compiler optimizes such calls.
Micro-Benchmarks after warming up.
scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t}
scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } })
res1: Long = 46
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } })
res2: Long = 46
As Daniel C. Sobrai said, you can append the content of any collection to a list using ++, whereas with ::: you can only concatenate lists.

How to flatten a List of different types in Scala?

I have 4 elements:List[List[Object]] (Objects are different in each element) that I want to zip so that I can have a List[List[obj1],List[obj2],List[obj3],List[obj4]]
I tried to zip them and I obtained a nested list that I can't apply flatten to because it says: no implicit argument matching parameter type.
How can I solve this? should I try another way or is there any way to make the flatten work?
I'm kinda new to scala so it may be a dumb question :D
Thanks in advance!
clau
For One Nested List:
flatten will do:
scala> List(List(1), List(2), List(3)).flatten
res4: List[Int] = List(1, 2, 3)
scala> List(List(List(1)), List(List(2)), List(List(3))).flatten
res5: List[List[Int]] = List(List(1), List(2), List(3))
For multiple Nested Lists then you can:
def flatten(ls: List[Any]): List[Any] = ls flatMap {
case i: List[_] => flatten(i)
case e => List(e)
}
val k = List(1, List(2, 3), List(List(List(List(4)), List(5)), List(6, 7)), 8)
flatten(k)
It prints List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8)
Before Scala 2.9
From the error you pasted, it looks like you're trying to call the flatten instance method of the nested list itself. That requires an implicit conversion to make something of type Iterable out of whatever types the List contains. In your case, it looks like the compiler can't find one.
Use flatten from the List singleton object, which doesn't require that implicit parameter:
scala> val foo = List(List(1), List("a"), List(2.3))
foo: List[List[Any]] = List(List(1), List(a), List(2.3))
scala> List.flatten(foo)
res1: List[Any] = List(1, a, 2.3)
After Scala 2.9
Just use foo.flatten.
The question is very vague. You should plain paste what you have, instead of trying to describe it. It would make everyone's (including your's) life much easier.
The code below is one example based on an assumption of what you have.
scala> List(List(1))
res0: List[List[Int]] = List(List(1))
scala> List(List(2))
res1: List[List[Int]] = List(List(2))
scala> List(List(3))
res2: List[List[Int]] = List(List(3))
scala> List(List(4))
res3: List[List[Int]] = List(List(4))
scala> res0 ::: res1 ::: res2 ::: res3
res4: List[List[Int]] = List(List(1), List(2), List(3), List(4))
In scala 2.10.2
scala> val foo = List(List(1), List("a"), List(2.3))
foo: List[List[Any]] = List(List(1), List(a), List(2.3))
scala> foo.flatten
res0: List[Any] = List(1, 2, a, 2.3)
working fine but
if you run like
scala> val foo = List(List(1,2), 2, List(2.3))
foo: List[Any] = List(List(1, 2), 2, List(2.3))
scala> foo.flatten
<console>:9: error: No implicit view available from Any => scala.collection.GenTraversableOnce[B].
foo.flatten
for that i write function
scala> def flat(ls: List[Any]): List[Any]= ls flatten {
| case t: List[Any] => flat(t)
| case c => List(c)
| }
flat: (ls: List[Any])List[Any]
scala> flat(List(List(1,2),2,List(2.3)))
res2: List[Any] = List(1, 2, 2, 2.3)
It helps if we have an example. Your code should look something like:
val f = List(1, 2)
val s = List(3, 4)
val top = List(f, s)
List.flatten(top) // returns List(1, 2, 3, 4)
You can only zip two lists at a time with list1 zip list2, and the type signature for the return values is List[(A,B)] not List[List[obj1],List[obj2],List[obj3],List[obj4]]
Consider List.concat, for instance
List.concat(List(1), List(2,22), List(3)) // delivers List(1, 2, 22, 3)