Sequencing functions with multiple arguments in Cats - scala

I was going through "Scala with Cats" by Underscore and stumbled upon the following statement:
Cats provides a cats.syntax.apply module that makes use of Semigroupal and Functor to allow users to sequence functions with multiple arguments.
As far as I understand we can only sequence functions with single arguments because functions can return only single value.
import cats.implicits._
val f1: Int => Int = x => x + 1
val f2: Int => Int = x => x * 4
val f3: Int => String = x => s"x = $x"
f1.map(f2).map(f3)(5)
For the following example, it says: Internally mapN uses the Semigroupal to extract the values from the Option and the Functor to apply the values to the function.
final case class Cat(name: String, born: Int, color: String)
(
Option("Garfield"),
Option(1978),
Option("Orange & black")
).mapN(Cat.apply)
// res10: Option[Cat] = Some(Cat("Garfield", 1978, "Orange & black"))
Here Cat.apply is indeed a function with multiple arguments but it is chained to a function that itself returns a tuple of options i.e., a single value. We could probably make it accept multiple arguments like so:
final case class Cat(name: String, born: Int, color: String)
val f: (String, Int, String) => (Option[String], Option[Int], Option[String]) =
(name, year, color) => (Option(name), Option(year), Option(color))
f("Garfield", 1978, "Orange & black").mapN(Cat.apply)
Now we have functions f and Cat.apply that accept multiple arguments and are chained together. Is it what the above statement was pointing to? But then I can't seem to find a way to chain more functions further. Is the statement applicable to chaining multiple argument functions only at one level? Also, notice here that function f is applied eagerly in contrast to the single argument function chaining example depicted above. Is is possible to apply functions lazily here?
There isn't much explanation I could find anywhere on Semigroupal on internet. Could anyone please explain this statement with an example? TIA.

But then I can't seem to find a way to chain more functions further.
I think we can because we can continue mapping over the context for example
f("Garfield", 1978, "Orange & black")
.mapN(Cat.apply)
.map(_.name) // here is another step in the chain of operations
mapN is product + map behind the scenes; we can reveal the constituent map like so
f("Garfield", 1978, "Orange & black")
.tupled
.map { case (a, b, c) => Cat.apply(a, b, c) }
.map { _.name }
where tupled extension method eventually calls Semigroupal#product.
When they say
...allow users to sequence functions with multiple arguments.
my interpretation is not that we keep chaining with just mapN, but instead we can continue chaining over the context in the general sense of the functor, and if at some point in the chain, usually the beginning, we have multiple values within multiple contexts of the same type, then semigroupal + functor allows us to join the values within the single context and continue chaining.
Also, notice here that function f is applied eagerly in contrast to the single argument function chaining example depicted above. Is is possible to apply functions lazily here?
That is kind of the main selling point of Semigroupal over the Monad, that is, to be able to "eagerly" execute independent operations, join the resulting values within the context and then continue chaining. With monadic chaining even if operations are independent one would still have to wait for the other before continuing the chain.

Related

Equality of functions in Scala, is functions objects in Scala?

I am reading the book Programming in Scala. In the book, it says that "A function literal is compiled into a class that when instantiated at runtime is a function value". And it mentions that "Function values are objects, so you can store them in variables if you like".
So I try to check the equality between functions. But I failed.
If function is object in Scala, then it should behave like other objects in Scala. Maybe check equality of function is meaningless, so it is disabled?
And will function be compiled into object in Scala?
Lambda are compiled as anonymous classes (not case class, as far as I remember). That means if you do:
val f1: (String) => String = _ => "F1"
val f2: (String) => String = _ => "F2"
Both f1 and f2 are subtype of Function1[String,String], but they are of different anonymous classes, so can't equal.
If you write it as:
case class F(res: String) extends ((String) => String) {
def apply(s: String) = res
}
Then:
val f1: (String) => String = F("A")
val f2: (String) => String = F("A")
f1 == f2 // true
It's not clear what "equality" of functions means. Typically, what people care about is "do these two functions compute the same result?"
This, however, is a well-known undecidable problem, the Function Problem. The actual proof is more complex, obviously, but a simple intuition is: if you could tell whether two functions were equal, then you could solve the Halting Problem by asking "is this function equal to while (true) {}?"
So, we cannot decide whether two functions compute the same result. What we could do, is for example, check whether they contain the exact same code. But that is pretty boring. Just some tiny compiler optimization or renaming a single variable will make two functions that intuitively should be equal not equal.
Ergo, we take the easy way out: two functions are equal if they are identical, otherwise they aren't.

Scala - Make signature of function parameter f of higher order function g dependent on varars of g

I am trying to define a higher order function f which accepts a variable number of parameters args of type Wrapper[T]* and a function parameter g in Scala.
The function f should decapsulate each object passed in args and then call g with the decapsulated parameters. Therefore, g has to accept exactly the same number of parameters of type T as args contains.
The closest thing I could achieve was to pass a Seq[T] to g and to use pattern matching inside of g. Like the following:
f("This", "Is", "An", "Example")(x => x match {
case Seq(a:String, b:String, c:String): //Do something.
})
With f defined like:
def f[V](args: Wrapper[T]*)
(g: (Seq[T]) => (V)) : V = {
val params = args.map(x => x.unwrap())
g(params)
}
How is it possible to accomplish a thing like this without pattern
matching?
It is possible to omit the types in the signature of g
by using type inference, but only if the number of parameters is
fixed. How could this be done in this case?
It is possible to pass
different types of parameters into varargs, if a type wildcard is
used args: Wrapper[_]*. Additionally, casting the result of
x.unwrap to AnyRef and using pattern matching in g is
necessary. This, however, completely breaks type inference and type
safety. Is there a better way to make mixing types in the varargs
possible in this special case?
I am also considering the use of scala makros to accomplish these tasks.
Did I get you right? I replaced your Wrapper with some known type, but that doesn't seem to be essential.
def f[T, V](args: T*)(g: PartialFunction[Seq[T], V]): V = g(args)
So later you can do this:
f(1,2,3) { case Seq(a,b,c) => c } // Int = 3
Okay, I've made my own Wrapper to be totally clear:
case class Wrapper[T](val x:T) {
def unwrap = x
}
def f[V](args: Wrapper[_]*)(g: PartialFunction[Seq[_], V]): V =
g(args.map(_.unwrap))
f(Wrapper("1"), Wrapper(1), Wrapper(BigInt(1))) {
case Seq(s: String, i: Int, b: BigInt) => (s, i, b)
} // res3: (String, Int, BigInt) = (1,1,1)
Regarding your concerns about type safety and conversions: as you can see, there aren't any explicit conversions in the code above, and since you are going to pattern-match with explicitly defined types, you may not to worry about these things - if some items of an undefined origin are going to show in your input, scala.MatchError will be thrown.

Difference between currying and higher-order functions

Looking at Programming in Scala (control abstraction) I saw these two examples that have the same effect:
1. Higher-Order Function
def withPrintWriter(file: File, op: PrintWriter => Unit) {
val writer = new PrintWriter(file)
try {
op(writer)
} finally {
writer.close()
}
}
2. Currying function
def withPrintWriter(file: File)(op: PrintWriter => Unit) {
val writer = new PrintWriter(file)
try {
op(writer)
} finally {
writer.close()
}
}
What is the difference between them? Can we always achieve the same result in both ways?
The concepts of higher-order functions and curried functions are generally used in an orthogonal way. A higher-order function is simply a function that takes a function as an argument or returns a function as a result, and it may or may not be curried. In general usage, someone referring to a higher-order function is usually talking about a function that takes another function as an argument.
A curried function, on the other hand, is one that returns a function as its result. A fully curried function is a one-argument function that either returns an ordinary result or returns a fully curried function. Note that a curried function is necessarily a higher-order function, since it returns a function as its result.
Thus, your second example is an example of a curried function that returns a higher-order function. Here's another example of curried function that does not take a function as an argument, expressed in various (nearly equivalent) ways:
def plus(a: Int)(b:Int) = a + b
def plus(a: Int) = (b: Int) => a + b
val plus = (a: Int) => (b: Int) => a + b
Higher order functions are functions that either take functions as parameter or return functions or both.
def f(g: Int => Int) = g(_: Int) + 23
scala> f(_ + 45)
res1: Int => Int = <function1>
scala> res1(4)
res2: Int = 72
This is a higher order function, it takes a function as parameter and returns another function. As you can see, higher order functions are a pre-requisite for currying. The curry function looks like this:
def curry[A,B,C](f: (A,B) => C) = (a: A) => (b: B) => f(a,b)
scala> curry((a: Int, b: Int) => a+b)
res3: Int => (Int => Int) = <function1>
scala> res3(3)
res4: Int => Int = <function1>
scala> res4(3)
res5: Int = 6
So to answer your question: They are two different concepts, where the one (higher order functions) is the pre-requisit for the other (currying).
Semantically, there is one difference I can think of between a curried and a not curried function. With the non-curried version, when you call withPrintWriter, that's a single method call. With the curried version, it's actually going to be two method calls. Think of it like this:
withPrintWriter.apply(file).apply(op)
Other than that, I think a lot of people use currying in this kind of situation for style. Using currying here makes this look more like a language feature then just a custom function call because you can use it like this:
withPrintWriter(file){ op =>
...
}
Using it in that way is trying to emulate some sore of control structure from the language itself, but again, this is only really a style thing and it does come with the overhead of an additional method call.
You can use the non-curried version in almost the same way, but it's not as clean looking:
withPrintWriter(file, { op =>
...
})
EDIT
#drexin makes a good point in his answer that it's worth mentioning here for me. When you think of the signature of the curried version of the method, it's really:
Function1[File, Function1[PrintWriter, Unit]]
They are mostly the same, but there is a difference with regard to type inference. Scala is not able to infer types between arguments of a single method invocation, but it is able to infer types for multiple argument lists.
Consider:
def foo1[T](x : T, y : T => T) = y(x)
def foo2[T](x : T)(y : T => T) = y(x)
foo1(1, t => t + 1) //does not compile with 'missing parameter type'
foo2(1)(t => t + 1) //compiles
You can see some additional information in this answer : Multiple parameter closure argument type not inferred
Strictly speaking, the example you gave is not really curried, it just has multiple argument lists. It just happens that multiple argument list Scala functions look a lot like curried functions in many situations. However, when you call a multiple argument list function but don't fill in one or more argument lists, it's really an example of partial application, not currying. Calling a multiple argument list with all its arguments is just one function call, not one per argument list.
There are two use cases where multiple argument list functions are helpful. The first is the case of implicit parameters, since all implicit parameters have to be in their own argument list separate from any explicit parameters. The second use case is functions that accept other functions as parameters, since if a parameter that is a function is in its own argument list, you can leave off the parentheses and just use braces, making the function call look like some sort of control structure.
Other than that, the difference is purely cosmetic.

How to pass a tuple argument the best way?

How to pass a tuple argument the best way ?
Example:
def foo(...): (Int, Int) = ...
def bar(a: Int, b: Int) = ...
Now I would like to pass the output of foo to bar. This can be achieved with:
val fooResult = foo(...)
bar(fooResult._1, fooResult._2)
This approach looks a bit ugly, especially when we deal with a n-tuple with n > 2. Also we have to store the result of foo in an extra value, because otherwise foo has to be executed more than once using bar(foo._1, foo._2).
Is there a better way to pass through the tuple as argument ?
There is a special tupled method available for every function:
val bar2 = (bar _).tupled // or Function.tupled(bar _)
bar2 takes a tuple of (Int, Int) (same as bar arguments). Now you can say:
bar2(foo())
If your methods were actually functions (notice the val keyword) the syntax is much more pleasant:
val bar = (a: Int, b: Int) => //...
bar.tupled(foo())
See also
How to apply a function to a tuple?
It is worth also knowing about
foo(...) match { case (a,b) => bar(a,b) }
as an alternative that doesn't require you to explicitly create a temporary fooResult. It's a good compromise when speed and lack of clutter are both important. You can create a function with bar _ and then convert it to take a single tuple argument with .tupled, but this creates a two new function objects each time you call the pair; you could store the result, but that could clutter your code unnecessarily.
For everyday use (i.e. this is not the performance-limiting part of your code), you can just
(bar _).tupled(foo(...))
in line. Sure, you create two extra function objects, but you most likely just created the tuple also, so you don't care that much, right?
Using tupled, as #Tomasz mentions, is a good approach.
You could also extract the tuple returned from foo during assignment:
val (x, y) = foo(5)
bar(x, y)
This has the benefit of cleaner code (no _1 and _2), and lets you assign descriptive names for x and y, making your code easier to read.

A Map of Different Function Types in Scala

I have two functions with different type signatures, and I want to store them both in a Map:
val add = ((a: Int, b: Int) => a + b)
val odd = ((a: Int) => a % 2 == 0)
var funcs = Map[String, Any]("add" -> add, "odd" -> odd)
Then I want to access these functions at a later date, without having to know about their types. How would I do this? I can write:
funcs("add").asInstanceOf[(Int, Int) => Int](1, 2)
But that requires me to either
know ahead of time what the type of the function is
do some sort of pattern match that accounts for every possible type.
Is there some way I can find out the type of the object stored as Any and convert it to that type?
Although this certainly is not a good idea, if you really have to do it, you can do it using reflection.
Using PaulP's Invocation utility:
scala> val add: (Int, Int) => Int = _ + _
add: (Int, Int) => Int = <function2>
scala> val isOdd: Int => Boolean = _ % 2 != 0
isOdd: Int => Boolean = <function1>
scala> import Invocation._
import Invocation._
scala> val funcs = Map("add" -> add, "isOdd" -> isOdd)
funcs: scala.collection.immutable.Map[java.lang.String,ScalaObject] = Map(add -> <function2>, isOdd -> <function1>)
scala> funcs("add") o 'apply(3, 4)
res18: Any = 7
scala> funcs("isOdd") o 'apply(11)
res19: Any = true
Is there some way I can find out the type of the object stored as Any and convert it to that type?
This doesn't actually make sense. Lets suppose I could do it, and it looks like this:
val func = funcs(func_name).toAppropriateType
Now what?
func now holds a value of some unknown type. I can call it... but I don't know its signature, so what arguments do I pass it? And the type/signature is going to be different on every invocation (depending on what was pulled out of the map), so the code to call it is going to have to be different for every invocation; I need some way of having different code executed for each possibility of func... but that would be a pattern match! And it would have to account for every possible type, just as match on Any.
In fact, the magical toAppropriateType method, even if it could exist, gains me nothing on top of just using an Any. It's still the case that the only things I can do with func are things you can do with all values of every possible type (i.e. very little).
In general, when you take something out of a collection you have to handle it with code that is valid for anything that the type allows to be put into the collection. The only alternative is to use features such as asInstanceOf, which throws away the guarantees of the type system and puts the responsibility for ensuring that you don't use the wrong type on you; meaning you have to have some other way of knowing what type to expect, outside of the type system.
If you want to have a collection of functions with one of a pre-determined set of signatures then the best way is to construct a type that only allows those signatures, and allows you to tell the difference between them (such as Rex Kerr's suggestion of using Either). Switching to using Any as soon as you find you need to combine things of different types in a collection usually causes more problems than it solves.
You could store them in an Either:
val funcs = Map[String, Either[Int=>Boolean, (Int,Int)=>Int]](
"add" -> Right(add),
"odd" -> Left(odd)
)
Now you can pull them apart again, though pattern matching is finicky here (Right(f) will work, but don't try to put conditions on what f is). I suggest using fold, right, left (and isRight and isLeft if you really must), like so:
def doSomething(s: String) =
funcs(s).fold(
f => { f(4) }, // Left is Int=>Boolean
g => { g(3,5)==8 } // Right is (Int,Int)=>Int
)
Presumably you'd want some way to load appropriate arguments also instead of the dummy values I put in.
If you have many variants of functions, you can define your own either-like hierarchy except with more different cases, or you can nest Eithers.