Use method with default parameter in map - scala

I want to map a stream of Doubles to a method which takes two parameters, one of them has a default value. I want to use the default parameter so my method has only 1 parameter which I need to pass:
def pow(x:Double, exponent:Double=2.0) = {
math.pow(x,exponent)
}
I've found out that the following works, but I do not understand why:
val res = (1 to 100).map(_.toDouble).map(pow(_))
I'm especially confused because the following does not work (compiler error because of missing type information):
val pow2 = pow(_)
val res = pow2(2.0)
println(res) // expect 4.0

The compiler is not able to infer the type that you will provide to pow2. In the res mapping you explicitly feed it a collection of Doublesand therefore pow(_) does not complain. However, in the case of val pow2 = pow(_) it complains that type parameter is missing. Change it to
val pow2 = pow(_: Double)
val res = pow2(2.0)
println(res)
and it will work just fine. pow(_) will be expanded two x => pow(x) and at this point the compiler cannot infere what's x without the type annotation.

Related

Scala named argument: recursive call

Very strange situation.
I have the following code snippet:
case class SomeResponse(
ok: Boolean,
result: Seq[Data]
)
class TestContainer {
def testMethod() = {
val response = SomeResponse(
// vvv - issue is here
ok = true, Seq(getStubData)
// ^^^
)
val result = Json.toJson(response)
}
def getStubData = Data(10, "James")
}
When I am not specifying parameter name, everything compiles and works as expected.
But when I explicitly set parameter name
val response = SomeResponse(
// vvv - issue is here
ok = true, result = Seq(getStubData)
// ^^^
compiler complies with the following message:
Error:(63, 30) recursive value response needs type
val result = Json.toJson(response)
Is there any specific compiler behavior for named arguments?
This is the result of the interaction between a semi-solved issue in scala and another one in sbt:
scala/bug#5091
sbt/sbt#1928
Judging by the comments there and in linked issues, during type inference the compiler treats all x = y statements in the same way, leading to a cycle when trying to infer result above.
Workarounds:
provide the explicit type of result or even response above; anything that will break the type inference cycle will do
rename val result

Error in lifting method to function

I have a method that with the implicit parameter. i get a error when i convert it to function in 2 case :
1:
def action(implicit i:Int) = i + " in action"
val f = action _
then i get a StackOverflowError.
2:
def action(implicit i:Int) = i + " in action"
val f = action(_)
then i get a error: missing parameter type
I must write like this :
val f = (i:Int) => action(i)
that's ok. And if the parameter of 'action' is not the implicit , all case are right. So how to explain , and what i miss ?
If you specify a parameter to a function to be implicit, you are inviting the compiler to supply the value of that parameter for you. So how does the compiler find those values? It looks for values of the same type (Int in your case) that have been declared as implicit values in a variety of scopes.
(For simplicity, I'll just use a local scope in this example, but you might want to read up on this topic. Programming in Scala, 3rd Ed is a good first step.)
Note that the names of the implicit values are ignored and have no bearing on proceedings, the compiler only looks at the types of implicit values. If multiple implicit values with the required type are found in the same scope, then the compiler will complain about ambiguous implicit values.
For example, the following provides a function with an implicit parameter and a default value for that parameter within the current scope:
def greetPerson(name: String)(implicit greeting: String) = s"$greeting $name!"
implicit val defaultGreeting = "Hello" // Implicit value to be used for greeting argument.
val y = greetPerson("Bob") // Equivalent to greetPerson("Bob")(defaultGreeting).
val z = greetPerson("Fred")("Hi")
Note that y is just a String value of "Hello Bob!", and z is a string with the value "Hi Fred!"; neither of them are functions.
Also note that greetPerson is a curried function. This is because implicit parameters cannot be mixed with regular, non-implicit parameters in the same parameter list.
In general, it's bad practice to use common types (Int, Boolean, String, etc.) as values for implicit parameters. In a big program, there might be a lot of different implicit values in your scope, and you might pick up an unexpected value. For that reason, it's standard practice to wrap such values in a case class instead.
If you're trying to create a value that supplies some of the arguments of another function (that is, a partially applied function), then that would look something like this:
def greetPerson(greeting: String, name: String) = s"$greeting $name!"
val sayHello = greetPerson("Hello", _: String)
val y = sayHello("Bob") // "Hello Bob!"
val sayHi = greetPerson("Hi", _: String)
val z = sayHi("Fred") // "Hi Fred!"
In both cases, we're creating partially applied functions (sayHi and sayHello) that call greetPerson with the greeting parameter specified, but which allow us to specify the name parameter. Both sayHello and sayHi are still only values, but their values are partially applied functions rather than constants.
Depending upon your circumstances, I think the latter case may suit you better...
I would also read up on how the underscore character (_) is used in Scala. In a partially applied function declaration, it corresponds to the arguments that will be provided later. But it has a lot of other uses too. I think there's no alternative to reading up on Scala and learning how and when to use them.

Scala wrongly pointing a double definition

In Scala, I'm trying to define two functions of the following type
def to(sinks: Sink[RequestModel, NotUsed]*): VyasaGraph = {
val current = sinks.toList
connect(previous, current)
previous = current
this
}
def to(functions: Function1[RequestModel, Unit]*): VyasaGraph = {
val current = (for (func <- functions) yield Sink.foreach[RequestModel](func)).toList
connect(previous, current)
previous = current
this
}
Why is sbt producing a double definition error
So the reason why it is throwing a double definition error is because, varargs are passed as Seq[T]. Since generic types are erased at compile time, both the functions would be equivalent.
You already found the reason, but the standard workaround is to add an always-available implicit parameter to one of the methods, and that's what DummyImplicit in Predef is for:
def to(functions: Function1[RequestModel, Unit]*)(implicit d: DummyImplicit) = ...
If you need to distinguish more than two functions, you can have multiple DummyImplicit parameters or define your own extra types:
class DummyImplicit2
object DummyImplicit2 {
implicit def d: DummyImplicit2 = null // to avoid creating garbage
}
...

Using fold on Option without having x => x

Given:
val personsOpt:Option[List[Person]] = ???
I prefer:
persons = personsOpt.fold(List[Person]()){person => person}
To this:
persons = personsOpt.getOrElse(List[Person]())
For type safety reasons. For example this does not compile:
persons = personsOpt.fold(Nil){person => person}
Is there a simple way to get the type safety but not have {person => person}?
EDIT: Two things now concretely understood:
There is nothing un-type-safe about getOrElse. For instance this does not compile: personsOpt.getOrElse("")
Nil is List() and if its type can't be inferred the compiler will ask you to be explicit. So there can be no type issues with using Nil
I couldn't find the link just now, but I did (incorrectly) read that getOrElse was somehow less type safe than using fold with an Option.
There is the function identity which is defined in Predef:
persons = personsOpt.fold(List[Person]())(identity)
I find this however a lot less readable than using getOrElse, and using this does not make your code more type-safe than using getOrElse. Note that passing Nil to getOrElse will make it return the correct type:
scala> case class Person(name: String)
scala> val personsOpt:Option[List[Person]] = None
personsOpt: Option[List[Person]] = None
scala> val persons = personsOpt.getOrElse(Nil)
persons: List[Person] = List()
Note that persons is a List[Person].

Scala - diverging implicit expansion when using toMap

I have the following definition of an enum:
object GraphType extends Enumeration {
type Type = Value
val MESSAGE, REQUEST, ERRORS = Value
}
Now I am trying to map each of the type to the corresponding, new TimeSeries as follows:
val dataSets = ( GraphType.values map (graphType => graphType -> new TimeSeries(graphType)) ).toMap
the type system lists datasets as Map[GraphType.Value, TimeSeries] which is precisely what I want. However, compilation fails with error message:
error: diverging implicit expansion for type scala.collection.generic.CanBuildFrom[ird.replay.gui.GraphType.ValueSet,(ird.replay.gui.GraphType.Value, org.jfree.data.time.TimeSeries),That]
starting with method newCanBuildFrom in object SortedSet
val dataSets = GraphType.values map (graphType => graphType -> new TimeSeries(graphType)) toMap
COuld anyone provide some explanation for this, rather cryptic, error message? Thanks
Try converting the Set of values for the enum to a List first like so:
val dataSets = (GraphType.values.toList.map(gt => (gt, new TimeSeries(gt)))).toMap
Something about that being a Set did not agree with how you were attempting to convert it to a Map, but it seems to work just fine with a List