My problem is phrased in the code below.
I’m trying to get some input that has the .map function in it. I know that if I call .map to it, it will return an Int to me.
// In my case, they are different representations of Ints
// By that I mean that in the end it all boils down to Int
val list: Seq[Int] = Seq(1,2,3,4)
val optInt: Option[Int] = Some(1)
// I can use a .map with a Seq, check!
list.map {
value => println(value)
}
// I can use it with an Option, check!
optInt.map {
value => println(value)
}
// Well, you're asking yourself why do I have to do it,
// Why don't I use foreach to solve my problem. Check!
list.foreach(println)
optInt.foreach(println)
// The problem is that I don't know what I'm going to get as input
// The only thing I know is that it's "mappable" (it has the .map function)
// And that if I were to apply .map it would return Ints to me
// Like this:
def printValues(genericInputThatHasMap: ???) {
genericInputThatHasMap.map {
value => println(value)
}
}
// The point is, what do I have to do to have this functionality?
// I'm researching right now, but I still haven't found anything.
// That's why I'm asking it here =(
// this works:
def printValues(genericInputThatHasMap: Seq[Int]) {
genericInputThatHasMap.map {
value => println(value)
}
}
Thanks in advance! Cheers!
First for a quick note about
mapandforeach. If you’re only interested in performing an operation with a side effect (e.g., printing to standard output or a file, etc.) on each item in your collection, useforeach. If you’re interested in creating a new collection by transforming each element in your old one, usemap. When you writexs.map(println), you will in fact print all the elements of the collection, but you’ll also get back a (completely useless) collection of units, and will also potentially confuse future readers of your code—including yourself—who expectforeachto be used in a situation like this.Now on to your problem. You’ve run into what is in my opinion one of the ugliest warts of the Scala standard library—the fact that methods named
mapandforeach(andflatMap) get magical treatment at the language level that has nothing to do with a specific type that defines them. For example, I can write this:And use it in a
forloop like this, simply because I’ve named my methodforeach:You can use structural types to do something similar in your own code:
Here any
xswith an appropriately typedforeachmethod—for example anOption[Int]or aList[Int]—will compile and work as expected.Structural types get a lot messier when you’re trying to work with
maporflatMapthough, and are unsatisfying in other ways—they impose some ugly overhead due to their use of runtime reflection, for example. They actually have to be explicitly enabled in Scala 2.10 to avoid warnings for these reasons.As senia’s answer points out, the Scalaz library provides a much more coherent approach to the problem through the use of type classes like
Monad. You wouldn’t want to useMonad, though, in a case like this: it’s a much more powerful abstraction than you need. You’d useEachto provideforeach, andFunctorformap. For example, in Scalaz 7:Or:
To summarize, you can do what you want in a standard, idiomatic, but arguably ugly way with structural types, or you can use Scalaz to get a cleaner solution, but at the cost of a new dependency.