Idiomatic scala way of creating unnamed extracting func - scala

Given that there is a functionfoo[A, B, C]( func: (a: A, b: B, c: C) => B) and I want to pass in this function def secondOfThree[A, B, C](a: A, b: B, c: C): B = b
I can call foo with foo(secondOfThree) which is ugly, but works fine.. However, I would expect to be able to call foo with something along the lines of foo(case (_, b, _) => b) however this doesn't work.
So what's the clean idiomatic scala way of creating a simple unnamed extracting function?

You don't need the case keyword, but Scala does need to know the types:
scala> def foo[A, B, C](func: (A, B, C) => B) = ...
foo: [A, B, C](func: (A, B, C) => B)Nothing
scala> foo[Symbol, Int, Char]((_, b, _) => b)
If the types are known to foo, then the call doesn't need to specify them:
scala> def foo(func: (Symbol, Int, Char) => Int) = func('a, 2, 'c') + 5
foo: (func: (Symbol, Int, Char) => Int)Int
scala> foo((_, b, _) => b)
res3: Int = 7

So if types could be inferred, you can just the simplest:
class Trio[A, B, C](a: A, b: B, c: C) {
def foo(func: (A, B, C) => B): B = func(a, b, c)
}
println(new Trio(1, "string", 'Symbol).foo((_, b, _) => b))

Related

Scala - multiple function, returns multiple function

I started to learn the basics of scala and and I have problem with understanding simple function. I have three tasks to do. First of them was easy for me and i know how it works. But next two I don't understand what I have to write to return.
def compose[A,B,C](f: A => B)(g: B => C): A => C = {
a: A => g(f(a))
}
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) {
???????????
}
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
??????????
}
Let's look at the types, you should be able to implement the method quite easily by looking at the them.
Start with prod, start by writing the input parameters and expected output:
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) = {
(a: A, b: B) => {
val c: C = ???
val d: D = ???
(c, d)
}
}
Then, how can you build c and d given what you have (that is f and g)?
I let you answer this question by yourself.
The same can be applied for lift:
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
(a: A) => {
val t: T = ???
}
}
This one might be a bit trickier if you have no idea what lift is supposed to do though.
Hint: you probably have to use f and g, otherwise they wouldn't exist. Then from the values you get, how to get the desired output type?

How to make a product of function in Scala

I've got an exercise to create a product of two functions from the code below:
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
}
My plan was to do something like this, but it doesn't work, because it can't resolve symbols A and B.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
v1: (A,B) => f(A)*g(B)
}
The syntax to define a function type signature and a function definition is different. When you return a value, you need to return the function definition.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) =
(a: A, b: B) => (f(a), g(b))

Scala pass a generic function into another generic function confusion

I'm implementing the List type in Scala when following a book.
Here's the definition of my List type:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
All the later mentioned functions are defined in the companion object List in the same file
object List
I wrote foldLeft and foldRight as the following
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}
def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
There's an exercise on the book, which is to implement foldLeft using foldRight. Here's my initial implementation
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)((a: A, b: B) => f(b, a))
}
Then I think I should write another function to do the reverse arguments if I'm to implement foldRight using foldLeft. As follows:
def reverseArgs[A,B](f: (A, B) => B): (B, A) => B = {
(b: B, a: A) => f(a, b)
}
So I changed code of foldLeftWithRight to the following:
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)(reverseArgs(f))
}
And IntelliJ is complaining about reverseArgs(f):
Type mismatch: expected (A, B) => B, actual (B, B) => B
When I try to compile the code, the error is the following:
Error:(21, 37) type mismatch;
found : (B, A) => B
required: (B, Any) => Any
foldRight(l, z)(reverseArgs(f))
An interesting observation is that when I use the reverseArgs on foldRightWithLeft, there's no problem at all:
def foldRightWithLeft[A,B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, z)(reverseArgs(f))
}
What is going on here?
If you rename type parameters of your reverseArgs function to X and Y, you'll get something like
def reverseArgs[X ,Y](f: (X, Y) => Y): (Y, X) => Y = ???
Type of f in foldLeftWithRight is (B, A) => B. Passing that to reverseArgs means that:
X = B
Y = A
Y = B
I guess Intellij infers from here that A = B and this is why it's complaining that (B, B) => B isn't (A, B) => B. Scalac decides that Y = Any instead, because it's the least upper bound of two potentially unrelated types.
Good solution here is to generalize more. Return type of reversed function does not have to be one of parameter types, so you can introduce another generic type for that:
def reverseArgs[X ,Y, Z](f: (X, Y) => Z): (Y, X) => Z = {
(b: Y, a: X) => f(a, b)
}

Scala: check combination of two variables

I want to check if two variables taken in any order can be paired into a specific pair. Basically the below, only it doesn't work because of type erasure at runtime
def combination[A,B](x: Any, y: Any): Option[(A, B)] =
(x, y) match {
case (a: A, b: B) => Some(a, b)
case (b: B, a: A) => Some(a, b)
case _ => None
Is there another way to do the same which would work...
Note, since it wasn't clear in your message, if you want to pattern-match against a pair of constants (a, b), you may want to consider back-ticks instead of what you're doing :
case (`a`, `b`) => Some(a, b)
On the other hand if you are trying to retrieve the elements of a pair of any values of type (A, B), in any order, you can do it for non-primitive types (i.e. subtypes of AnyRef) :
import scala.reflect.ClassTag
def combination[A, B](x: AnyRef, y: AnyRef)(implicit tagA: ClassTag[A], tagB: ClassTag[B]): Option[(A, B)] = (x, y) match {
case (a: A, b: B) => Some(a, b)
case (b: B, a: A) => Some(a, b)
case _ => None
}

Convert expression to polish notation in Scala

I would like to convert an expression such as: a.meth(b) to a function of type (A, B) => C that performs that exact computation.
My best attempt so far was along these lines:
def polish[A, B, C](symb: String): (A, B) => C = { (a, b) =>
// reflectively check if "symb" is a method defined on a
// if so, reflectively call symb, passing b
}
And then use it like this:
def flip[A, B, C](f : (A, B) => C): (B, A) => C = {(b, a) => f(a,b)}
val op = flip(polish("::"))
def reverse[A](l: List[A]): List[A] = l reduceLeft op
As you can pretty much see, it is quite ugly and you have to do a lot of type checking "manually".
Is there an alternative ?
You can achieve it easily with plain old subtype polymorphism. Just declare interface
trait Iface[B, C] {
def meth(b: B): C
}
Then you could implement polish easily
def polish[B, C](f: (Iface[B, C], B) => C): (Iface[B, C], B) => C = { (a, b) =>
f(a, b)
}
Using it is completely typesafe
object IfaceImpl extends Iface[String, String] {
override def meth(b: String): String = b.reverse
}
polish((a: Iface[String, String], b: String) => a meth b)(IfaceImpl, "hello")
Update:
Actually, you could achieve it using closures only
def polish[A, B, C](f: (A, B) => C): (A, B) => C = f
class Foo {
def meth(b: String): String = b.reverse
}
polish((_: Foo) meth (_: String))(new Foo, "hello")
Or without helper function at all :)
val polish = identity _ // Magic at work
((_: Foo) meth (_: String))(new Foo, "hello")