I have a function def f(a: Int, b: Int, c: Int, d: Int, ...) and I'd like to supply a list of consecutive integers as parameters (in a unit test).
Is there a neat way to supply (1 to N).toList to f? Since the function is not def f(x: Int*) I cannot simply use list: _* with list the list of integers.
I don't think you can do it in standard Scala in a typesafe way, but it's possible to do it using the Shapeless library. Even if you don't use this library in the project, you can depend on it only for the test scope.
Here is the code sample:
import shapeless._
import shapeless.ops.function._
import shapeless.ops.traversable._
def applyToList[F, HL <: HList, R](f: F)(args: List[Any])(implicit
// convert `(T1, T2, ...) => R` to a function from a single HList argument `HL => R`
fnToProduct: FnToProduct.Aux[F, HL => R],
// convert the argument list to the HList, expected by the converted function
toHList: FromTraversable[HL]
): R = {
toHList(args) match {
case Some(hargs) => fnToProduct(f)(hargs)
case None => sys.error("argument list not applicable to function")
}
}
Using it is as simple as this:
def f(a: Int, b: Int, c: Int, d: Int): Any = ???
applyToList(f _)(List(1, 2, 3, 4))
But notice the need for an explicit eta-conversion f _, because the Scala compiler doesn't really know, that F is a function.
You can change the definition to return Option[R], because it's impossible to know at compile-time if the provided List will fit the function or not. For example, the argument list may have a non-matching number of elements. But if this is for unit-tests, you may as well just throw an exception.
If you can't modify f() then you're kinda stuck. One (not terrific) thing you could do is write an implicit translator.
Let's pretend that f() takes 4 Int args.
implicit class Caller4[A,R](func: (A,A,A,A)=>R) {
def call(as :A*) :R = func(as(0),as(1),as(2),as(3))
}
(f _).call(1 to 4:_*) //call f(1,2,3,4)
The good new is that this will work for any/all methods that take 4 parameters of the same type.
The bad news is that you need a different translator for every required arity, and the compiler won't catch it if you invoke call() with too few parameters.
Related
Since Scala 2.12 (or is it 2.13, can't be sure), the compiler can infer latent type arguments across multiple methods:
def commutative[
A,
B
]: ((A, B) => (B, A)) = {???} // implementing omitted
val a = (1 -> "a")
val b = commutative.apply(a)
The last line successfully inferred A = Int, B = String, unfortunately, this requires an instance a: (Int, String) to be given.
Now I'd like to twist this API for a bit and define the following function:
def findApplicable[T](fn: Any => Any)
Such that findApplicable[(Int, String)](commutative) automatically generate the correct function specialised for A = Int, B = String. Is there a way to do it within the language's capability? Or I'll have to upgrade to scala 3 to do this?
UPDATE 1 it should be noted that the output of commutative can be any type, not necessarily a Function2, e.g. I've tried the following definition:
trait SummonedFn[-I, +O] extends (I => O) {
final def summon[II <: I]: this.type = this
}
Then redefine commutative to use it:
def commutative[
A,
B
]: SummonedFn[(A, B), (B, A)] = {???} // implementing omitted
val b = commutative.summon[(Int, String)]
Oops, this doesn't work, type parameters don't get equal treatment like value parameters
If at some point some call-site knows the types of arguments (they aren't actually Any => Any) it is doable using type classes:
trait Commutative[In, Out] {
def swap(in: In): Out
}
object Commutative {
def swap[In, Out](in: In)(implicit c: Commutative[In, Out]): Out =
c.swap(in)
implicit def tuple2[A, B]: Commutative[(A, B), (B, A)] =
in => in.swap
}
At call site:
def use[In, Out](ins: List[In])(implicit c: Commutative[In, Out]): List[Out] =
ins.map(Commutative.swap(_))
However, this way you have to pass both In as well as Out as type parameters. If there are multiple possible Outs for a single In type, then there is not much you can do.
But if you want to have Input type => Output type implication, you can use dependent types:
trait Commutative[In] {
type Out
def swap(in: In): Out
}
object Commutative {
// help us transform dependent types back into generics
type Aux[In, Out0] = Commutative[In] { type Out = Out0 }
def swap[In](in: In)(implicit c: Commutative[In]): c.Out =
c.swap(in)
implicit def tuple2[A, B]: Commutative.Aux[(A, B), (B, A)] =
in => in.swap
}
Call site:
// This code is similar to the original code, but when the compiler
// will be looking for In it will automatically figure Out.
def use[In, Out](ins: List[In])(implicit c: Commutative.Aux[In, Out]): List[Out] =
ins.map(Commutative.swap(_))
// Alternatively, without Aux pattern:
def use2[In](ins: List[In])(implicit c: Commutative[In]): List[c.Out] =
ins.map(Commutative.swap(_))
def printMapped(list: List[(Int, String)]): Unit =
println(list)
// The call site that knows the input and provides implicit
// will also know the exact Out type.
printMapped(use(List("a" -> 1, "b" -> 2)))
printMapped(use2(List("a" -> 1, "b" -> 2)))
That's how you can solve the issue when you know the exact input type. If you don't know it... then you cannot use compiler (neither in Scala 2 nor in Scala 3) to generate this behavior as you have to implement this functionality using some runtime reflection, e.g. checking types using isInstanceOf, casting to some assumed types and then running predefined behavior etc.
I'm not sure I understand the question 100%, but it seems like you want to do some kind of advanced partial type application. Usually you can achieve such an API by introducing an intermediary class. And to preserve as much type information as possible you can use a method with a dependent return type.
class FindApplicablePartial[A] {
def apply[B](fn: A => B): fn.type = fn
}
def findApplicable[A] = new FindApplicablePartial[A]
scala> def result = findApplicable[(Int, String)](commutative)
def result: SummonedFn[(Int, String),(String, Int)]
And actually in this case since findApplicable itself doesn't care about type B (i.e. B doesn't have a context bound or other uses), you don't even need the intermediary class, but can use a wildcard/existential type instead:
def findApplicable[A](fn: A => _): fn.type = fn
This works just as well.
def weirdfunc(message: String, f: (Int, Int) => Int){
println(message + s" ${f(3,5)}")
}
I have the function as above. How do I make it so that the function f is generic for all Numeric types?
What you want is called a higher-ranked type (specifically, rank 2). Haskell has support for these types, and Scala gets a lot of its type theory ideas from Haskell, but Scala has yet to directly support this particular feature.
Now, the thing is, with a bit of black magic, we can get Scala to do what you want, but the syntax is... not pretty. In Scala, functions are always monomorphic, but you want to pass a polymorphic function around as an argument. We can't do that, but we can pass a polymorphic function-like object around that looks and behaves mostly like a function. What would this object look like?
trait NumFunc {
def apply[A : Numeric](a: A, b: A): A
}
It's just a trait that defines a polymorphic apply. Now we can define the function that you really want.
def weirdfunc(message: String, f: NumFunc) = ???
The trouble here, as I mentioned, is that the syntax is really quite atrocious. To call this, we can't just pass in a function anymore. We have to create a NumFunc and pass that in. Essentially, from a type theoretic perspective, we have to prove to the compiler that our function works for all numeric A. For instance, to call the simple weirdfunc that only takes integers and pass the addition function is very simple.
weirdfunc("Some message", (_ + _))
However, to call our "special" weirdfunc that works for all number types, we have to write this mess.
weirdfunc("Hi", new NumFunc {
override def apply[A : Numeric](a: A, b: A): A = {
import math.Numeric.Implicits._
a + b
}
})
And we can't hide that away with an implicit conversion because, as I alluded to earlier, functions are monomorphic, so any conversion coming out a function type is going to be monomorphic.
Bottom line. Is it possible? Yes. Is it worth the costs in terms of readability and usability? Probably not.
Scala has a typeclass for this, so it's quite easy to achieve using a context bound and the standard lib.
def weirdfunc[T: Numeric](message: String, x: T, y: T, f: (T, T) => T) {
println(message + s" ${f(x, y)}")
}
def test[T](a: T, b: T)(implicit ev: Numeric[T]): T = ev.plus(a, b)
weirdFunc[Int]("The sum is ", 3, 5, test)
// The sum is 8
Sorry cktang you cannot generify this. The caller gets to set the generic parameter.. not the called function.. just like the caller passes function parameters.
However you can use currying so that you pass the 'f' of type Int once, and then pass different Int pairs. Then you may pass 'f' of type Double, and pass different Double pairs.
def weirdfunc[A](message: String, f: (A, A) => A)(x: A, y: A){
println(message + s" ${f(x, y)}")
}
def g(x: Int, y: Int): Int = x * y
val wierdfuncWithF = weirdfunc("hello", g) _
wierdfuncWithF(3, 5)
wierdfuncWithF(2, 3)
In particular what you want cannot be done as it will break generics rules.
I have defined an abstract base class like following:
abstract class Base() {
val somevariables
}
And then, I extend this class like following:
case class Derived (a: SomeOtherClass, i: Int) extends Base {
//Do something with a
}
Then, I have a method (independent of classes) that is as follows:
def myMethod (v1: Base, v2: Base, f:(Base, Base) => Int ): Int
And I want to use the above method as myMethod(o1, o2, f1), where
o1, o2 are objects of type Derived
f1 is as follows def f1(v1: Derived, v2: Derived): Int
Now, this gives me an error because myMethod expects the function f1 to be (Base, Base) => Int, and not (Derived, Derived) => Int. However, if I change the definition of f1 to (Base, Base) => Int, then it gives me an error because internally I want to use some variable from SomeOtherClass, an argument that Base does not have.
You should use type parameters to make sure that the types in myMethod line up correctly.
def myMethod[B <: Base](v1: B, v2: B)(f: (B, B) => Int): Int
Or perhaps a bit more general:
def myMethod[B <: Base, A >: B](v1: B, v2: B)(f: (A, A) => Int): Int
If you want to be able to use function f1 where function f2 is expected, f1 must either be of the same type (both input parameters and return value) or a subclass of f2. Liskov Substitution Principle teaches us that for one function to be a subclass of another, it needs to require less (or same) and provide more (or same).
So if you have a method that as a parameter takes a function of type (Fruit, Fruit) => Fruit, here are types for some valid functions that you can pass to that method:
(Fruit, Fruit) => Fruit
(Fruit, Fruit) => Apple
(Any, Any) => Fruit
(Any, Any) => Apple
This relates to covariance/contravariance rule; for example, every one-parameter function in Scala is a trait with two type parameters, Function2[-S, +T]. You can see that it is contravariant in its parameter type and covariant in its return type - requires S or less ("less" because it's more general, so we lose information) and provides T or more ("more" because it's more specific, so we get more information).
This brings us to your problem. If you had things the other way around, trying to fit (Base, Base) => Int in the place where (Derived, Derived) => Int is expected, that would work. Method myMethod obviously expects to be feeding this function with values of type Derived, and a function that takes values of type Base will happily accept those; after all, Derived is a Base. Basically what myMethod is saying is: "I need a function that can handle Deriveds", and any function that knows how to work with Bases can also take any of its subclasses, including Derived.
Other people have pointed out that you can set the type of function f's parameters to a subtype of Base, but at some point you will probably want to use v1 and v2 with that function, and then you will need to revert to downcasting via pattern matching. If you're fine with that, that you can also just pattern match on the function directly, trying to figure out what's its true nature. Either way, pattern matching sucks in this case because you will need to fiddle around myMethod every time a new type is introduced.
Here is how you can solve it more elegantly with type classes:
trait Base[T] {
def f(t1: T, t2: T): Int
}
case class Shape()
case class Derived()
object Base {
implicit val BaseDerived = new Base[Derived] {
def f(s1: Derived, s2: Derived): Int = ??? // some calculation
}
implicit val BaseShape = new Base[Shape] {
def f(s1: Shape, s2: Shape): Int = ??? // some calculation
}
// implementations for other types
}
def myMethod[T: Base](v1: T, v2: T): Int = {
// some logic
// now let's use f(), without knowing what T is:
implicitly[Base[T]].f
// some other stuff
}
myMethod(Shape(), Shape())
What happens here is that myMethod says: "I need two values of some type T and I need to have an implicit Base[T] available in scope (that's the [T: Base] part, which is a fancy way of saying that you need an implicit parameter of type Base[T]; that way you would access it by its name, and this way you access it via implicitly). Then I know I will have f() available which performs the needed logic". And since the logic can have different implementation based on the type, this is a case of ad-hoc polymorphism and type classes are a great way of dealing with that.
What's cool here is that when a new type is introduced that has its own implementation of f, you just need to put this implementation in the Base companion object as an implicit value, so that it's available to myMethod. Method myMethod itself remains unchanged.
According to my (very simple) tests, this change...
def myMethod[B <: Base](v1: Base, v2: Base, f:(B, B) => Int ): Int = ???
...will allow either of these methods...
def f1(a: Derived, b:Derived): Int = ???
def f2(a: Base, b:Base): Int = ???
...to be accepted as a passed parameter.
myMethod(Derived(x,1), Derived(x,2), f1)
myMethod(Derived(x,1), Derived(x,2), f2)
I am trying to write a generic weighted average function.
I want to relax the requirements on the values and the weights being of the same type. ie, I want to support sequences of say: (value:Float,weight:Int) and (value:Int,weight:Float) arguments and not just: (value:Int,weight:Int)
To do so, I first need to implement a function that takes two generic numerical values and returns their product.
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}
Writing the signature and thinking about the return type, made me realise that I need to define some sort of hierarchy for Numerics to determine the return type. ie x:Float*y:Int=z:Float, x:Float*y:Double=z:Double.
Now, Numeric class defines operations plus, times, etc. only for arguments of the same type. I think I would need to implement a type:
class NumericConverter[Numeirc[A],Numeric[B]]{
type BiggerType=???
}
so that I can write my times function as:
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) :
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...}
and convert the "smaller type" to the "bigger one" and feed it to times().
Am I on the right track? How would I "implement" the BiggerType?
clearly I can't do something like:
type myType = if(...) Int else Float
as that is evaluated dynamically, so it worn't work.
I understand that I might be able to do this Using Scalaz, etc. but this is an academic exercise and I want to understand how to write a function that statically returns a type based on the argument types.
Feel free to let me know if there is a whole easier way of doing this.
update:
this is what I came up with it.
abstract class NumericsConvert[A: Numeric,B: Numeric]{
def AisBiggerThanB: Boolean
def timesA=new PartialFunction[(A,B), A] {
override def isDefinedAt(x: (A, B)): Boolean = AisBiggerThanB
override def apply(x: (A, B)): A = implicitly[Numeric[A]].times(x._1, x._2.asInstanceOf[A])
}
def timesB=new PartialFunction[(A,B), B] {
override def isDefinedAt(x: (A, B)): Boolean = !AisBiggerThanB
override def apply(x: (A, B)): B = implicitly[Numeric[B]].times(x._1.asInstanceOf[B], x._2)
}
def times: PartialFunction[(A, B), Any] = timesA orElse timesB
}
def times[A: Numeric, B: Numeric](x: B, y: A)= implicitly[NumericsConvert[A,B]].times(x,y)
which is silly as I will have to create implicits for both
IntDouble extends NumericsConvert[Int,Double]
and
DoubleInt extends NumericsConvert[Double,Int]
not to mention that the return type of times is now Any, but regardless, I am getting errors for my times functions. I thought I would add it here in case it might help with arriving at a solution. so side question: how I can pass context bound types of one class/function to another like I am trying to do in times.
I think you're making this harder than it needs to be.
You need "evidence" that both parameters are Numeric. With that established let the evidence do the work. Scala will employ numeric widening so that the result is the more general of the two received types.
def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T =
ev.times(a,b)
If you want to get a little fancier you can pull in the required implicits. Then it's a little easier to read and understand.
def mult[T: Numeric](a: T, b: T): T = {
import Numeric.Implicits._
a * b
}
Proof:
mult(2.3f , 7) //res0: Float = 16.1
mult(8, 2.1) //res1: Double = 16.8
mult(3, 2) //res2: Int = 6
For more on generic types and numeric widening, this question, and its answer, are worth studying.
There is a Wrapper class for arbitrary functions. I tried to abstract the input and output (return value) of the function with the two type parameters [I, O] (for input and output).
class Wrapper[I, O](protected val f: I => O {
protected def doIt(input: I): O = f(input)
}
As this should be a wrapper for arbitrary functions, I have a problem with functions that take multiple parameters.
val multiplyFunction = (a: Int, b: Int) => a * b
val multiplyWrapper = new Wrapper[(Int, Int), Int](multiplyFunction)
The second line does not compile, because the wrapper expects a function which takes a Tuple with two Ints as the only parameter.
Is there a way to rewrite this, so that I can abstract the function's parameters no matter how many parameters there are? Ideally the solution would be type safe, by the compiler.
Maybe I there is an alternative to using a tuple to specify the types for the wrapper when creating an instance it.
I hope I don't have to write it like the Tuple classe Tuple2 to TupleN or Function2 to FunctionN. I don't know all the details about this, but that does look more like a workaround and is not a abstract / generic solution.
You could use tupled method on function: new Wrapper(multiplyFunction.tupled).
If you want to make this transparent to the wrapper class's user you could use duck typing:
object Wrapper {
def apply[I, O](e: { def tupled: I => O }) = new Wrapper(e.tupled)
def apply[I, O](e: I => O) = new Wrapper(e)
}
scala> Wrapper( (a: Int) => a )
res0: Wrapper[Int,Int] = Wrapper#29d03e78
scala> Wrapper( (a: Int, b: Int) => a * b )
res1: Wrapper[(Int, Int),Int] = Wrapper#581cdfc2
You'll get some overhead due to reflection.