Conditional application of one of two functions to one argument - scala

I have two functions that take one argument, a String. I was to apply either one or the other based on some condition. This is what I attempted:
def foo(s: String) = { ... }
def bar(s: String) = { ... }
(if (condition) foo else bar)("baz")
But I get an error like this:
<console>:10: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied function
(if (true) foo else bar)("baz")
^
I tried writing foo_ but of course I got error: not found: value foo_. What's the correct way to express this idiom in Scala?

You need a space between the method name and the underscore. This works fine:
def foo(s: String) = s + "-FOO"
def bar(s: String) = s + "-BAR"
val condition = true
(if (condition) foo _ else bar _)("baz")
// res0: String = baz-FOO
The underscore after the method name tells Scala that you want to want to pass the method as a higher-level function. From what I understand, this is a way to disambiguate whether you want to pass a method as a function or pass the result of a method with no arguments. For example:
def f = 1
val x = Some(f)
What should the type of x be? Will it be Some[Int] or Some[()=>Int]? It should default to the former, but if you want the latter you can use the underscore notation:
val y = Some(f _)
You have to deal with all this underscore nonsense because Scala methods aren't functions. If you declare foo and bar as functions rather than methods then your original code works as-is:
val foo = (s: String) => s + "-FOO"
val bar = (s: String) => s + "-BAR"
val condition = false
(if (condition) foo else bar)("baz")
// res1: String = baz-BAR

There are several things I want to mention:
def foo(s: String) = { ... }
def bar(s: String) = { ... }
foo and bar are not functions, there are just normal method. Also, def f = 3 is also a method not function.
(if (condition) foo else bar)("baz") obviously, this statement need foo and bar to be a function because of ("baz") argument.
as #wendao mentioned to use _ to change method to function. I think the simplest solution is to define foo and bar as a function.
def foo: String => String = { value =>
"Hi " + value
}
def bar: String => String = { value =>
"farewell " + value
}
val x: Some[String => String] = Some(foo)
(if (true) foo else bar)("John") // Hi John

It doesn't know that what you actually want to return a function, you'd have to tell it that what you want is a by-name parameter:
def foo(x : String) = x //> foo: (x: String)String
def bar(x : String) = x //> bar: (x: String)String
val condition = true //> condition : Boolean = true
val result : String => String = if (condition) foo else bar
//> result : String => String = <function1>
result("something") //> res0: String = something

This is a little more absurd:
scala> var b = true
b: Boolean = true
scala> def f(s: String) = s"f+$s"
f: (s: String)String
scala> def g(s: String) = s"g+$s"
g: (s: String)String
scala> import Function._ ; import PartialFunction._
import Function._
import PartialFunction._
scala> unlift(condOpt(_: String) { case s if b => f(s) }) applyOrElse ("hi", g)
res0: String = f+hi
scala> b = false
b: Boolean = false
scala> unlift(condOpt(_: String) { case s if b => f(s) }) applyOrElse ("hi", g)
res1: String = g+hi

Related

Apply several transformation functions to string

Suppose I have 2 methods:
def a(s: String) = s + "..."
def b(s: String) = s + ",,,"
And I want to create 3rd method which will call both methods:
def c (s: String) = a(b(s))
How I can do it in idiomatic Scala way?
I think it's better to aggregate this functions into some List and then sequentially apply them:
List(a_, b_)
I think it's better to aggregate this functions into some List and
then sequentially apply them.
You get some help by specifying an expected type:
scala> val fs: List[String => String] = List(a,b)
fs: List[String => String] = List(<function1>, <function1>)
scala> fs.foldLeft("something")((s,f) => f(s))
res0: String = something...,,,
Here is how you can combine a set of functions into one:
// a() and b() are as defined in the question
// the following is equivalent to newfunc(x) = b(a(x))
val newFunc: String => String = List( a _, b _).reduce( _ andThen _ )
You can even create a generic function to combine them:
def functionChaining[A]( functions: A => A *): A => A = functions.reduce( _ andThen _ )
or using foldLeft:
def functionChaining[A]( functions: A => A *): A => A = functions.foldLeft( (x:A) => x )( _ andThen _ )
Here is an example of how to use this on the REPL:
scala> val newFunc: String => String = functionChaining( (x:String) => x + "---", (x:String) => x * 4)
scala> newFunc("|")
res12: String = |---|---|---|---
Many answers use andThen, but that will be give you
b(a(s))
Given that you want
a(b(s))
compose is the way to go (well, that or reversing the list, but what's the point?)
def c(s: String) = List[String => String](a, b).reduce(_ compose _)(s)
// or alternatively
def c(s: String) = List(a _, b _).reduce(_ compose _)(s)
As a result
c("foo") // foo,,,...
Now, speaking of what's idiomatic, I believe that
a(b(s))
is more idiomatic and readable than
List(a _, b _).reduce(_ compose _)(s)
This clearly depends on the number of functions you're composing. If you were to have
a(b(c(d(e(f(g(h(s))))))))
then
List[String => String](a, b, c, d, e, f, g, h).reduce(_ compose _)(s)
is probably neater and more idiomatic as well.
If you really think you need to do this:
val c = a _ andThen b
// (The signature is:)
val c:(String)=>String = a _ andThen b
or, more obviously:
def d(s:String) = a _ andThen b
If chained application is preferred then the below works. Caveats - Implicit syntax is a bit ugly; This being a structural type uses reflection.
object string {
implicit def aPimp(s: String) = new {
def a = "(a- " + s + " -a)"
}
implicit def bPimp(s: String) = new {
def b = "(b- " + s + " -b)"
}
}
scala> import string._
scala> "xyz".a.b
res0: String = (b- (a- xyz -a) -b)
scala> "xyz".b.a
res1: String = (a- (b- xyz -b) -a)
In my opinion, if not for the ugly syntax, this would be idiomatic scala.

Force grouping of ascription on underscore in scala

I am trying to do:
MyObject.myMethod(_:MyType.myAttribute)
This fails with
type myAttribute is not a member of object MyObject
which is correct. The problem is that I want to call myMethod on myAttribute of _:MyType, not ascribe MyType:myAttribute to _. Can I somehow group the type ascription _:MyType? (_:MyType).myAttribute returns type MyType => classOf(myAttribute), which is not what I want.
Edit: I changed the title and text of this post to no longer refer to this as the associativity of the dot, which I believe was not correct.
Are you trying to create function (m: MyType) => MyObject.myMethod(m.myAttribute) using underscore?
If so, the problem is that MyObject.myMethod((_:MyType).myAttribute) means MyObject.myMethod((m:MyType) => m.myAttribute).
You can use infix notation:
MyObject myMethod (_:MyType).myAttribute
Proof it works:
scala> case class MyType(myAttribute: Int)
defined class MyType
scala> object MyObject {
| def myMethod(a: Int) = a.toString
| }
defined module MyObject
scala> MyObject myMethod (_:MyType).myAttribute
res0: MyType => java.lang.String = <function1>
scala> res0(MyType(1))
res1: java.lang.String = 1
scala> MyObject myMethod (MyType(1))
<console>:1: error: type mismatch;
found : MyType
required: Int
MyObject myMethod (_:MyType)
^
I'm not sure whether this illustrates or answers your question, but it's true.
My guess is that you expected your a.b(_.i) to be an anon func after you add an ascription (to type the parameter).
But the subexpr foils you by there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u. (SLS 6.23)
Also, you can use scalac -Xprint:parser to see how it's taken.
object Foo {
def m(k: Int) = 7 * k
}
class Bar {
val i = 5
val What = i
}
object Bar {
type What = Int
}
object Test extends App {
Foo.m(_:Bar.What)
// this is not anon func placeholder syntax...
//Foo.m((_:Bar).What) // _ is in a subexpr
//Foo.m(_.i)
// ...for this
val f = (x: Bar) => Foo.m(x.i)
// InfixExpr is ok
val g = Foo m (_: Bar).i
val b = new Bar
println(f(b))
println(g(b))
}
Contrast, to illustrate what is being restricted:
scala> val f: (Int,Int)=>Int = _+_
f: (Int, Int) => Int = <function2>
scala> val g: Int=>Int = if (_ > 0) 1 else 2
<console>:7: error: missing parameter type for expanded function ((x$1) => x$1.$greater(0))
List(1,2,3).map((i: Int) => i * i)
EDIT
List(1,2,3).map((_: Int).unary_-)
EDIT 2
implicit class MyAttribute(i: Int) { def myMethod() = i * i }
List(1,2,3).map((_: Int).myMethod.unary_-)
Explanation
I used implicit class (Scala-2.10) to add myMethod on Int, after that unary "-" operation executed on result. You could add something like def wrap: MyAttribute to MyAttribute, and use it like (_: Int).wrap.method1.method2.method3.result.abs, for example.

Hiding closure boilerplate with macros?

Given an example closure, which in this case returns the number of words in a string (with an additional arbitrary operator).
val myfunc = (s: String) => Option(s).map(_.split(" ").size).filter(_ >= 2)
Is there a way I can hide some of the boilerplate such that I can write:
val myfunc = given[String].map(_.split(" ").size).filter(_ >= 2)
If you can live with two parentheses and an underscore extra, you don't need macros for that:
class Given[A] {
def apply[B](f: Option[A] => B): A => B = (a: A) => f(Option(a))
}
def given[A] = new Given[A]
In action:
scala> val myfunc = given[String](_.map(_.split(" ").size).filter(_ >= 2))
myfunc: String => Option[Int] = <function1>
scala> List("salmon cod herring","tuna").map(myfunc)
res4: List[Option[Int]] = List(Some(3), None)
I doubt. A macro replaces the function call it is in with something that type checks. So, what would you replace given[String] with in your example? If you replaced it with (s: String) => Option(s), you'd get this:
((s: String) => Option(s)).map(_.split(" ").size).filter(_ >= 2)
Which doesn't work like you want. You want the whole line to be changed, which is not going to happen.

Why put a generic type next to a function?

When I look at Scala libraries I see code like this. Why put test [A] .
def test[A](block : Int => Unit) : Unit = {
block(10)
}
test { u =>
println(u)
}
This is just as valid I suppose. It runs the same way.
def test(block : Int => Unit) : Unit = {
block(10)
}
I've just been curious what the reasoning(or design pattern) is behind it. Thanks.
The type parameter A makes no sense here because it is not used.
def test[A](block: Int => A): A = block(10)
Here A specifies the return type.
When there a generic type next to the function, it means that the function is a generic function.
The following is a very simple example:
// generic functions which returns type of `A`
def test1[A](x: A) = x
def test2[A](x: => A) = { println("Hello"); x }
val x1 = test1(1)
// x1: Int = 1
val x2 = test1("Hello World")
// x2: java.lang.String = Hello World
val x3 = test2(123.4)
// Hello
// x3: Double = 123.4
val x4 = test2("Test2")
// Hello
// x4: java.lang.String = Test2
As you can see, the return type of test1 and test2 are determined by the type of their arguments.
The following is another use case.
// We could implement `map` function ourself.
// We don't care about what type of List contains,
// so we make it a generic function.
def map[A, B](xs: List[A], f: A => B): List[B] = {
var result: List[B] = Nil
for (i <- xs) {
result ++= List(f(i))
}
result
}
// Now use can map any type of List to another List.
map(List("1", "2", "3"), (x: String) => x.toInt)
//res1: List[Int] = List(1, 2, 3)

Using lazy evaluation functions in varargs

What is wrong is the following method?
def someMethod(funcs: => Option[String]*) = {
...
}
That actually "works" under 2.7.7 if you add parens:
scala> def someMethod(funcs: => (Option[String]*)) = funcs
someMethod: (=> Option[String]*)Option[String]*
except it doesn't actually work at runtime:
scala> someMethod(Some("Fish"),None)
scala.MatchError: Some(Fish)
at scala.runtime.ScalaRunTime$.boxArray(ScalaRunTime.scala:136)
at .someMethod(<console>:4)
at .<init>(<console>:6)
at .<clinit>(<console>) ...
In 2.8 it refuses to let you specify X* as the output of any function or by-name parameter, even though you can specify it as an input (this is r21230, post-Beta 1):
scala> var f: (Option[Int]*) => Int = _
f: (Option[Int]*) => Int = null
scala> var f: (Option[Int]*) => (Option[Int]*) = _
<console>:1: error: no * parameter type allowed here
var f: (Option[Int]*) => (Option[Int]*) = _
But if you try to convert from a method, it works:
scala> def m(oi: Option[Int]*) = oi
m: (oi: Option[Int]*)Option[Int]*
scala> var f = (m _)
f: (Option[Int]*) => Option[Int]* = <function1>
scala> f(Some(1),None)
res0: Option[Int]* = WrappedArray(Some(1), None)
So it's not entirely consistent.
In any case, you can possibly achieve what you want by passing in an Array and then sending that array to something that takes repeated arguments:
scala> def aMethod(os: Option[String]*) { os.foreach(println) }
aMethod: (os: Option[String]*)Unit
scala> def someMethod(funcs: => Array[Option[String]]) { aMethod(funcs:_*) }
someMethod: (funcs: => Array[Option[String]])Unit
scala> someMethod(Array(Some("Hello"),Some("there"),None))
Some(Hello)
Some(there)
None
If you really want to (easily) pass a bunch of lazily evaluated arguments, then you need a little bit of infrastructure that as far as I know doesn't nicely exist in the library (this is code for 2.8; view it as inspiration for a similar strategy in 2.7):
class Lazy[+T](t: () => T, lt: Lazy[T]) {
val params: List[() => T] = (if (lt eq null) Nil else t :: lt.params)
def ~[S >: T](s: => S) = new Lazy[S](s _,this)
}
object Lz extends Lazy[Nothing](null,null) {
implicit def lazy2params[T : Manifest](lz: Lazy[T]) = lz.params.reverse.toArray
}
Now you can easily create a bunch of parameters that are lazily evaluated:
scala> import Lz._ // To get implicit def
import Lz._
scala> def lazyAdder(ff: Array[()=>Int]) = {
| println("I'm adding now!");
| (0 /: ff){(n,f) => n+f()}
| }
lazyAdder: (ff: Array[() => Int])Int
scala> def yelp = { println("You evaluated me!"); 5 }
yelp: Int
scala> val a = 3
a: Int = 3
scala> var b = 7
b: Int = 7
scala> lazyAdder( Lz ~ yelp ~ (a+b) )
I'm adding now!
You evaluated me!
res0: Int = 15
scala> val plist = Lz ~ yelp ~ (a+b)
plist: Lazy[Int] = Lazy#1ee1775
scala> b = 1
b: Int = 1
scala> lazyAdder(plist)
I'm adding now!
You evaluated me!
res1: Int = 9
Evidently repeated arguments are not available for by-name parameters.