I am pretty new to Scala/Functional programing ,and i am trying to figure out how to write a function that will return an function(not explicitly said that it will be function called getSometing) ,but only by set of parameters ,so basically i want to rewrite this
def plusTwo(nr : Int) : Int={
nr + 2
}
def getAlgorythm(algoName : String) = (plusTwo : Int)=>{
algoName match{
case "plusTwo" => plusTwo
}
}
To someting like this
def plusTwo(nr : Int) : Int={
nr + 2
}
def square(nr : Int) : Int{
nr * nr
}
def getAlgorythm(algoName : String) = (someFunctionThatTakesIntParam: Int)=>{
algoName match{
case "plusTwo" => plusTwo
case "square" => square
}
}
Is this non-explicit form of syntax somehow possible in Scala ? I think it should be some way, in some level this is like signing different implementations to common interface.
I am pointing here to posibility ,that if this is posible in Scala,it can be way to avoid awesome amount of reflection calls,specialy with Gui frameworks,while you are binding data.
I will rewrite your code in slightly cleaner style and add some fixes:
def plusTwo(nr : Int) : Int = nr + 2
def square(nr : Int) : Int = nr * nr
def getAlgorithm(algoName : String) =
algoName match{
case "plusTwo" => plusTwo _
case "square" => square _
}
Algorithm is spelled with i in English
The square method needs an = in its defintion
plusTwo and square are methods, not functions: this may be a bit confusing, but these are different constructions in Scala. Often Scala tries to blur this distinction, but unfortunately this is not one of these cases,
so, in the places we'd want to treat these methods as functions we need to postfix them with an _, which when used after a method call instructs the compiler to transform methods into functions.
To further clarify the distinction between methods and functions let's make another implementation:
val plusTwo: Int => Int = nr => nr + 2
val square = (nr: Int) => nr * nr
def getAlgorythm(algoName : String) =
algoName match{
case "plusTwo" => plusTwo
case "square" => square
}
Now, the two methods and not methods anymore, they are vals, both of type Int => Int, in other words, functions! No need to use _ this time.
Related
I have two kinds of definition of a three-parameter function as below:
val minus1: (Int, Int, Int) => Int = _ - _ - _
val minus2: (Int, Int, Int) => Int = (_ - _) - _
minus1 is fine, but minus2 is reported illegal, that confused me a lot
Following ComDubh's insturction, i write a new function like:
val minus3 : (Int, Int, Int)=>Int = ((_-_)-_)
why this was still wrong? Did that mean i shouldn't put any parenthese between the "_"s?
and i have a more complicated question like
val func4: Int=>Int = x => if (x>0) 1 else -1
val func5: Int=>Int = if (_>0) 1 else -1
func4 is good, but why i can't omit the parametr name "x" to rewrite the function as func5(the compiler regards the 1 or -1 as the return value and reports Int(1) doesn't fit Int=>Int). Thans for your time
You're creating an anonymous function. Scala has to know where the definition of the anonymous function starts and ends. Your use of parentheses in minus2 tells Scala that _ - _ is the complete function. The compiler isn't happy of course as you're missing an argument.
I have superficially read a couple of blog articles/Wikipedia about continuation-passing style. My high-level goal is to find a systematic technique to make any recursive function (or, if there are restrictions, being aware of them) tail-recursive. However, I have trouble articulating my thoughts and I'm not sure if what my attempts of it make any sense.
For the purpose of the example, I'll propose a simple problem. The goal is, given a sorted list of unique characters, to output all possible words made out of these characters in alphabetical order. For example, sol("op".toList, 3) should return ooo,oop,opo,opp,poo,pop,ppo,ppp.
My recursive solution is the following:
def sol(chars: List[Char], n: Int) = {
def recSol(n: Int): List[List[Char]] = (chars, n) match {
case (_ , 0) => List(Nil)
case (Nil, _) => Nil
case (_ , _) =>
val tail = recSol(n - 1)
chars.map(ch => tail.map(ch :: _)).fold(Nil)(_ ::: _)
}
recSol(n).map(_.mkString).mkString(",")
}
I did try to rewrite this by adding a function as a parameter but I did not manage to make something I was convinced to be tail-recursive. I prefer not including my attempt(s) in the question as I'm ashamed of their naiveness, so please excuse me for this.
Therefore the question is basically: how would the function above be written in CPS ?
Try that:
import scala.annotation.tailrec
def sol(chars: List[Char], n: Int) = {
#tailrec
def recSol(n: Int)(cont: (List[List[Char]]) => List[List[Char]]): List[List[Char]] = (chars, n) match {
case (_ , 0) => cont(List(Nil))
case (Nil, _) => cont(Nil)
case (_ , _) =>
recSol(n-1){ tail =>
cont(chars.map(ch => tail.map(ch :: _)).fold(Nil)(_ ::: _))
}
}
recSol(n)(identity).map(_.mkString).mkString(",")
}
The first order of business in performing the CPS transform is deciding on a representation for continuations. We can think of continuations as a suspended computation with a "hole". When the hole is filled in with a value, the remainder of the computation can be computed. So functions are a natural choice for representing continuations, at least for toy examples:
type Cont[Hole,Result] = Hole => Result
Here Hole represents the type of the hole that needs to be filled in, and Result represents the type of value the computation ultimately computes.
Now that we have a way to represent continuations, we can worry about the CPS transform itself. Basically, this involves the following steps:
The transformation is applied recursively to an expression, stopping at "trivial" expressions / function calls. In this context, "trivial" includes functions defined by Scala (since they are not CPS-transformed, and thus do not have a continuation parameter).
We need to add a parameter of type Cont[Return,Result] to each function, where Return is the return type of the untransformed function and Result is the type of the ultimate result of the computation as a whole. This new parameter represents the current continuation. The return type for the transformed function is also changed to Result.
Every function call needs to be transformed to accommodate the new continuation parameter. Everything after the call needs to be put into a continuation function, which is then added to the parameter list.
For example, a function:
def f(x : Int) : Int = x + 1
becomes:
def fCps[Result](x : Int)(k : Cont[Int,Result]) : Result = k(x + 1)
and
def g(x : Int) : Int = 2 * f(x)
becomes:
def gCps[Result](x : Int)(k : Cont[Int,Result]) : Result = {
fCps(x)(y => k(2 * y))
}
Now gCps(5) returns (via currying) a function that represents a partial computation. We can extract the value from this partial computation and use it by supplying a continuation function. For example, we can use the identity function to extract the value unchanged:
gCps(5)(x => x)
// 12
Or, we can print it by using println instead:
gCps(5)(println)
// prints 12
Applying this to your code, we obtain:
def solCps[Result](chars : List[Char], n : Int)(k : Cont[String, Result]) : Result = {
#scala.annotation.tailrec
def recSol[Result](n : Int)(k : Cont[List[List[Char]], Result]) : Result = (chars, n) match {
case (_ , 0) => k(List(Nil))
case (Nil, _) => k(Nil)
case (_ , _) =>
recSol(n - 1)(tail =>
k(chars.map(ch => tail.map(ch :: _)).fold(Nil)(_ ::: _)))
}
recSol(n)(result =>
k(result.map(_.mkString).mkString(",")))
}
As you can see, although recSol is now tail-recursive, it comes with the cost of building a more complex continuation at each iteration. So all we've really done is trade space on the JVM's control stack for space on the heap -- the CPS transform does not magically reduce the space complexity of an algorithm.
Also, recSol is only tail-recursive because the recursive call to recSol happens to be the first (non-trivial) expression recSol performs. In general, though, recursive calls would be take place inside a continuation. In the case where there is one recursive call, we can work around that by transforming only calls to the recursive function to CPS. Even so, in general, we would still just be trading stack space for heap space.
So I'm using play Twirl templates (not within play; independent project) and I have some templates that generate some database DDLs. The following works:
if(config.params.showDDL.isSupplied) {
print( BigSenseServer.config.options("dbms") match {
case "mysql" => txt.mysql(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
case "pgsql" => txt.pgsql(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
case "mssql" => txt.mssql$.MODULE$(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
})
System.exit(0)
}
But I have a lot of repeated statements. If I try to assign the case to a variable and use the $.MODULE$ trick, I get an error saying my variable doesn't take parameters:
val b = BigSenseServer.config.options("dbms") match {
case "mysql" => txt.mysql$.MODULE$
case "pgsql" => txt.pgsql$.MODULE$
case "mssql" => txt.mssql$.MODULE$
}
b("string1","string2","string3","string4","string5","string6")
and the error:
BigSense/src/main/scala/io/bigsense/server/BigSenseServer.scala:32: play.twirl.api.BaseScalaTemplate[T,F] with play.twirl.api.Template6[A,B,C,D,E,F,Result] does not take parameters
What's the best way to simplify this Scala code?
EDIT: Final Solution using a combination of the answers below
The answers below suggest creating factory classes, but I really want to avoid that since I already have the Twirl generated template object. The partially applied functions gave me a better understanding of how to achieve this. Turns out all I needed to do was to pick the apply methods and to eta-expand these; if necessary in combination with partial function application. The following works great:
if(config.params.showDDL.isSupplied) {
print((config.options("dbms") match {
case "pgsql" =>
txt.pgsql.apply _
case "mssql" =>
txt.mssql.apply _
case "mysql" =>
txt.mysql.apply(InetAddress.getLocalHost().getCanonicalHostName,
_:String, _:String, _:String,_:String, _:String)
})(
config.options("dbDatabase"),
config.options("dboUser"),
config.options("dboPass"),
config.options("dbUser"),
config.options("dbPass")
))
System.exit(0)
}
You can try to use eta-expansion and partially applied functions.
Given a factory with some methods:
class Factory {
def mysql(i: Int, s: String) = s"x: $i/$s"
def pgsql(i: Int, s: String) = s"y: $i/$s"
def mssql(i: Int, j: Int, s: String) = s"z: $i/$j/$s"
}
You can abstract over the methods like this:
val factory = new Factory()
// Arguments required by all factory methods
val i = 5
val s = "Hello"
Seq("mysql", "pgsql", "mssql").foreach {
name =>
val f = name match {
case "mysql" =>
// Eta-expand: Convert method into function
factory.mysql _
case "pgsql" =>
factory.pgsql _
case "mssql" =>
// Argument for only one factory method
val j = 10
// Eta-expand, then apply function partially
factory.mssql(_ :Int, j, _: String)
}
// Fill in common arguments into the new function
val result = f(i, s)
println(name + " -> " + result)
}
As you can see in the "mssql" case, the arguments may even differ; yet the common arguments only need to be passed once. The foreach loop is just to test each case, the code in the body shows how to partially apply a function.
You can try to do this by using tupled() to create tupled version of the function.
object X {
def a(x : Int, y : Int, z : Int) = "A" + x + y + z
def b(x : Int, y : Int, z : Int) = "B" + x + y + z
def c(x : Int, y : Int, z : Int) = "C" + x + y + z
}
val selectedFunc = X.a _
selectedFunc.tupled((1, 2, 3)) //returns A123
More specifically, you would store your parameters in a tuple:
val params = (BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName) //etc.
and then in your match statement:
case "mysql" => (txt.mysql _).tupled(params)
Note: this is a theoretical question, I am not trying to fix anything, nor am I trying to achieve any effect for a practical purpose
When creating a lambda in Scala using the (arguments)=>expression syntax, can the return type be explicitly provided?
Lambdas are no different than methods on that they both are specified as expressions, but as far as I understand it, the return type of methods is defined easily with the def name(arguments): return type = expression syntax.
Consider this (illustrative) example:
def sequence(start: Int, next: Int=>Int): ()=>Int = {
var x: Int = start
//How can I denote that this function should return an integer?
() => {
var result: Int = x
x = next(x)
result
}
}
You can always declare the type of an expression by appending : and the type. So, for instance:
((x: Int) => x.toString): (Int => String)
This is useful if you, for instance, have a big complicated expression and you don't want to rely upon type inference to get the types straight.
{
if (foo(y)) x => Some(bar(x))
else x => None
}: (Int => Option[Bar])
// Without type ascription, need (x: Int)
But it's probably even clearer if you assign the result to a temporary variable with a specified type:
val fn: Int => Option[Bar] = {
if (foo(y)) x => Some(bar(x))
else _ => None
}
Let say you have this function:
def mulF(a: Int, b: Int): Long = {
a.toLong * b
}
The same function can be written as lambda with defined input and output types:
val mulLambda: (Int, Int) => Long = (x: Int, y: Int) => { x.toLong * y }
x => x:SomeType
Did not know the answer myself as I never had the need for it, but my gut feeling was that this will work. And trying it in a worksheet confirmed it.
Edit: I provided this answer before there was an example above. It is true that this is not needed in the concrete example. But in rare cases where you'd need it, the syntax I showed will work.
In response to this question, I've been having a go at implementing a Haskell-style 'where' expression in Scala using the macro-paradise branch. The code is available at scala-where. I can now write something like the following:
val result = where ( f1(1) * f2(2), {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
})
However, what I'd really like to do is to be able to call this in infix position:
val result = ( f1(1) * f2(2)) where {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
}
Normally, this sort of thing would be easy, but I can't see how to do it with the macro call. The expression (f1(1) * f2(2)) won't type before macro application, so something like building an implicit value class doesn't work. Is there a way to get this kind of syntax otherwise?
Failing this, just having two parameter lists so one could do:
val result = where (f1(1) * f2(2)) {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
}
would be nice, but again this seems difficult. Can one call a macro with two parameter lists?
For the first option: I would think you could make the implicit conversion an untyped macro itself, no?
For the second option: You can call a macro with multiple parameter lists, yes. Multiple lists at the call site will translate to multiple lists at the definition site, e.g.:
def myMacro(a: _)(b: _) = macro myMacro_impl
def myMacro_impl(c: Context)(a: c.Tree)(b: c.Tree): c.Tree = { ... }
Would be called as:
myMacro(...)(...)
Answer: as of 2013-03-08 it is not possible to use untyped macros in an infix position. Quoted from Eugene Burmako on the scala-user mailing list:
Currently the argument on the left has to be typechecked first before
any implicit resolution kicks in. The fact that you can write "class
foo(x: _)" is an oversight - the underscore syntax is supposed to be
working only in untyped macros.
For reference, the closest I came to being able to do this was the following:
implicit class HasWhere(val exp : _) {
def where(block : Unit) = macro whereInfix
}
def whereInfix(c : Context)(block : c.Expr[Unit]) = {
import c.universe._
val exp = Select(c.prefix.tree, TermName("exp"))
val Expr(Block((inner, _))) = block
val newinner = inner :+ exp
Block(newinner : _*)
}