Scala extractors - skip unused parameters - scala

given following code:
abstract class MyTuple
...
case class MySeptet(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int) extends MyTuple
case class MyOctet(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int) extends MyTuple
...
When using generated extractor, is it possible to skip remaining parameters, supposing they're unused ?
e.g. I don't want to write plenty of underscores in the following code snippet:
case MyOctet(a, b, _, _, _, _, _, _) => ... // uses only a and b

A simple approach to providing extractors for tupled classes that relies in fact in Array extractors, hence bypassing the original problem.
Let
abstract class MyTuple (order: Int)
case class MySeptet(coord: Array[Int]) extends MyTuple(7)
case class MyOctet(coord: Array[Int]) extends MyTuple(8)
and so for
val o = MyOctet( (1 to 8).toArray )
we can extract the first two elements in an octet like this,
o match {
case MyOctet( Array(a,b,_*) ) => a+b
case _ => 0
}
res: Int = 3
Note this does not address the problem of skipping remaining parameters in the case classes defined above.
Also note a weakness of this approach, illustrated as follows,
scala> val Array(a,b) = Array(1)
scala.MatchError: [I#16a75c0 (of class [I)

case o: MyOctet => o.a + o.b

Related

How to annotate a parameter as implicit in pattern match while extracting values

I have a class like
case class A(a: Int, b: String)
and a function
def f(a: Int)(implicit b: String) =???
Is it possible to do something like this?
val a = A(11, "hello")
a match {
case A(a, implicit b) => f(a)
}
How can I make the parameter b implicit without explicitly declaring it after extraction.
I wouldn't worry about passing the argument implicitly, since you can easily provide it explicitly in this particular case:
case class A(a: Int, b: String)
def f(a: Int)(implicit b: String) =???
val a = A(11, "hello")
a match {
case A(a, b) => f(a)(b)
}
If you must pass the value implicitly, it needs to be declared in scope. For example:
a match {
case A(a, b) => {
implicit val s = b
f(a)
}
}
Also, as has been pointed out, don't use implicit with a common type. It's better if you wrap it in another class:
case class A(a: Int, b: String)
case class SomeCustomString(s: String)
def f(a: Int)(implicit b: SomeCustomString) =???
val a = A(11, "hello")
a match {
case A(a, b) => {
implicit val s = SomeCustomString(b)
f(a)
}
}
If you could explain the use case for the implicit argument, I could provide a better example.
Update: There is a kind of way to do what you want:
case class SomeCustomString(s: String)
case class A(a: Int, b: String) {
implicit val s = SomeCustomString(b)
}
def f(a: Int)(implicit s: SomeCustomString) =???
val a = A(11, "hello")
import a._
f(a.a)
Or, if you must have it within a pattern match, that last bit would be:
a match {
case x: A => {
import x._
f(x.a)
}
}
Update 2: Or, as yet another approach (again, with implicit largely redundant):
case class SomeCustomString(s: String)
case class A(a: Int, b: String) {
implicit val s = SomeCustomString(b)
def invokeF = f(a)
}
def f(a: Int)(implicit s: SomeCustomString) =???
val a = A(11, "hello")
a.invokeF
or
a match {
case x: A => x.invokeF
}
Does that help?

Passing in An Operator as a Parameter

I'm doing an exercise in "Scala for the Impatient", Chapter 14, Q8:
Essentially I need to create a function (utilizing pattern matching) that takes in an operator and nodes, and it outputs the result of the operation. E.G. Node(+, Node(*, Leaf(2), Leaf(3)) Leaf(1)) should output 7.
Here are some of the given classes:
sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree
So I create a Node class, but I'm having difficulties figuring out how to pass in the operator.
case class Node(op: Function (what goes here?) , leaves: BinaryTree*) extends BinaryTree
I want to use pattern matching like so:
tree match {
case Node(op, leaves # _*) => op match {
case op : Function => leaves.reduceLeft(_ op _)
}
case leaf: Leaf => leaf.value
But the
case op : Function => leaves.reduceLeft(_ op _)
part is wrong. I don't know how to use the operator that's being passed in the Node class. What am I doing wrong here?
I am assuming the operator will be always going to be binary hence, our So called BinaryTree will have atleast two operands :
trait BinaryTree
case class Leaf(value: Int) extends BinaryTree
case class Node(op: Function2[Int, Int, Int], l1: BinaryTree*) extends BinaryTree
object Operators {
val + = (a: Int, b: Int) => a + b
val * = (a: Int, b: Int) => a * b
}
def f(tree: BinaryTree): Int = {
tree match {
case n: Node => n.l1.map(f).reduceLeft((r,c) => n.op(r,c))
case leaf: Leaf => leaf.value
}
}
Some test results:
Simple one:
scala> f(Node(Operators.*,Leaf(4),Leaf(2),Leaf(3)))
res4: Int = 24
scala> f(Node(Operators.+,
Node(Operators.*, Leaf(2), Leaf(1), Leaf(4), Leaf(5)), Leaf(6)))
res5: Int = 46
scala> f(Node(Operators.+,
Node(Operators.*, Leaf(2), Leaf(1), Leaf(4), Leaf(5)),
Node(Operators.+,Leaf(9),Leaf(9)), Leaf(6)))
res6: Int = 64
Quite complex:
scala> f(Node(Operators.+,
Node(Operators.*, Leaf(2), Leaf(1),
Node(Operators.* ,Leaf(4), Leaf(5) ,Leaf(2))),
Node(Operators.+,Leaf(9),Leaf(9)), Leaf(6),
Node(Operators.*, Leaf(2), Leaf(2))))
res7: Int = 108
It has more elegant solutions, but since you want it with pattern matching:
sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree
case class Node(op: (Int, Int) => Int , leaves: BinaryTree*) extends BinaryTree
def calc(tree: BinaryTree): Int = tree match {
case Leaf(v) => v
case Node(op, h, leaves # _*) => leaves.foldLeft(calc(h))((a,b) => op(a,calc(b)))
}
object Operators {
def +(a: Int, b: Int): Int = a + b
def *(a: Int, b: Int): Int = a * b
}
val tree = Node(Operators.+, Node(Operators.*, Leaf(9), Leaf(3)), Leaf(1))
calc(tree)

Scala - tupled and partially applied functions

I'm fairly new to Scala and functional programming in general so I'm having a bit trouble wrapping my head around the concept of partially applied functions and function currying. There's also a pretty high chance that I'm gonna mix up some terminology, so all corrections are appreciated.
Note: I'm using the Scala Play framework but this is more of a Scala problem than a Play problem.
Given a function like this
def create(id: Long, userId: Long, label: String)
I get the userId and label as a (Int, String) tuple and the id as a Long. Basically what I'm trying to do is passing the id and the tuple to the function at the same time.
Now, I've read that passing a tuple to a function can be done something like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> (f _).tupled((2, "Hello"))
res0: Int = 0
and that it is also possible to partially apply a function like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> val ff = f(_: Int, "Hello")
ff: Int => Int = <function1>
scala> ff(2)
res1: Int = 0
So my initial idea was to combine these two concepts something like this
scala> def g(a: Long, b: Int, c: String) = 0
g: (a: Long, b: Int, c: String)Int
scala> val h = g(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> (h _).tupled((2, "Hello"))
However this results in an error
<console>:10: error: _ must follow method; cannot follow h.type
(h _).tupled((1, "Hello"))
^
So my question is first of all why doesn't this work because to me this makes sense. And secondly how would I go about achieving this effect?
Thanks for your help!
Just don't abstract it twice: don't do redundand underscore to the h as it's already a function after partial-applying:
scala> def create(a: Long, b: Int, c: String) = 0
create: (a: Long, b: Int, c: String)Int
scala> val h = create(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> h.tupled((1, "Hello"))
res0: Int = 0
More deeply, tupled is defined on functions (means object of Function, like Int => String), not on methods (like def f(i: Int): String) - so sometimes you need to convert a method to the function - it's called eta-expansion (or eta-abstraction more generally). When you do partial applying - eta-expansion is done automatically (you already have a (Int, String) => Int) - so you don't have to do it twice.
See The differences between underscore usage in these scala's methods, Difference between method and function in Scala for more information.

Can individual case statements have type parameters? If so, how?

I'm trying to write a function that takes a String, calls a 3rd party library twice and if the results happen to be the same type and that type is Ordered, to compare the items based on the string. For example (that doesn't compile but hopefully conveys what I mean):
def libraryFunction(i: Int): AnyRef // this is somewhere else
def comp(c: String): Boolean = {
val aa = libraryFunction(0)
val bb = libraryFunction(1)
(c, aa, bb) match {
case [A <: Ordered[A]]("<", a: A, b: A) => a < b
case [A <: Ordered[A]](">", a: A, b: A) => a > b
....
}
}
A naive solution would be to simply enumerate all the types I care about:
def comp(c: String): Boolean = {
val aa = libraryFunction(0)
val bb = libraryFunction(1)
(c, aa, bb) match {
case ("<", a: Int, b: Int) => a < b
case (">", a: Int, b: Int) => a > b
case ("=", a: Int, b: Int) => a == b
case ("<", a: Double, b: Double) => a < b
....
}
}
But that seems like a ton of redundant code (I'm using squants to track units, so there's more than just int and double to worry about) that I'd like to avoid if possible.
Is there some way to do this? Or even a more formal way of asking the question such that searching would be more fruitful?
Edit: my initial attempt to hide some of the complexity seems to have been poorly executed, refactoring to expose relevant details.
You need to make you BlackBox type parametrized.
case class BlackBox[T](l: T, r: T)
def comp[A: Ordering](c: String, d: BlackBox[A]): Boolean = (c, d) match {
case ("<", BlackBox(a, b)) => implicitly[Ordering[A]].lt(a, b)
case (">", BlackBox(a, b)) => implicitly[Ordering[A]].gt(a, b)
}
println(comp(">", BlackBox(1, 2)))
println(comp(">", BlackBox(1.5, 2.5)))
I don't think that you can do it without type-parametrization. If you don't have types at compile type you have no chances to get Ordered implicit instance. Implicit resolution is compile time operation.

How to compose to methods, without duplicate input arguments

Suppose I have two methods
scala> def a(a: Int, b: Int, c: Int) : Int = …
a: (a: Int, b: Int, c: Int)Int
scala> def b(i: Int) : Int = …
b: (i: Int)Int
How to define a method c, that is the composition of both ?
Unfortunately, the following code doen't compile :
def c = b(a)
You could convert method a to function and then use method andThen like this:
def a(a: Int, b: Int, c: Int) : Int = a + b + c
def b(i: Int) : Int = i * 2
val c = (a _).tupled andThen b
c(1, 1, 1)
// 6
Note that I have to convert function (Int, Int, Int) => Int to tupled version - ((Int, Int, Int)) => Int - here to use andThen. So result function c accepts Tuple3 as argument.
You could convert c to untupled version ((Int, Int, Int) => Int) using Function.untupled:
val untupledC = Function.untupled(c)
untupledC(1, 1, 1)
// 6
shapeless
There is no untupled method for function arity > 5.
You could also use shapeless toProduct/fromProduct methods for any arity like this:
import shapeless.ops.function._
import shapeless.ops.function._
val c = (a _).toProduct.andThen(b).fromProduct
Scalaz defines Functor instances for higher-arity functions, so you can just write
(a _).map(b)