scala how to wrap this response to yield instead of val?
I have get method realization with vals, how can I refactor it with for yield structure
case Method.GET -> !! / "leagues" =>
val openDotaResponse: ZIO[Client, Throwable, Response] = Client.request("https://api.opendota.com/api/leagues")
val bodyOfResponse: ZIO[Client, Throwable, String] = openDotaResponse.flatMap(_.body.asString)
val eitherListOfLeagues: ZIO[Client, Throwable, Either[String, List[League]]] = bodyOfResponse.map(_.fromJson[List[League]])
val listOfLeagues: ZIO[Client, Throwable, List[League]] = eitherListOfLeagues.map(eitherList => eitherList.toOption.getOrElse(Nil))
val result: ZIO[Client, Throwable, Response] = listOfLeagues.map(listLeagues => Response.json(listLeagues.toJson))
result
case Method.GET -> !! / "4leagues" =>
// val response1: ZIO[Client, Throwable, Response] = for {
// openDotaResponse: ZIO[Client, Throwable, Response] <- Client.request("https://api.opendota.com/api/leagues")
// bodyOfResponse: ZIO[Client, Throwable, String] <- openDotaResponse.flatMap(_.body.asString)
// eitherListOfLeagues: ZIO[Client, Throwable, Either[String, List[League]]] <- bodyOfResponse.map(_.fromJson[List[League]])
// listOfLeagues: ZIO[Client, Throwable, List[League]] <- eitherListOfLeagues.map(eitherList => eitherList.getOrElse(Nil))
// result: ZIO[Client, Throwable, Response] <- listOfLeagues.map(listLeagues => Response.json(listLeagues.toJson)).map(_.body)
// val res1: Response = result.map(_.body)
// res1
// } yield res1
//response1
Try
for {
openDotaResponse <- Client.request("https://api.opendota.com/api/leagues")
bodyOfResponse <- openDotaResponse.body.asString
eitherListOfLeagues = bodyOfResponse.fromJson[List[League]]
listOfLeagues = eitherListOfLeagues.toOption.getOrElse(Nil)
result = Response.json(listOfLeagues.toJson)
} yield result
or just
for {
openDotaResponse <- Client.request("https://api.opendota.com/api/leagues")
bodyOfResponse <- openDotaResponse.body.asString
eitherListOfLeagues = bodyOfResponse.fromJson[List[League]]
listOfLeagues = eitherListOfLeagues.toOption.getOrElse(Nil)
} yield Response.json(listOfLeagues.toJson)
What is Scala's yield?
Related
The goal is to lazily evaluate a collection of functions stopping on and returning the first happy result. Computation should be sequential. Here is my attempt
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
val in = 42
(f1(in) #:: f2(in) #:: f3(in) #:: Stream.empty) collectFirst { case Right(x) => x } toRight("boom")
which outputs
f1(42)
f2(42)
f3(42)
res0: Either[String,Int] = Right(42)
where we see all three executed, whilst
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Right(i) }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Right(i) }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
would output
f1(42)
res0: Either[String,Int] = Right(42)
where we see only one executed.
Does cats provide abstraction for such lazy failure-biased traversal?
You can use the Ior data type which is an inclusive-or relationship between two data types.
import cats.data.Ior
import cats.implicits._
import scala.annotation.tailrec
object Main2 {
def main(args: Array[String]) : Unit = {
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
def traverseLazy(input: Int, list: List[Int => Either[String, Int]]): Ior[List[String], Int] = {
#tailrec
def go(ls: List[Int => Either[String, Int]], acc: List[String]): Ior[List[String], Int] = ls match {
case x :: xs => x(input) match {
case Left(error) => go(xs, error :: acc)
case Right(value) => if (ls.isEmpty) value.rightIor else Ior.both(acc, value)
}
case Nil => acc.leftIor
}
go(list, List.empty)
}
val res = traverseLazy(42, List(f1, f2, f3)).fold(
_.intercalate("\n"),
res => s"succeeded with $res",
(errors, res) => s"completed successfully with res $res but some errors were also found: ${errors.intercalate(", ")}")
println(res)
}
}
Ah I was overcomplicating, orElse already implements such semantics and gives simply
f1(in) orElse f2(in) orElse f3(in) orElse Left("boom")
as it takes by-name parameter.
def merge(bigrams1: Map[String, mutable.SortedMap[String, Int]],
bigrams2: Map[String, mutable.SortedMap[String, Int]]): Map[String, mutable.SortedMap[String, Int]] = {
bigrams2 ++ bigrams1
.map(entry1 => entry1._1 -> (entry1._2 ++ bigrams2.getOrElse(entry1._1, mutable.SortedMap())
.map(entry2 => entry2._1 -> (entry2._2 + entry1._2.getOrElse(entry2._1, 0)))))
}
At compile time, I get these errors:
Error:(64, 114) diverging implicit expansion for type scala.math.Ordering[T1]
starting with method Tuple9 in object Ordering
bigrams2 ++ bigrams1.map(entry1 => entry1._1 -> (entry1._2 ++ bigrams2.getOrElse(entry1._1, mutable.SortedMap()).map(entry2 => entry2._1 -> (entry2._2 + entry1._2.getOrElse(entry2._1, 0)))))
Error:(64, 114) not enough arguments for method apply: (implicit ord: scala.math.Ordering[A])scala.collection.mutable.SortedMap[A,B] in class SortedMapFactory.
Unspecified value parameter ord.
bigrams2 ++ bigrams1.map(entry1 => entry1._1 -> (entry1._2 ++ bigrams2.getOrElse(entry1._1, mutable.SortedMap()).map(entry2 => entry2._1 -> (entry2._2 + entry1._2.getOrElse(entry2._1, 0)))))
Specifying the types of the sorted map solves the problem:
def merge(bigrams1: Map[String, mutable.SortedMap[String, Int]],
bigrams2: Map[String, mutable.SortedMap[String, Int]]): Map[String, mutable.SortedMap[String, Int]] = {
bigrams2 ++ bigrams1
.map(entry1 => entry1._1 -> (entry1._2 ++ bigrams2.getOrElse(entry1._1, mutable.SortedMap[String, Int]())
.map(entry2 => entry2._1 -> (entry2._2 + entry1._2.getOrElse(entry2._1, 0)))))
}
Why do these type parameters need to be specified? Why can they not be inferred without problems with the implicit ordering?
Full code:
import java.io.File
import scala.annotation.tailrec
import scala.collection.mutable
import scala.io.Source
import scala.util.matching.Regex
case class Bigrams(bigrams: Map[String, mutable.SortedMap[String, Int]]) {
def mergeIn(bigramsIn: Map[String, mutable.SortedMap[String, Int]]): Bigrams = {
Bigrams(Bigrams.merge(bigrams, bigramsIn))
}
def extractStatistics(path: String): Bigrams = {
val entry: File = new File(path)
if (entry.exists && entry.isDirectory) {
val bigramsFromDir: Map[String, mutable.SortedMap[String, Int]] = entry
.listFiles
.filter(file => file.isFile && file.getName.endsWith(".sgm"))
.map(Bigrams.getBigramsFrom)
.foldLeft(Map[String, mutable.SortedMap[String, Int]]())(Bigrams.merge)
val bigramsFromSubDirs: Bigrams = entry
.listFiles
.filter(entry => entry.isDirectory)
.map(entry => extractStatistics(entry.getAbsolutePath))
.foldLeft(Bigrams())(Bigrams.merge)
bigramsFromSubDirs.mergeIn(bigramsFromDir)
} else if (entry.exists && entry.isFile) {
Bigrams(Bigrams.getBigramsFrom(entry))
} else
throw new RuntimeException("Incorrect path")
}
def getFreqs(word: String): Option[mutable.SortedMap[String, Int]] = {
bigrams.get(word)
}
}
object Bigrams {
def fromPath(path: String): Bigrams = {
new Bigrams(Map[String, mutable.SortedMap[String, Int]]()).extractStatistics(path)
}
def apply(): Bigrams = {
new Bigrams(Map())
}
val BODY: Regex = "(?s).*<BODY>(.*)</BODY>(?s).*".r
// Return a list with the markup for each article
#tailrec
def readArticles(remainingLines: List[String], acc: List[String]): List[String] = {
if (remainingLines.size == 1) acc
else {
val nextLine = remainingLines.head
if (nextLine.startsWith("<REUTERS ")) readArticles(remainingLines.tail, nextLine +: acc)
else readArticles(remainingLines.tail, (acc.head + "\n" + nextLine) +: acc.tail)
}
}
def merge(bigrams1: Map[String, mutable.SortedMap[String, Int]],
bigrams2: Map[String, mutable.SortedMap[String, Int]]): Map[String, mutable.SortedMap[String, Int]] = {
bigrams2 ++ bigrams1
.map(entry1 => entry1._1 -> (entry1._2 ++ bigrams2.getOrElse(entry1._1, mutable.SortedMap[String, Int]())
.map(entry2 => entry2._1 -> (entry2._2 + entry1._2.getOrElse(entry2._1, 0)))))
}
def merge(bigrams1: Bigrams, bigrams2: Bigrams): Bigrams = {
new Bigrams(merge(bigrams1.bigrams, bigrams2.bigrams))
}
def getBigramsFrom(path: File): Map[String, mutable.SortedMap[String, Int]] = {
val file = Source.fromFile(path)
val fileLines: List[String] = file.getLines().toList
val articles: List[String] = Bigrams.readArticles(fileLines.tail, List())
val bodies: List[String] = articles.map(extractBody).filter(body => !body.isEmpty)
val sentenceTokens: List[List[String]] = bodies.flatMap(getSentenceTokens)
sentenceTokens.foldLeft(Map[String, mutable.SortedMap[String, Int]]())((acc, tokens) => addBigramsFrom(tokens, acc))
}
def getBigrams(tokens: List[String]): List[(String, String)] = {
tokens.indices.
map(i => {
if (i < tokens.size - 1) (tokens(i), tokens(i + 1))
else null
})
.filter(_ != null).toList
}
// Return the body of the markup of one article
def extractBody(article: String): String = {
try {
val body: String = article match {
case Bigrams.BODY(bodyGroup) => bodyGroup
}
body
}
catch {
case _: MatchError => ""
}
}
def getSentenceTokens(text: String): List[List[String]] = {
val separatedBySpace: List[String] = text
.replace('\n', ' ')
.replaceAll(" +", " ") // regex
.split(" ")
.map(token => if (token.endsWith(",")) token.init.toString else token)
.toList
val splitAt: List[Int] = separatedBySpace.indices
.filter(i => i > 0 && separatedBySpace(i - 1).endsWith(".") || i == 0)
.toList
groupBySentenceTokens(separatedBySpace, splitAt, List()).map(sentenceTokens => sentenceTokens.init :+ sentenceTokens.last.substring(0, sentenceTokens.last.length - 1))
}
#tailrec
def groupBySentenceTokens(tokens: List[String], splitAt: List[Int], sentences: List[List[String]]): List[List[String]] = {
if (splitAt.size <= 1) {
if (splitAt.size == 1) {
sentences :+ tokens.slice(splitAt.head, tokens.size)
} else {
sentences
}
}
else groupBySentenceTokens(tokens, splitAt.tail, sentences :+ tokens.slice(splitAt.head, splitAt.tail.head))
}
def addBigramsFrom(tokens: List[String], bigrams: Map[String, mutable.SortedMap[String, Int]]): Map[String, mutable.SortedMap[String, Int]] = {
var newBigrams = bigrams
val bigramsFromTokens: List[(String, String)] = Bigrams.getBigrams(tokens)
bigramsFromTokens.foreach(bigram => { // TODO: This code uses side effects to get the job done. Try to remove them.
val currentFreqs: mutable.SortedMap[String, Int] = newBigrams.get(bigram._1)
.map((map: mutable.SortedMap[String, Int]) => map)
.getOrElse(mutable.SortedMap())
val incrementedWordFreq = currentFreqs.get(bigram._2)
.map(freq => freq + 1)
.getOrElse(1)
val newFreqs = currentFreqs + (bigram._2 -> incrementedWordFreq)
newBigrams = newBigrams - bigram._1 + (bigram._1 -> newFreqs)
})
newBigrams
}
}
The thing is that method Map#getOrElse in 2.13 (or MapLike#getOrElse in 2.12) has signature
def getOrElse[V1 >: V](key: K, default: => V1): V1
https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/Map.scala#L132-L135
https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/MapLike.scala#L129-L132
i.e. it expects not necessarily default of the same type as V in Map[K, +V] (or MapLike[K, +V, +This <: MapLike[K, V, This] with Map[K, V]]) but possibly of a supertype of V. In your case V is mutable.SortedMap[String, Int] and there are so many its supertypes (you can look at inheritance hierarchy yourself). mutable.SortedMap() can be of any type mutable.SortedMap[A, B] or their super types.
If you replace method getOrElse with having fixed V
implicit class MapOps[K, V](m: Map[K, V]) {
def getOrElse1(key: K, default: => V): V = m.get(key) match {
case Some(v) => v
case None => default
}
}
or in 2.12
implicit class MapOps[K, V, +This <: MapLike[K, V, This] with Map[K, V]](m: MapLike[K, V, This]) {
def getOrElse1(key: K, default: => V): V = m.get(key) match {
case Some(v) => v
case None => default
}
}
then in your code
... bigrams2.getOrElse1(entry1._1, mutable.SortedMap())
all types will be inferred and it will compile.
So sometimes types should be just specified explicitly when compiler asks.
Simplified code:
val one: Future[String] = Future("1")
val many: Future[List[String]] = Future({"1","2","3"})
for {
a <- one
b <- many
} yield {
doSomething(a,b) // Type mismatch, expected String, actual: List[String]
}
What I want to happen is to call for each couple of one/many and get a list of the outputs
{doSomething("1","1"),doSomething("1","2"),doSomething("1","3")}
Can I get this to work with for comprehensions even when one is a Future[String] and the other a Future[List[String]]?
Try
val one: Future[String] = Future("1")
val many: Future[List[String]] = Future(List("1","2","3"))
def doSomething(a: String, b: String) = ???
for {
a <- one
b <- many
} yield {
b.map(v => doSomething(a, v))
}
Alternatively we could use scalaz ListT transformer like so
import scalaz._
import ListT._
import scalaz.std.scalaFuture.futureInstance
val one: Future[String] = Future("1")
val many: Future[List[String]] = Future(List("1","2","3"))
def doSomething(a: String, b: String) = ???
for {
a <- listT(one.map(v => List(v)))
b <- listT(many)
} yield {
doSomething(a, b)
}
Is it possible to pattern match on function heads in scala?
For example, can I write something along the lines of:
def myFunction(a:: b:: xs): Int = ???
def myFunction(a:: xs): Int = ???
def myFunction(List.empty): Int = ???
You can use partial functions for this case. Example:
val myFunctionCase1: PartialFunction[List[Int], Int] = {
case a :: b :: xs => ???
}
val myFunctionCase2: PartialFunction[List[Int], Int] = {
case a :: xs => ???
}
val myFunctionCase3: PartialFunction[List[Int], Int] = {
case Nil => ???
}
// compose functions
val myFunction: List[Int] => Int =
myFunctionCase1 orElse myFunctionCase2 orElse myFunctionCase3
Usage examples:
myFunctionCase1(List(1,2,3)) // invoke
myFunctionCase1(List(1)) // throw MatchError
myFunctionCase2(List(1)) // invoke
...
myFunction(List(1,2,3))
myFunction(List(1))
myFunction(Nil)
...
I wrote my first data access object in slick 3.0. it works but I found a lot of repetitive code in my code
class Items(tag: Tag) extends Table[Item](tag, "ITEMS") {
def id = column[Long]("ITEMS_ID", O.PrimaryKey, O.AutoInc)
def name = column[String]("ITEMS_NAME")
def price = column[Double]("ITEMS_PRICE")
def * = (id, name, price) <> ((Item.apply _).tupled, Item.unapply _)
}
object Shop extends Shop{
val items = TableQuery[Items]
val db = Database.forConfig("h2mem1")
def create(name: String, price: Double) : Int = {
val action = items ++= Seq(Item(0, name, price))
val future1 = db.run(action)
val future2 = future1 map {result =>
result map {x => x}
}
Await.result(future2, Duration.Inf).getOrElse(0)
}
def list() : Seq[Item] = {
val action = items.result
val future = db.run(action)
val future2 = future map {result =>
result map {x => x}
}
Await.result(future2, Duration.Inf)
}
def get(id: Long) : Option[Item] = {
val query = items.filter(_.id === id).result
val future1 = db.run(query)
val future2 = future1 map {result =>
result.map {x => x}
}
Await.result(future2, Duration.Inf).headOption
}
def delete(id: Long) : Int = {
val query = items.filter(_.id === id).delete
val future1 = db.run(query)
val future2 = future1 map {result =>
result
}
Await.result(future2, Duration.Inf)
}
def update(item: Item) : Int = {
val query = items.filter(_.id === item.id).update(item)
val future1 = db.run(query)
val future2 = future1 map {result => result}
Await.result(future2, Duration.Inf)
}
def createItemsTable() : Boolean = {
if (!checkTable("ITEMS")) {
val action = items.schema.create
val future1 = db.run(action)
future1 map {x => x}
true
} else false
//Await.result(future2, Duration.Inf)
}
def checkTable(tableName: String) : Boolean = {
val action = MTable.getTables
val future1 = db.run(action)
val future2 = future1 map {result =>
result map {x => x.name.name}
}
val retVal = Await.result(future2, Duration.Inf)
retVal.exists(x => x == tableName)
}
}
this works, but i hate the fact that I am writing this piece of code again and again
val future1 = db.run(query)
val future2 = future1 map {result => result}
Await.result(future2, Duration.Inf)
and
val future1 = db.run(query)
val future2 = future1 map {result =>
result.map {x => x}
}
Await.result(future2, Duration.Inf)
I want to know if there is a generic and safe way of avoiding the repeated use of these lines in every function.
You can define a generic function like
def runAction[R, Q](action: DBIOAction[R, NoStream, Nothing])(f: R => Q): Q = {
val future1 = db.run(action)
val future2 = future1 map { r: R =>
f(r)
}
Await.result(future2, Duration.Inf)
}
and use it like
def create(name: String, price: Double): Int = {
val action = items ++= Seq(Item(0, name, price))
runAction(action)(_.map(x => x)).getOrElse(0)
}