For the following map signature, am I reading it correctly?
object OptionImpl extends Option {
def map[B](f: A => B): Option[B]
}
source - FP in Scala
[B] means only objects of type B can call this function
f: A => B means that it accepts 1 argument, a function, that returns the same type B
I'm fuzzy on a concrete example of this function.
B is just a wildcard (i.e. generic). It just says that these two types are the same:
def map[B](f: A => B): Option[B]
^ ^
That is, it says: if you pass me a function that converts As to Bs, I will give you back an Option that may contain a B (where B can be any type).
This is a very useful link http://blog.tmorris.net/posts/scalaoption-cheat-sheet/ on usage of Option.
If you have scenario like this
option match {
case None => None
case Some(x) => Some(foo(x))
}
use
option.map(foo(_))
Another example
def processBody(contentType: String): String = {
.....
}
val body: Option[String] =
headers.get("Content-Type").map(processBody(_))
I assumed here that headers.get returns an Option.
Related
Since Scala 2.12 (or is it 2.13, can't be sure), the compiler can infer latent type arguments across multiple methods:
def commutative[
A,
B
]: ((A, B) => (B, A)) = {???} // implementing omitted
val a = (1 -> "a")
val b = commutative.apply(a)
The last line successfully inferred A = Int, B = String, unfortunately, this requires an instance a: (Int, String) to be given.
Now I'd like to twist this API for a bit and define the following function:
def findApplicable[T](fn: Any => Any)
Such that findApplicable[(Int, String)](commutative) automatically generate the correct function specialised for A = Int, B = String. Is there a way to do it within the language's capability? Or I'll have to upgrade to scala 3 to do this?
UPDATE 1 it should be noted that the output of commutative can be any type, not necessarily a Function2, e.g. I've tried the following definition:
trait SummonedFn[-I, +O] extends (I => O) {
final def summon[II <: I]: this.type = this
}
Then redefine commutative to use it:
def commutative[
A,
B
]: SummonedFn[(A, B), (B, A)] = {???} // implementing omitted
val b = commutative.summon[(Int, String)]
Oops, this doesn't work, type parameters don't get equal treatment like value parameters
If at some point some call-site knows the types of arguments (they aren't actually Any => Any) it is doable using type classes:
trait Commutative[In, Out] {
def swap(in: In): Out
}
object Commutative {
def swap[In, Out](in: In)(implicit c: Commutative[In, Out]): Out =
c.swap(in)
implicit def tuple2[A, B]: Commutative[(A, B), (B, A)] =
in => in.swap
}
At call site:
def use[In, Out](ins: List[In])(implicit c: Commutative[In, Out]): List[Out] =
ins.map(Commutative.swap(_))
However, this way you have to pass both In as well as Out as type parameters. If there are multiple possible Outs for a single In type, then there is not much you can do.
But if you want to have Input type => Output type implication, you can use dependent types:
trait Commutative[In] {
type Out
def swap(in: In): Out
}
object Commutative {
// help us transform dependent types back into generics
type Aux[In, Out0] = Commutative[In] { type Out = Out0 }
def swap[In](in: In)(implicit c: Commutative[In]): c.Out =
c.swap(in)
implicit def tuple2[A, B]: Commutative.Aux[(A, B), (B, A)] =
in => in.swap
}
Call site:
// This code is similar to the original code, but when the compiler
// will be looking for In it will automatically figure Out.
def use[In, Out](ins: List[In])(implicit c: Commutative.Aux[In, Out]): List[Out] =
ins.map(Commutative.swap(_))
// Alternatively, without Aux pattern:
def use2[In](ins: List[In])(implicit c: Commutative[In]): List[c.Out] =
ins.map(Commutative.swap(_))
def printMapped(list: List[(Int, String)]): Unit =
println(list)
// The call site that knows the input and provides implicit
// will also know the exact Out type.
printMapped(use(List("a" -> 1, "b" -> 2)))
printMapped(use2(List("a" -> 1, "b" -> 2)))
That's how you can solve the issue when you know the exact input type. If you don't know it... then you cannot use compiler (neither in Scala 2 nor in Scala 3) to generate this behavior as you have to implement this functionality using some runtime reflection, e.g. checking types using isInstanceOf, casting to some assumed types and then running predefined behavior etc.
I'm not sure I understand the question 100%, but it seems like you want to do some kind of advanced partial type application. Usually you can achieve such an API by introducing an intermediary class. And to preserve as much type information as possible you can use a method with a dependent return type.
class FindApplicablePartial[A] {
def apply[B](fn: A => B): fn.type = fn
}
def findApplicable[A] = new FindApplicablePartial[A]
scala> def result = findApplicable[(Int, String)](commutative)
def result: SummonedFn[(Int, String),(String, Int)]
And actually in this case since findApplicable itself doesn't care about type B (i.e. B doesn't have a context bound or other uses), you don't even need the intermediary class, but can use a wildcard/existential type instead:
def findApplicable[A](fn: A => _): fn.type = fn
This works just as well.
In Option we have
def getOrElse[B >: A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def orElse[B >: A](obj: => Option[B]): Option[B] = this match {
case None => obj
case _ => this
}
In Either we have:
def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B]
I understand what is going and why, a rather extended example could be this
OrElse( { Option[B]}).map{....} If B is such that A :> B, then if
Some(a) you get Some(a).map(f:B => ???) then Kaboom
generally speaking i think i am ok with variance. What i did not see or figure out because that is not what the simple example of co-variance and contravariance explain as use cases, and would like to confirm here:
The return type of a function as parameter is checked for variance position of the outer container.
Typically the example would be
Container[+A] {
def outerfunction[B](value: A): B
}
We are then explained, can't do, contra-variance position for A. I will not re-do to full explanation as to why. Let's assume we all understand it.
What is not usually explained is:
Container[+A] {
def outerfunction(f: ??? => A): A
}
It is not just taking a parameter of type A, but also taking any function parameter that return that A. The compiler goes at length to check that too. I wonder if it stops here, or if it is anything that can produce an A, as parameter to a function of the Container.
Your understanding is completely correct. To be honest, I am not sure what exactly is the question, but I will assume it's - which places does compiler check in a case such as:
trait Container[+A] {
def outerfunction(f: String => A): A
}
And the answer is - all of them.
So when compiler sees trait Container[+A], it will check the body of that Container for all occurrences of A, to see if they are in:
parameter position (which brings the contravariant requirement)
return type position (covariant requirement)
both (invariant requirement)
neither (so-called phantom variance).
In case of Container[+A], it will require that all occurrences of A are in covariant position, meaning that it will have a problem with String => A.
It's as simple as that. Doesn't matter if it's an "inner function" or an "outer function".
I have following code snippet:
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def orElse[B>:A](ob: => Option[B]): Option[B] =
this.map(Some(_)).getOrElse(ob)
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
The function orElse has a argument ob of type Option[B]. In the function body, I pass ob to the function getOrElse but it expects a type of B, how it is possible?
Because B can be any type?
Type A is identified once at the top. Type B, on the other hand, is being identified/defined separately at each method.
So if orElse receives an Option[B] for some unknown type B and passes it to getOrElse then, as far as getOrElse is concerned, that becomes the new B.
This might make a little more sense if you had used C instead of B for the getOrElse method, and used D instead of B for the orElse method. Everything would work the same but it'd be easier to see the non-relationships.
It's analogous to value parameters. If we have a method f(x:Int) = g(x-1) the received parameter is called x. The method g(x: Int)=... also calls its parameter x but that doesn't mean the values are the same.
When I write a function like def foo[A,B], what exactly does the [A,B] mean? I know it's a Polymorphic Method; but when do you use foo [A] versus foo [A,B]?
Here's an example where I don't understand the difference. This function compiles:
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
Whereas this one doesn't compile. I don't understand why the A isn't required, after all A is referenced by the f: A => B:
def map[A,B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
[error] ..../Stream.scala:61: type mismatch;
[error] found : h.type (with underlying type A)
[error] required: A
[error] foldRight(empty[B])((h,t) => cons(f(h), t))
(this is from one of the FP in Scala exercises)
Addendum
After reading the answers I'm adding some context, to help future readers. The function is defined inside a trait:
trait Stream[+A] {
...
def map[B](f: A => B):Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
...
}
So the error was being caused by type shadowing, but see #acjay's excellent answer below.
Googling scala type shadowing doesn't result in a direct definition in any of the scala docs, which is interesting because as #travisbrown says below, it's "one of the most common sources of beginner confusion I've seen". There is a discussion here: Why does Scala support shadow variables?
In the first example, there's only one type parameter because that's not a function in isolation, it's a method in class Stream[A], which declares the first type parameter. Approximately like so:
class Stream[A] {
// ...
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
So you get the A from the surrounding class scope. Suppose instead that you made map a method on the companion object instead. In this case, the companion object has no type parameter, so you have to define both parameters on the method:
class Stream[A] {
// ... methods, with foldRight, but no `map`
}
object Stream {
// ...
def map[A, B](stream: Stream[A])(f: A => B): Stream[B] =
stream.foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
This second option would be used slightly differently. You would say Stream.map(myStream)(myMappingFunction) instead of myStream.map(myMappingFunction). Both options are perfectly valid, but it's probably more idiomatic to put the method in the class.
So, to answer your question, you use multiple type parameters on a method when two or more of the arguments and/or return type need to be generic. You might also use two type parameters for classes as well, like (disregarding variance):
Type Map[A, B] - A is the key type and B is the value type
Type Tuple2[A, B] (better known as (A, B)) - A is the type of the 1st element, B is the type of the 2nd element
Type Function1[A, B] (better known as A => B) - A is the argument type, B is the return type
...and so on.
Is there any quick way to use as a concrete function (of type, say, (A) => B) as a PartialFunction[A, B]? The most concise syntax I know of is:
(a: A) => a match { case obj => func(obj) }
Is there an implicit conversion anywhere, something like:
implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] {
def isDefinedAt(a: A) = true
def apply(a: A) = func(a)
}
I guess I just wrote what I was looking for, but does this already exist in the Scala libraries?
Doing this with an implicit conversion is dangerous, for the same reason that (A) => B should not inherit from PartialFunction[A, B]. That is, the contract of PartialFunction guarantees that you can safely* call apply wherever isDefinedAt returns true. Function1's contract provides no such guarantee.
Your implicit conversion will result in a PartialFunction that violates its contract if you apply it to a function that is not defined everywhere. Instead, use a pimp to make the conversion explicit:
implicit def funcAsPartial[A, B](f: A => B) = new {
/** only use if `f` is defined everywhere */
def asPartial(): PartialFunction[A, B] = {
case a => f(a)
}
def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = {
case a if isDefinedAt(a) => f(a)
}
}
// now you can write
val f = (i: Int) => i * i
val p = f.asPartial // defined on all integers
val p2 = f.asPartial(_ > 0) // defined only on positive integers
* As discussed in the comments, it may not be entirely clear what "safety" means here. The way I think about it is that a PartialFunction explicitly declares its domain in the following precise sense: if isDefinedAt returns true for a value x, then apply(x) can be evaluated in a way that is consistent with the intent of the function's author. That does not imply that apply(x) will not throw an exception, but merely that the exception was part of the design of the function (and should be documented).
No, I tried to find one a few months ago and ended up writing my own that's essentially the same as yours.