How to compose a zero-argument function? - scala

What I want to achieve is the 2 functions (one of them is no arg function) are composed into one.
Here is an example to give you idea what I am doing:
object Test extends App {
val zeroArgFunc = () => 10
val intArgFunc = (i: Int) => s"hello $i"
val stringArgFunc = (s: String) => println(s)
// This line works perfectly fine.
val intAndThenString: Int => Unit = stringArgFunc compose intArgFunc
// But this line fails with 'type mismatch' compilation error.
val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc
}
Compilation error:
[error] found : () => Int
[error] required: ? => Int
[error] val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc
[error] ^
[error] one error found
Any idea what's wrong?
[UPD] The Scala version is 2.13.1 (if it matters).

Desugaring () => 10 we have
new Function0[Int] { def apply() = 10 }
and Function0 does not have compose or andThen methods
trait Function0[... +R] extends ... { ...
def apply(): R
override def toString(): String = "<function0>"
}
so it seems Function0 cannot be composed.
On the other hand (i: Int) => s"hello $i" and (s: String) => println(s) correspond to Function1 which does have compose method defined, hence they can be composed.
Consider changing () => 10 to (_: Unit) => 10 which changes the type from Function0 to Function1, and then
(intArgFunc compose zeroArgFunc)()
outputs res4: String = hello 10.
Addressing comment by #Duelist, IMHO Function0[T] is not semantically equivalent to Function1[Unit, T]. For example, given
val f = () => 10
val g = (_: Unit) => 10
then
f()
g()
indeed outputs
res7: Int = 10
res8: Int = 10
however
f(println("woohoo")) // error: no arguments allowed for nullary method apply
g(println("woohoo")) // OK!
where we see the two do not have the same behaviour. Nevertheless, if you would like to consider them as equivalent perhaps you could define an extension method on Function0 and be explicit about conversion, for example
implicit class Fun0ToFun1[A, B](f: () => A) {
def toFun1: Unit => A = (_: Unit) => f()
}
would allow the following syntax
(intArgFunc compose zeroArgFunc.toFun1)()
Addressing comment by #egordoe, out-of-the-box compose is only ever defined for Function1, thus Function2, Function3, etc., cannot be composed just like Function0. However we could define extension composeN methods on function, for example, say we want to compose Function1 with Function0, then
implicit class ComposeFun1WithFun0[A, B](f1: A => B) {
def compose0(f2: () => A): () => B = () => f1(f2())
}
gives
(intArgFunc compose0 zeroArgFunc)()

compose on Function1 (which intArgFunc is) is just defined to only accept single-argument functions:
def compose[A](g: (A) => T1): (A) => R
You could write helper functions to convert () => A to/from Unit => A
def toUnitFun[A](f: () => A): Unit => A = _ => f()
def fromUnitFun[A](f: Unit => A): () => A = () => f(())
and then
val zeroAndThenInt = fromUnitFun(intArgFunc compose toUnitFun(zeroArgFunc))
You can even make your original code work by marking to/fromUnitFun as implicit.

Related

scala map method can not correctly resolve function type in collection with fixed function types

I have the following code,
def obsKPI[T](kpi: Option[T], f: T => Unit) = {
kpi match {
case Some(obsValue) => f(obsValue)
case _ => Unit
}
}
def func1(str:String):Unit = println(str)
def func2(num: Int):Unit = println(num)
//option1: val inputArgs = List((Some("first"),(func1 _)),(Some("third"), (func1 _)))
//option2: val inputArgs = List((Some(456), (func2 _)),(None,(func2 _)))
// option3:
val inputArgs = List((Some("first"),(func1 _)),(Some(456), (func2 _)),(Some("third"), (func1 _)),(None,(func2 _)))
inputArgs.map(x => obsKPI(x._1, x._2))
when running either option 1 or 2 (the inputArgs list contains function of only String=>Unit or Int=>Unit), the code works, but when running option 3, I get an error:
:68: error: type mismatch;
found : Int with String => Unit
required: Any => Unit
inputArgs.map(x => obsKPI(x._1, x._2))
^
Thanks for letting me know what went wrong in here.
Functions aren't covariant in their parameter types (they are in fact contravariant).
This means, that if Foo is a subclass of Bar, Foo => Unit is not a subclass of Bar => Unit (the opposite is true).
In your case, you are trying to coerce func1 and func2 to Any => Unit, but that cannot work, because their types are incompatible - one is String => Unit, and the other one is Int => Unit.
One way to get around this problem, is to use a case class rather than a tuple:
case class KPI[T](t: Option[T], f: T => Unit)
def obsKPI(kpi: KPI[_]) = kpi match {
case KPI(Some(k), f) => f(k)
case _ => () // `()` is the value of type Unit. Unit, as you had it is the value of type Unit.type - not what you want at all
}
// You can also write the above more concise like this: def obsKPI[T](kpi: KPI[T]) = kpi.t.foreach(kpi.f)
def func1(str:String) = println(str)
def func2(num: Int) = println(num)
val inputArgs = List(KPI(Some("first"),func1 _), KPI(Some(456), func2 _), KPI(Some("third"), func1 _), KPI[Int](None,func2 _))
inputArgs.foreach(obsKPI) // Could do .map here too, but ending up with a list of ()s is unlikely what you you want.
You can make it look a bit more elegant, if you make your obsKPI into a member of the case class:
case class KPI[T](t: Option[T], f: T => Unit) {
def obs = t.foreach(f)
}
val inputArgs = List(KPI(Some("first"),func1 _), KPI(Some(456), func2 _), KPI(Some("third"), func1 _), KPI[Int](None,func2 _))
inputArgs.foreach(_.obs)

Scala class method to function with class instance as parameter

I'm pretty sure what I'd like to do is probably not possible and not a good idea anyway. Nonetheless, here it is.
I would like to find a generic way of transforming any method on any class into a function that takes as arguments an instance of the class and the parameters of the method and calls the method on the instance with the specified parameters (which is basically how method calls work at a low-level: the object instance is a hidden parameter pushed by the compiler on the stack frame)
Example:
Given
class A { def foo(param1: Type1): TypeN }
I would like to have something like:
def functor[X](methodName: String): (obj: X, methodParams: Types*) => TypeN
Such that:
// Type (obj: A, param1: Type1) => TypeN
val fooFn = functor[A]("foo")
val res: TypeN = fooFn(new A, new Type1)
Which would allow something like:
def flip[A, B, C](fn: A => B => C): B => A => C = (b: B) => (a: A) => fn(a)(b)
// Type (param1: Type1) => (obj: A) => TypeN
val fooFl = flip(fooFn.curried)
List(new A, new A).map(fooFl(new Type1) _)
One example where something like that could be useful follows:
Imagine you have:
val divide = (i: Int) => Try(2/i).toOption
List(1, 0).map(i => divide(i).getOrElse(0))
but you'd like an arguably cleaner:
import OptionUtils.getOrElse
List(1, 0).map(getOrElse(0) _ compose divide)
Now, I've defined that getOrElse manually as:
object OptionUtils {
def getOrElse[A](default: A)(option: Option[A]) = option.getOrElse(default)
}
But would like to be able to do automatically define such a methods for all (or any given selection) of methods in a specified class. Ideally I'd have something like:
val optionUtils: Utils[Option] = Utils(Option, List("getOrElse", "or"))
optionUtils.getOrElse(None, 1) // = 1
optionUtils.getOrElseFl(1)(None) // = 1
Any suggestions/comments?
You can use Java relection for this (here is scala code)
Or Scala reflection:
import scala.reflect._, runtime.universe._
def functor[X: TypeTag: ClassTag, R](methodName: String)(obj: X) = {
val m = runtimeMirror(getClass.getClassLoader)
val method = typeTag[X].tpe.declaration(newTermName(methodName)).asMethod
val call = m.reflect(obj).reflectMethod(method)
(call.apply _) andThen (_.asInstanceOf[R])
}
scala> functor[Option[Int], Int]("get") _
res19: Option[Int] => (Seq[Any] => Int) = <function1>
scala> res19(Some(5))(Nil)
res20: Int = 5

scala -- syntax to indicate any kind of anonymous function, whatsoever

I'd like to be able to pass in callback functions as parameters to a method. Right now, I can pass in a function of signature () => Unit, as in
def doSomething(fn:() => Unit) {
//... do something
fn()
}
which is fine, I suppose, but I'd like to be able to pass in any function with any parameters and any return type.
Is there a syntax to do that?
Thanks
To be able to execute a function passed as a callback you have to be able to call it with the arguments it requires. f: A => R must be called as f(someA), and g: (A,B) => R must be called as f(someA, someB).
Implementing a callback you want a function that accepts a context and returns something (you don't care what the something is). For example foreach in scala.Option is defined as:
def foreach[U](f: (A) => U): Unit
The function is called with a value of type A but the result is discarded so we don't care what type it has. Alternatively if you don't care what was completed the callback function could be implemented as:
def onComplete[U](f: () => U): Unit
It would then allow being called with any function that takes no arguments:
val f: () => Int = ...
val g: () => String = ...
onComplete(f) // In result is discarded
onComplete(g) // String result is discarded
If you really wanted a function that accepted any possible function there are some tricks you could use (but you really shouldn't). For example you could define a view bound with implicit conversions:
// Type F is any type that can be converted to () => U
def onComplete[F <% () => U, U](f: F): Unit
// Define conversions for each Function type to Function0
implicit def f1tof0[A,U](f: A => U): () => U = ...
implicit def f2tof0[A,B,U](f: (A,B) => U): () => U = ...
implicit def f3tof0[A,B,C,U](f: (A,B,C) => U): () => U = ...
.
.
etc.
Now onComplete accepts any function:
val f: Int => String = ...
val g: (List[Int], String) => String = ...
onComplete(f)
onComplete(g)
Defining the types for the above conversions is relatively simple, but there is no rational way to implement them so is pretty much entirely useless.

What's the difference of the two method definition?

What's the difference of the following definition?
1.def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
2.def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
The first definition can accept any thing, string, or function etc. but the second one can only accept function. I'd like to know reazon.
scala> def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: => AnyRef)Unit
scala> debug("hi")
hi
scala> debug(() => "xx")
<function0>
scala> def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: () => AnyRef)Unit
scala> debug("hi")
<console>:9: error: type mismatch;
found : java.lang.String("hi")
required: () => AnyRef
debug("hi")
^
The first is a call-by-name parameter, i.e. it evaluates the the argument each time it is used in the method, and only if it is used. As you have discovered, this can be anthing that evaluates to the required type.
The second takes specifically a Function0[AnyRef] object. You can think of the () as an empty parameter list (not to be confused with the Unit value, which is written the same).

How to overload scala function apply methods

As a follow on to: scala loan pattern, optional function param
What would the proper syntax be to move the withLoaner param to overloaded apply methods? I've tried several versions of the following unsuccessfully. Also, any insights into my error conceptually very appreciated.
def withLoaner = new {
def apply(n:Int, op: Int => String):String = (1 to n).map(op).mkString("\n")
def apply(n:Int, op: () => String):String = apply{n, i:Int => op()} // no compile
def apply(op: () => String):String = apply{1, i:Int => op()} // no compile
}
When passing multiple parameters, you must use parenthesis around them. Using {} only works for single parameters.
Also, when using function literals, if you specify type, you have to put all of the functions parameters inside parenthesis.
So,
def withLoaner = new {
def apply(n:Int, op: Int => String):String = (1 to n).map(op).mkString("\n")
def apply(n:Int, op: () => String):String = apply(n, i => op()) // no type on i
def apply(op: () => String):String = apply(1, (i: Int) => op()) // parenthesis around parameters
}
2 little changes:
Use ( instead of { when calling apply:
apply(.......)
Use ( around the arg to an implicit function:
apply(1, (i:Int) => op())