`doto` for Scala - scala

Clojure offers a macro called doto that takes its argument and a list of functions and essentially calls each function, prepending the (evaluated) argument:
(doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
-> {a=1, b=2}
Is there some way to implement something similar in Scala? I envision something with the following form:
val something =
doto(Something.getInstance) {
x()
y()
z()
}
which will be equivalent to
val something = Something.getInstance
something.x()
something.y()
something.z()
Might it be possible using scala.util.DynamicVariables?
Note that with factory methods, like Something.getInstance, it is not possible to use the common Scala pattern
val something =
new Something {
x()
y()
z()
}

I don't think there is such a thing built-in in the library but you can mimic it quite easily:
def doto[A](target: A)(calls: (A => A)*) =
calls.foldLeft(target) {case (res, f) => f(res)}
Usage:
scala> doto(Map.empty[String, Int])(_ + ("a" -> 1), _ + ("b" ->2))
res0: Map[String,Int] = Map(a -> 1, b -> 2)
scala> doto(Map.empty[String, Int])(List(_ + ("a" -> 1), _ - "a", _ + ("b" -> 2)))
res10: Map[String,Int] = Map(b -> 2)
Of course, it works as long as your function returns the proper type. In your case, if the function has only side effects (which is not so "scalaish"), you can change doto and use foreach instead of foldLeft:
def doto[A](target: A)(calls: (A => Unit)*) =
calls foreach {_(target)}
Usage:
scala> import collection.mutable.{Map => M}
import collection.mutable.{Map=>M}
scala> val x = M.empty[String, Int]
x: scala.collection.mutable.Map[String,Int] = Map()
scala> doto(x)(_ += ("a" -> 1), _ += ("a" -> 2))
scala> x
res16: scala.collection.mutable.Map[String,Int] = Map(a -> 2)

In Scala, the "typical" way to do this would be to chain "tap" or "pipe" methods. These are not in the standard library, but are frequently defined as so:
implicit class PipeAndTap[A](a: A) {
def |>[B](f: A => B): B = f(a)
def tap[B](f: A => B): A = { f(a); a }
}
Then you would
(new java.util.HashMap[String,Int]) tap (_.put("a",1)) tap (_.put("b",2))
This is not as compact as the Clojure version (or as compact as Scala can be), but it is about as close to canonical as one is likely to get.
(Note: if you want to minimize run-time overhead for adding these methods, you can make a a private val and have PipeAndTap extend AnyVal; then this will be a "value class" which is only converted into a real class when you need an object to pass around; just calling a method doesn't actually require class creation.)
(Second note: in older versions of Scala, implicit class does not exist. You have to separately write the class and an implicit def that converts a generic a to a PipeAndTap.)

I think, that the closest would be to import this object's members in scope:
val something = ...
import something._
x()
y()
z()
In this post you can find another example (in section "Small update about theoretical grounds"):
http://hacking-scala.posterous.com/side-effecting-without-braces
Also small advantage with this approach - you can import individual members and rename them:
import something.{x, y => doProcessing}

More simple I guess:
val hm = Map [String, Int] () + ("a"-> 1) + ("b"-> 2)
Your sample
val something =
doto (Something.getInstance) {
x()
y()
z()
}
doesn't look very functional, because - what is the result? I assume you're side effecting.
Something.x().y().z()
could be a way if each call produces the type where the next function can act on.
z(y(x(Something)))
another kind of producing a result.
And there is the andThen method to chain method calls on collections, you might want to have a look at.
For your Map-example, a fold-left is another way to go:
val hm = Map [String, Int] () + ("a"-> 1) + ("b"-> 2)
val l = List (("a", 8), ("b", 7), ("c", 9))
(hm /: l)(_ + _)
// res8: scala.collection.immutable.Map[String,Int] = Map(a -> 8, b -> 7, c -> 9)

Well, I can think of two ways of doing it: passing strings as parameters, and having a macro change the string and compile it, or simply importing the methods. If Scala had untyped macros, maybe they could be used as well -- since it doesn't have them, I'm not going to speculate on it.
At any rate, I'm going to leave macro alternatives to others. Importing the methods is rather simple:
val map = collection.mutable.Map[String, Int]()
locally {
import map._
put("a", 1)
put("b", 2)
}
Note that locally doesn't do anything, except restrict the scope in which the members of map are imported.

One very basic way to chain several actions is function composition:
val f:Map[Int,String]=>Map[Int,String] = _ + (1 -> "x")
val g:Map[Int,String]=>Map[Int,String] = _ + (2 -> "y")
val h:Map[Int,String]=>Map[Int,String] = _ + (3 -> "z")
(h compose g compose f)(Map(42->"a"))
// Map[Int,String] = Map((42,a), (1,x), (2,y), (3,z))
In this case it's not very practical, though, as the type of the functions can't be inferred easily...

Related

Convert Seq[Try[Option(String, Any)]] into Try[Option[Map[String, Any]]]

How to conveniently convert Seq[Try[Option[String, Any]]] into Try[Option[Map[String, Any]]].
If any Try before convert throws an exception, the converted Try should throw as well.
Assuming that the input type has a tuple inside the Option then this should give you the result you want:
val in: Seq[Try[Option[(String, Any)]]] = ???
val out: Try[Option[Map[String,Any]]] = Try(Some(in.flatMap(_.get).toMap))
If any of the Trys is Failure then the outer Try will catch the exception raised by the get and return Failure
The Some is there to give the correct return type
The get extracts the Option from the Try (or raises an exception)
Using flatMap rather than map removes the Option wrapper, keeping all Some values and discaring None values, giving Seq[(String, Any)]
The toMap call converts the Seq to a Map
Here is something that's not very clean but may help get you started. It assumes Option[(String,Any)], returns the first Failure if there are any in the input Seq and just drops None elements.
foo.scala
package foo
import scala.util.{Try,Success,Failure}
object foo {
val x0 = Seq[Try[Option[(String, Any)]]]()
val x1 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(None))
val x2 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))))
val x3 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))), Failure(new Exception("bad")))
def f(x: Seq[Try[Option[(String, Any)]]]) =
x.find( _.isFailure ).getOrElse( Success(Some(x.map( _.get ).filterNot( _.isEmpty ).map( _.get ).toMap)) )
}
Example session
bash-3.2$ scalac foo.scala
bash-3.2$ scala -classpath .
Welcome to Scala 2.13.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions for evaluation. Or try :help.
scala> import foo.foo._
import foo.foo._
scala> f(x0)
res0: scala.util.Try[Option[Equals]] = Success(Some(Map()))
scala> f(x1)
res1: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1)))
scala> f(x2)
res2: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1, B -> two)))
scala> f(x3)
res3: scala.util.Try[Option[Equals]] = Failure(java.lang.Exception: bad)
scala> :quit
If you're willing to use a functional support library like Cats then there are two tricks that can help this along:
Many things like List and Try are traversable, which means that (if Cats's implicits are in scope) they have a sequence method that can swap two types, for example converting List[Try[T]] to Try[List[T]] (failing if any of the items in the list are failure).
Almost all of the container types support a map method that can operate on the contents of a container, so if you have a function from A to B then map can convert a Try[A] to a Try[B]. (In Cats language they are functors but the container-like types in the standard library generally have map already.)
Cats doesn't directly support Seq, so this answer is mostly in terms of List instead.
Given that type signature, you can iteratively sequence the item you have to in effect push the list type down one level in the type chain, then map over that container to work on its contents. That can look like:
import cats.implicits._
import scala.util._
def convert(listTryOptionPair: List[Try[Option[(String, Any)]]]): Try[
Option[Map[String, Any]]
] = {
val tryListOptionPair = listTryOptionPair.sequence
tryListOptionPair.map { listOptionPair =>
val optionListPair = listOptionPair.sequence
optionListPair.map { listPair =>
Map.from(listPair)
}
}
}
https://scastie.scala-lang.org/xbQ8ZbkoRSCXGDJX0PgJAQ has a slightly more complete example.
One way to approach this is by using a foldLeft:
// Let's say this is the object you're trying to convert
val seq: Seq[Try[Option[(String, Any)]]] = ???
seq.foldLeft(Try(Option(Map.empty[String, Any]))) {
case (acc, e) =>
for {
accOption <- acc
elemOption <- e
} yield elemOption match {
case Some(value) => accOption.map(_ + value)
case None => accOption
}
}
You start off with en empty Map. You then use a for comprehension to go through the current map and element and finally you add a new tuple in the map if present.
The following solutions is based on this answer to the point that almost makes the question a duplicate.
Method 1: Using recursion
def trySeqToMap1[X,Y](trySeq : Seq[Try[Option[(X, Y)]]]) : Try[Option[Map[X,Y]]] = {
def helper(it : Iterator[Try[Option[(X,Y)]]], m : Map[X,Y] = Map()) : Try[Option[Map[X,Y]]] = {
if(it.hasNext) {
val x = it.next()
if(x.isFailure)
Failure(x.failed.get)
else if(x.get.isDefined)
helper(it, m + (x.get.get._1-> x.get.get._2))
else
helper(it, m)
} else Success(Some(m))
}
helper(trySeq.iterator)
}
Method 2: directly pattern matching in case you are able to get a stream or a List instead:
def trySeqToMap2[X,Y](trySeq : LazyList[Try[Option[(X, Y)]]], m : Map[X,Y]= Map.empty[X,Y]) : Try[Option[Map[X,Y]]] =
trySeq match {
case Success(Some(h)) #:: tail => trySeqToMap2(tail, m + (h._1 -> h._2))
case Success(None) #:: tail => tail => trySeqToMap2(tail, m)
case Failure(f) #:: _ => Failure(f)
case _ => Success(Some(m))
}
note: this answer was previously using different method signatures. It has been updated to conform to the signature given in the question.

Scala method to side effect on map and return it

What is the best way to apply a function to each element of a Map and at the end return the same Map, unchanged, so that it can be used in further operations?
I'd like to avoid:
myMap.map(el => {
effectfullFn(el)
el
})
to achieve syntax like this:
myMap
.mapEffectOnKV(effectfullFn)
.foreach(println)
map is not what I'm looking for, because I have to specify what comes out of the map (as in the first code snippet), and I don't want to do that.
I want a special operation that knows/assumes that the map elements should be returned without change after the side-effect function has been executed.
In fact, this would be so useful to me, I'd like to have it for Map, Array, List, Seq, Iterable... The general idea is to peek at the elements to do something, then automatically return these elements.
The real case I'm working on looks like this:
calculateStatistics(trainingData, indexMapLoaders)
.superMap { (featureShardId, shardStats) =>
val outputDir = summarizationOutputDir + "/" + featureShardId
val indexMap = indexMapLoaders(featureShardId).indexMapForDriver()
IOUtils.writeBasicStatistics(sc, shardStats, outputDir, indexMap)
}
Once I have calculated the statistics for each shard, I want to append the side effect of saving them to disk, and then just return those statistics, without having to create a val and having that val's name be the last statement in the function, e.g.:
val stats = calculateStatistics(trainingData, indexMapLoaders)
stats.foreach { (featureShardId, shardStats) =>
val outputDir = summarizationOutputDir + "/" + featureShardId
val indexMap = indexMapLoaders(featureShardId).indexMapForDriver()
IOUtils.writeBasicStatistics(sc, shardStats, outputDir, indexMap)
}
stats
It's probably not very hard to implement, but I was wondering if there was something in Scala already for that.
Function cannot be effectful by definition, so I wouldn't expect anything convenient in scala-lib. However, you can write a wrapper:
def tap[T](effect: T => Unit)(x: T) = {
effect(x)
x
}
Example:
scala> Map(1 -> 1, 2 -> 2)
.map(tap(el => el._1 + 5 -> el._2))
.foreach(println)
(1,1)
(2,2)
You can also define an implicit:
implicit class TapMap[K,V](m: Map[K,V]){
def tap(effect: ((K,V)) => Unit): Map[K,V] = m.map{x =>
effect(x)
x
}
}
Examples:
scala> Map(1 -> 1, 2 -> 2).tap(el => el._1 + 5 -> el._2).foreach(println)
(1,1)
(2,2)
To abstract more, you can define this implicit on TraversableOnce, so it would be applicable to List, Set and so on if you need it:
implicit class TapTraversable[Coll[_], T](m: Coll[T])(implicit ev: Coll[T] <:< TraversableOnce[T]){
def tap(effect: T => Unit): Coll[T] = {
ev(m).foreach(effect)
m
}
}
scala> List(1,2,3).tap(println).map(_ + 1)
1
2
3
res24: List[Int] = List(2, 3, 4)
scala> Map(1 -> 1).tap(println).toMap //`toMap` is needed here for same reasons as it needed when you do `.map(f).toMap`
(1,1)
res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1)
scala> Set(1).tap(println)
1
res6: scala.collection.immutable.Set[Int] = Set(1)
It's more useful, but requires some "mamba-jumbo" with types, as Coll[_] <: TraversableOnce[_] doesn't work (Scala 2.12.1), so I had to use an evidence for that.
You can also try CanBuildFrom approach: How to enrich a TraversableOnce with my own generic map?
Overall recommendation about dealing with passthrough side-effects on iterators is to use Streams (scalaz/fs2/monix) and Task, so they've got an observe (or some analog of it) function that does what you want in async (if needed) way.
My answer before you provided example of what you want
You can represent effectful computation without side-effects and have distinct values that represent state before and after:
scala> val withoutSideEffect = Map(1 -> 1, 2 -> 2)
withoutSideEffect: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)
scala> val withSideEffect = withoutSideEffect.map(el => el._1 + 5 -> (el._2 + 5))
withSideEffect: scala.collection.immutable.Map[Int,Int] = Map(6 -> 6, 7 -> 7)
scala> withoutSideEffect //unchanged
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)
scala> withSideEffect //changed
res1: scala.collection.immutable.Map[Int,Int] = Map(6 -> 6, 7 -> 7)
Looks like the concept you're after is similar to the Unix tee
utility--take an input and direct it to two different outputs. (tee
gets its name from the shape of the letter 'T', which looks like a
pipeline from left to right with another line branching off downwards.)
Here's the Scala version:
package object mypackage {
implicit class Tee[A](a: A) extends AnyVal {
def tee(f: A => Unit): A = { f(a); a }
}
}
With that, we can do:
calculateStatistics(trainingData, indexMapLoaders) tee { stats =>
stats foreach { case (featureShardId, shardStats) =>
val outputDir = summarizationOutputDir + "/" + featureShardId
val indexMap = indexMapLoaders(featureShardId).indexMapForDriver()
IOUtils.writeBasicStatistics(sc, shardStats, outputDir, indexMap)
}
}
Note that as defined, Tee is very generic--it can do an effectful
operation on any value and then return the original passed-in value.
Call foreach on your Map with your effectfull function. You original Map will not be changed as Maps in scala are immutable.
val myMap = Map(1 -> 1)
myMap.foreach(effectfullFn)
If you are trying to chain this operation, you can use map
myMap.map(el => {
effectfullFn(el)
el
})

How to turn a list of objects into a map of two fields in Scala

I'm having a real brain fart here. I'm working with the Play Framework. I have a method which takes a map and turns it into a HTML select element. I had a one-liner to take a list of objects and convert it into a map of two of the object's fields, id and name. However, I'm a Java programmer and my Scala is weak, and I've only gone and forgotten the syntax of how I did it.
I had something like
organizations.all.map {org => /* org.prop1, org.prop2 */ }
Can anyone complete the commented part?
I would suggest:
map { org => (org.id, org.name) } toMap
e.g.
scala> case class T(val a : Int, val b : String)
defined class T
scala> List(T(1, "A"), T(2, "B"))
res0: List[T] = List(T(1,A), T(2,B))
scala> res0.map(t => (t.a, t.b))
res1: List[(Int, String)] = List((1,A), (2,B))
scala> res0.map(t => (t.a, t.b)).toMap
res2: scala.collection.immutable.Map[Int,String] = Map(1 -> A, 2 -> B)
You could also take an intermediary List out of the equation and go straight to the Map like this:
case class Org(prop1:String, prop2:Int)
val list = List(Org("foo", 1), Org("bar", 2))
val map:Map[String,Int] = list.map(org => (org.prop1, org.prop2))(collection.breakOut)
Using collection.breakOut as the implicit CanBuildFrom allows you to basically skip a step in the process of getting a Map from a List.

Should x._1,x._2... syntax be avoided?

I'm just starting out in Scala. I find myself using tuple variables a lot.
For example, here's some code I wrote:
/* Count each letter of a string and return in a list sorted by character
* countLetter("test") = List(('e',1),('s',1),('t',2))
*/
def countLetters(s: String): List[(Char, Int)] = {
val charsListMap = s.toList.groupBy((c:Char) => c)
charsListMap.map(x => (x._1, x._2.length)).toList.sortBy(_._1)
}
Is this tuple syntax (x._1, x._2 etc) frowned upon by Scala developers?
Are the tuple accessors frowned upon by Scala developers?
Short answer: no.
Slightly longer (by one character) answer: yes.
Too many _n's can be a code smell, and in your case the following is much clearer, in my opinion:
def countLetters(s: String): List[(Char, Int)] =
s.groupBy(identity).mapValues(_.length).toList.sortBy(_._1)
There are lots of methods like mapValues that are specifically designed to cut down on the need for the noisy tuple accessors, so if you find yourself writing _1, etc., a lot, that probably means you're missing some nice library methods. But occasionally they're the cleanest way to write something (e.g., the final _1 in my rewrite).
One other thing to note is that excessive use of tuple accessors should be treated as a nudge toward promoting your tuples to case classes. Consider the following:
val name = ("Travis", "Brown")
println("Hello, " + name._1)
As opposed to:
case class Name(first: String, last: String)
val name = Name("Travis", "Brown")
println("Hello, " + name.first)
The extra case class definition in the second version buys a lot of readability for a single line of code.
There is a better solution then x._N. Common way to work with tuples is pattern matching:
charsListMap.map{case (a, b) => (a, b.length)}
You also may take a look at scalaz, there are some instruments for tuples:
import scalaz._
import Scalaz._
scala> (1, "a") bimap (_ + 2, _ + 2)
res0: (Int, java.lang.String) = (3,a2)
scala> ('s, "abc") :-> { _.length }
res1: (Symbol, Int) = ('s,3)
Starting in Scala 3, with the parameter untupling feature, the following will become an alternative for .map(x => x._1 -> x._2.length):
.map(_ -> _.length)
and thus, your example becomes:
"test".toList.groupBy(identity).map(_ -> _.length).toList.sortBy(identity)
// List(("e", 1), ("s", 1), ("t", 2))
Concerning your example more specifically and starting in Scala 2.13, you could also use groupMapReduce which (as its name suggests) is an equivalent of a groupBy followed by mapValues and a reduce step:
"test".groupMapReduce(identity)(_ => 1)(_ + _).toList.sortBy(identity)

Understanding how to return list.reduceLeft

I have the following method where I want to return a map by performing a reduceLeft on a list. My issue is that occasionally the list is empty so Im not sure the correct way to deal with that:
def results(start: String, end: String) = {
val iter = new QueryIterator(RK, start, end);
val list = for (hcol <- iter) yield (Map(hcol.getValue() ->
Map(hcol.getName()) -> hcol.getTime()))))
list.reduceLeft(_ ++ _)
}
When the list is empty it throws an exception that stops the execution. What is the best way to get around this problem?
You can use foldLeft instead and start with an empty map of the type that you want to return, e.g.
list.foldLeft(Map.empty[Int,(String,Float)])(_ ++ _)
(Make sure you properly match the type of the map; I'm guessing that getValue() returns an Int, etc..)
If that's confusing you could do it imperative stylee (but don't tell anyone I told you)
var m = Map[Int,(String,Float)]()
new QueryIterator(RK, start, end) foreach { hcol =>
m += Map(hcol.getValue -> Map(hcol.getName -> hcol.getTime))
}
m
You can use .sum method from Scalaz.
import scalaz._
import Scalaz._
scala> List(Map(1 -> 2, 3 -> 4), Map(4 -> 11)).asMA.sum
res21: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4, 4 -> 11)
scala> (Nil : List[Map[Int, Int]]).asMA.sum
res22: Map[Int,Int] = Map()