It's not the standard library, but it might be "standard enough": with Cats, you should be able to write something like
val content =
s3
.getObject(bucket, key)
.getObjectContent
.pure[Id].map(Source.fromInputStream)
.mkString
.toInt
where pure[Id] wraps the input value into the do-nothing Id
monad, and then passes it as argument to Source.fromInputStream
.
EDIT: This does not seem to work reliably. If the object already has a method map
, then this method is called instead of Id.map
.
Smaller example (just to demonstrate the necessary imports):
import cats.Id
import cats.syntax.applicative._
import cats.syntax.functor._
object Main {
def square(x: Int) = x * x
def main(args: Array[String]): Unit = {
println(42.pure[Id].map(square))
}
}
However, writing either
val content =
Source
.fromInputStream(
s3
.getObject(bucket, key)
.getObjectContent
)
.mkString
.toInt
or
val content =
Source
.fromInputStream(s3.getObject(bucket, key).getObjectContent)
.mkString
.toInt
does not require any extra dependencies, and frees you both from the burden of defining otherwise useless case classes, and also from the burden of reindenting your code every time you rename either content
or s3
.
It also shows how the expressions are actually nested, and what depends on what - there is a reason why the vast majority of mainstream programming languages of the past 50 years have a call-stack.