The Option class has a method named fold(). The docs say:
sealed abstract class Option[+A]
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
Returns the result of applying f to this scala.Option's value if the scala.Option is nonempty. Otherwise, evaluates expression ifEmpty.
The docs continue:
This is equivalent to scala.Option map f getOrElse ifEmpty.
But is this really true? I've been told that under certain circumstances, with values of certain types, there are differences, but never with a decent explanation. What exactly are the situations where these two constructions will behave differently and why?
Option.fold is safer than .getOrElse. You can see the definition for .fold below, where both ifEmpty and f are of type B (introduced only after scala 2.10, probably):
#inline final def fold[B](ifEmpty: => B)(f: A => B): B =
if (isEmpty) ifEmpty else f(this.get)
which means you will probably not mess up the data types (exception below):
scala> val data = Option("massive data").fold(-1) { _ => 1 }
data: Int = 1
// but if I try to return different type in either of ifEmpty or f
// compiler will curse me right at my face
scala> val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
<console>:17: error: type mismatch;
found : String("Let me get caught by compiler")
required: Int
val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
^
While getOrElse is not as safe, unless you provide the type (supertype B in following definition) manually.
#inline final def getOrElse[B >: A](default: => B): B =
if (isEmpty) default else this.get
which means you can return a different type from getOrElse than what the original value wrapped in Option[A] was.
scala> val data = Option("massive data").map(_ => 1).getOrElse(List("I'm not integer"))
data: Any = 1
// you have to manually mention the type to getOrElse to restrict,
// which is not that smart in my opinion
scala> val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
<console>:17: error: type mismatch;
found : List[String]
required: Int
val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
^
The interesting thing is you can return unit from getOrElse or fold which can introduce bugs in an application unless you catch it in unit tests.
scala> val data = Option("massive data").fold() { _ => 1 }
data: Unit = ()
scala> val data = Option("massive data").map(_ => 1).getOrElse()
data: AnyVal = 1
As a counterpoint to #prayagupd's answer, fold often invites you to mess up types in a specific way.
The problem is that by Scala's rules, only ifEmpty is used to infer B and then f is checked to be suitable. Which means that using None or Nil as ifEmpty, which is quite common, will lead to their singleton types being used as B instead of Option/List[SomeType], no matter what f returns.
Of course, there are workarounds: specify B explicitly, use Option.empty[SomeType] or None: Option[SomeType] instead of None. Or just use pattern-matching.
Related
I have a function in a context, (in a Maybe / Option) and I want to pass it a value and get back the return value, directly out of the context.
Let's take an example in Scala :
scala> Some((x:Int) => x * x)
res0: Some[Int => Int] = Some(<function1>)
Of course, I can do
res0.map(_(5))
to execute the function, but the result is wrapped in the context.
Ok, I could do :
res0.map(_(5)).getOrElse(...)
but I'm copy/pasting this everywhere in my code (I have a lot of functions wrapped in Option, or worst, in Either...).
I need a better form, something like :
res0.applyOrElse(5, ...)
Does this concept of 'applying a function in a concept to a value and immediatly returning the result out of the context' exists in FP with a specific name (I'm lost in all those Functor, Monad and Applicatives...) ?
You can use andThen to move the default from the place where you call the function to the place where you define it:
val foo: String => Option[Int] = s => Some(s.size)
val bar: String => Int = foo.andThen(_.getOrElse(100))
This only works for Function1, but if you want a more generic version, Scalaz provides functor instances for FunctionN:
import scalaz._, Scalaz._
val foo: (String, Int) => Option[Int] = (s, i) => Some(s.size + i)
val bar: (String, Int) => Int = foo.map(_.getOrElse(100))
This also works for Function1—just replace andThen above with map.
More generally, as I mention above, this looks a little like unliftId on Kleisli, which takes a wrapped function A => F[B] and collapses the F using a comonad instance for F. If you wanted something that worked generically for Option, Either[E, ?], etc., you could write something similar that would take a Optional instance for F and a default value.
You could write something like applyOrElse using Option.fold.
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
val squared = Some((x:Int) => x * x)
squared.fold {
// or else = ifEmpty
math.pow(5, 2).toInt
}{
// execute function
_(5)
}
Using Travis Browns recent answer on another question, I was able to puzzle together the following applyOrElse function. It depends on Shapeless and you need to pass the arguments as an HList so it might not be exactly what you want.
def applyOrElse[F, I <: HList, O](
optionFun: Option[F],
input: I,
orElse: => O
)(implicit
ftp: FnToProduct.Aux[F, I => O]
): O = optionFun.fold(orElse)(f => ftp(f)(input))
Which can be used as :
val squared = Some((x:Int) => x * x)
applyOrElse(squared, 2 :: HNil, 10)
// res0: Int = 4
applyOrElse(None, 2 :: HNil, 10)
// res1: Int = 10
val concat = Some((a: String, b: String) => s"$a $b")
applyOrElse(concat, "hello" :: "world" :: HNil, "not" + "executed")
// res2: String = hello world
The getOrElse is most logical way to do it. In regards to copy/pasting it all over the place - you might not be dividing your logic up on the best way. Generally, you want to defer resolving your Options (or Futures/etc) in your code until the point you need to have it unwrapped. In this case, it seems more sensible that your function takes in an an Int and returns an Int, and you map your option where you need the result of that function.
I am trying to do several dependent Slick/DB calls and then display the resulting data within a twirl template.
def show(slug: String) = Action.async { implicit rs =>
for {
f <- fooDAO.findBySlug(slug) // f is of type Option[foo]
fid <- f.flatMap(a => a.id.map(b => b)) // fid is of type Long
b <- barDAO.findByFooId(fid) // b is of type Seq[bar]
} yield {
f.map {
case Some(f) => Ok(views.html.foobar(f, b))
case _ => NotFound
}
}
}
I first need to get the "ID" to then be able to query other relevant data. The compiler is now producing this error:
play.sbt.PlayExceptions$CompilationException: Compilation error[type mismatch;
found : scala.concurrent.Future[Option[play.api.mvc.Result]]
required: Option[?]]
Any help would be greatly appreciated.
There is a fundamental flaw in your code, in that you're mixing in the same comprehension an Option and a Seq
A for-comprehension is expected to work on the same "container" type, which will be the resulting representation of the yield
e.g. if you combine several Options you get an Option, if you combine Seqs you get a Seq.
In this case you can overcome the problem by converting the Option (foo) to a Seq (which will be empty if the foo is None and have 1 element if not).
The end result would be
val results: Seq[(Foo, Bar)] =
for {
f <- fooDAO.findBySlug(slug).toSeq // f is of type Seq[Foo]
b <- barDAO.findByFooId(f.id) // b is of type Seq[Bar]
} yield (f, b)
But I guess this is not what you need. I suppose you want to get all Bars associated with the retrieved Foo, if any, and present it with your template. If no Foo is present for the slug, you want a NotFound.
We can do it like this
def show(slug: String) = Action.async { implicit rs =>
val f = fooDAO.findBySlug(slug) // f is of type Option[Foo]
f.fold(
NotFound,
foo => Ok(views.html.foobar(foo, barDAO.findByFooId(foo.id))
)
}
You can make it more explicit by defining a supporting method
def show(slug: String) = Action.async { implicit rs =>
def barsOf(f: Foo): Seq[Bar] = barDAO.findByFooId(f.id)
val f = fooDAO.findBySlug(slug) // f is of type Option[Foo]
f.fold(
NotFound,
foo => Ok(views.html.foobar(foo, barsOf(foo))
)
}
It's a bit tricky understanding what you're trying to achieve here, but if the whole thing is predicated on the findbySlug returning a Future[Option[Foo]] and the eventual outcome being a NotFound if that Option is a None, then your yield should probably just be:
...
} yield {
f.fold(NotFound)(foo => Ok(views.html.foobar(foo, b)))
}
Option[T] is a fantastic type for data-retrieval and control-flow, but pattern-matching on it is almost never the right approach. The use of fold feels nicely succinct for the task.
Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:
def createLongStringFunction[T](): (T) => Boolean = {
(obj: T) => obj.toString.length > 7
}
but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:
// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7
Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?
This is a purely contrived and useless example. Of course I could just make the function use Any here.
No, type parameters only apply to methods and not function objects. For example,
def f[T](x: T) = x //> f: [T](x: T)T
val g = f _ //> g: Nothing => Nothing = <function1>
// g(2) // error
val h: Int=>Int = f _ //> h : Int => Int = <function2>
h(2) //> res0: Int = 2
The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.
As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.
As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:
trait ~>[A[_],B[_]] {
def apply[X](a : A[X]) : B[X]
}
type Id[A] = A //necessary hack
object newList extends (Id ~> List) {
def apply[X](a : Id[X]) = List(a)
}
def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))
tupleize(newList, 1, "Hello") // (List(1), List(Hello))
Since longStringFunction defined as followed is a value, which must have some given type.
val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7
However, you can reuse a function object with a method:
scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>
scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean
scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>
scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>
scala> f1 eq f2
res0: Boolean = true
This works because trait Function1[-T1, +R] is contravariant of type T1.
In scala, Function values are parametrically monomorphic(while methods are polymorphic)
Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.
Please consider the following refs:
http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/
http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/
Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.
I can use scalaz |> operator when I want to switch function and object so there can be a little more readability acquired. Let me introduce you a model function :def length2(x:String) = x.length * 2 Now, I can write it in both ways:"aoeu" |> length2
length2("aoeu")
But if I define this function more generic, it stops working.def length2(x:SeqLike[_,_]) = x.length * 2
length2("aoeu") // ok
"aoeu" |> length2 // doesn't work
Why the compiler doesn't understand this? There is definitely an implicit conversion from String to some class mixing in trait SeqLike.
scala> "aoeu" |> length2
<console>:14: error: type mismatch;
found : (scala.collection.SeqLike[_, _]) => Int
required: (java.lang.String) => ?
"aoeu" |> length2
The error message is pretty clear.
Although there is an implicit conversion from String to SeqLike[_,_], there is no conversion from (SeqLike[_, _]) => Int to String => ?.
This can be fixed using the following implicit conversion:
implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
def g(t:T) = f(t)
g _
}
Edit 2: here is a non-scalaz operator.
class Pipe[T](t:T) {
def |%>[X, U](f: (X) => U)(implicit ev: T <%< X) = f(t)
}
implicit def toPipe[T](t:T) = new Pipe(t:T)
Then you can use it like this:
def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2
"abc" |%> l1
"abc" |%> l2
It allows |%> to take a function that does not work directly on a T but on a X as long as there is evidence of an implicit conversion from T to X.
Do not use existential types unless necessary. They break things, and are not required here.
On the other hand, seeing in the error in the other answer made things more clear. You there are two implicit conversions being asked for when you use |>. Does it work if you declare it like this instead:
def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2