I'm learning Scala and have the following toy code:
object M {
def isSorted[X](xs: Array[X], compare: (X, X) => Boolean): Boolean =
xs.dropRight(1).zip(xs.drop(1)).forall(Function.tupled(compare))
def curry[A,B,C](f: (A, B) => C) : A => (B => C) =
(a) => (b) => f(a, b)
}
My goal is to call it like:
M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
But I receive the error:
scala> M.curry(M.isSorted)(Array(1,2,3))
<console>:8: error: type mismatch;
found : Int(1)
required: Nothing
M.curry(M.isSorted)(Array(1,2,3))
Let's back up and look at the type of the curried function:
scala> M.curry(M.isSorted)
res2: Array[Nothing] => (((Nothing, Nothing) => Boolean) => Boolean) = <function1>
That's no good. It wants an Array[Nothing] but there can be no instances of Nothing.
I understand at some point I will need to introduce a constraint so the compiler can prove that the expression a < b is allowable; that is, that a and b are Ordered. But I don't know where I would put the constraint. curry is perfectly generic; the constraint doesn't belong there. isSorted knows nothing about the implementation of compare, so it doesn't belong there either.
The closest I've gotten to having it working is with def isSorted[X >: Any]
scala> M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
<console>:8: error: value < is not a member of Any
M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
^
scala> M.curry(M.isSorted)(Array(1,2,3))((a: Int, b: Int) => a < b)
<console>:8: error: type mismatch;
found : (Int, Int) => Boolean
required: (Any, Any) => Boolean
M.curry(M.isSorted)(Array(1,2,3))((a: Int, b: Int) => a < b)
^
How can I get this working?
object M {
def isSorted[X](xs: Array[X], compare: (X, X) => Boolean): Boolean =
xs.dropRight(1).zip(xs.drop(1)).forall(Function.tupled(compare))
def curry[A,B,C](f: (A, B) => C) : A => (B => C) =
(a) => (b) => f(a, b)
}
Well... I don't think this is the best way to define these functions but in this case, since these are generic functions so you need to provide them with a type when calling.
As #dk14 has pointed out in his comment... M.sorted can not get type info because Scala lacks support for polymorphic lambdas.... which simply means no generics in anonymous functions.
So you need to do this for this particular case.
M.curry( M.isSorted[Int] )( Array(1,2,3) ) ( (a , b) => a < b )
Related
As a part of learning Scala I try to implement Haskell's flip function (a function with signature (A => B => C) => (B => A => C)) in Scala - and implement it as a function (using val) and not as a method (using def).
I can implement it as a method, for instance this way:
def flip[A, B, C](f: (A, B) => C):((B, A) => C) = (b: B, a: A) => f(a, b)
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
However, when I try to implement it as a function, it does not work:
val flip = (f: ((Any, Any) => Any)) => ((a: Any, b: Any) => f(b, a))
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
When I try to compile this code, it fails with this message:
Error:(8, 18) type mismatch;
found : (Int, Int) => Int
required: (Any, Any) => Any
val f = flip(minus)
I understand why it fails: I try to pass (Int, Int) => Int where (Any, Any) => Any is expected. However, I don't know how to fix this problem. Is it possible at all?
Scala doesn't support polymorphic functions, unlike methods which are. This is due to the first class value nature of functions, which are simply instances of the FunctioN traits. These functions are classes, and they need the types to be bound at declaration site.
If we took the flip method and tried to eta expand it to a function, we'd see:
val flipFn = flip _
We'd get back in return a value of type:
((Nothing, Nothing) => Nothing) => (Nothing, Nothing) => Nothing
Due to the fact that none of the types were bound, hence the compiler resorts to the buttom type Nothing.
However, not all hope is lost. There is a library called shapeless which does allow us to define polymorphic functions via PolyN.
We can implement flip like this:
import shapeless.Poly1
object flip extends Poly1 {
implicit def genericCase[A, B, C] = at[(A, B) => C](f => (b: B, a: A) => f(a, b))
}
flip is no different from the FunctionN trait, it defines an apply method which will be called.
We use it like this:
def main(args: Array[String]): Unit = {
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
}
Yielding:
2
This would also work for String:
def main(args: Array[String]): Unit = {
val stringConcat = (a: String, b: String) => a + b
val f = flip(stringConcat)
println(f("hello", "world"))
}
Yielding:
worldhello
I have defined an identity function and a composition function:
def identity[T](x: T): T = x
def composition[A, B, C](f: A => B, g: B => C)(x: A) = g(f(x))
I am trying to assert that the identity function can be applied on both sides with the same result:
assert(composition((x: Int) => x + 1, identity)(3) == composition(identity, (x: Int) => x + 1)(3))
However, I am getting these errors:
Error:(7, 40) type mismatch;
found : Nothing => Nothing
required: Int => Nothing
assert(composition((x: Int) => x + 1, identity)(3) == composition(identity, (x: Int) => x + 1)(3));}
And:
Error:(7, 68) type mismatch;
found : Nothing => Nothing
required: A => Nothing
assert(composition((x: Int) => x + 1, identity)(3) == composition(identity, (x: Int) => x + 1)(3));}
Why is this the case?
This is the case because the compiler is having difficulty inferring the types properly, specifically inferring what A is. You can help him by placing A as the first argument and each function in a separate parameter list:
def composition[A, B, C](x: A)(f: A => B)(g: B => C) = g(f(x))
And now this works as expected:
scala> :pa
// Entering paste mode (ctrl-D to finish)
def identity[T](x: T): T = x
def composition[A, B, C](x: A)(f: A => B)(g: B => C) = g(f(x))
// Exiting paste mode, now interpreting.
identity: [T](x: T)T
composition: [A, B, C](x: A)(f: A => B)(g: B => C)C
scala> println(composition(3)((x: Int) => x + 1)(identity) == composition(3)(identity)((x: Int) => x + 1))
true
Alternatively, you can specify the type parameter explicitly to help the compiler infer the right type:
println(composition((x: Int) => x + 1, identity[Int], 3) ==
composition(identity[Int], (x: Int) => x + 1, 3))
Below should work. Note the type param for the identity function.
assert(composition((x: Int) => x + 1, identity[Int])(3) == composition(identity[Int], (x: Int) => x + 1)(3))
Since you have not specified the type param for the identity function, it becomes Nothing and it does not match with the type signature of your method.
I want to make a sum function that works with all Numeric types.
This works:
object session {
def mapReduce[A](f: A => A, combine: (A, A) => A, zero: A, inc: A)
(a: A,b: A)
(implicit num:Numeric[A]): A = {
def loop(acc: A, a: A) =
if (num.gt(a, b)) acc
else combine(f(a), mapReduce(f, combine, zero, inc)(num.plus(a, inc), b))
loop(zero, a)
}
def sum(f: Int => Int)
(a: Int, b: Int) : Int = {
mapReduce(f, (x: Int, y: Int) => x + y, 0, 1)(a, b)}
sum(x => x)(3, 4) //> res0: Int = 7
def product(f: Int => Int)
(a: Int, b: Int): Int = {
mapReduce(f, (x: Int, y: Int) => x * y, 1, 1)(a, b)}
product(x => x)(3, 4) //> res1: Int = 12
def fact(n: Int) = product(x => x)(1, n)
fact(5) //> res3: Int = 120
}
but when I try to make sum generic like this:
def sum[A](f: A => A)
(a: A, b: A)
(implicit num:Numeric[A]): A = {
mapReduce(f, (x: A, y: A) => num.plus(x, y), 0, 1)(a, b)}
sum(x => x)(3.0, 4.0) // should be 12.0
I get this error on f
type mismatch; found : A => A required: Any => Any
when i pass it to mapReduce. So what do i need to do to make sum accept any Numeric value?
If I'm not mistaken, the other answer is almost correct except for the fact that the type has to be made explicit when calling mapReduce instead of when calling sum.
So in your generic definition of sum, you might want to do this:
def sum[A](f: A => A)(a: A, b: A)(implicit num: Numeric[A]): A =
mapReduce[A](f, num.plus, num.zero, num.one)(a, b)
That's however not enough for the typer to infer the concrete type of A, e.g. Double when calling sum(x => x)(3.0, 4.0). The reason for this is that the typer is going from first to last parameter list, left to right.
Your first parameter list declares f: A => A and only the second parameter list defines (a: A, b: A). Once the typer reaches the end of the first parameter list, it doesn't know what A exactly is, and hence it fixes the type of A to some "abstract" A. The only thing that it knows about A at this point is that it is a subtype of Any.
When the typer then gets to the second parameter list, it could theoretically infer A as Double or whatever your concrete type is, but as said before the type has already been fixed. This is just a flaw of Scala's typer which can easily be circumvented once you get the hang of it.
More precisely, all you have to do is help the typer by switching the first and second parameter lists like so:
def sum[A](a: A, b: A)(f: A => A)(implicit num: Numeric[A]): A =
mapReduce[A](f, num.plus, num.zero, num.one)(a, b)
Then it's possible to call sum without being explicit about the type, e.g.
Console println sum(3.0, 4.0)(x => x) // 7.0
Give the type of sum explicitly. I have already provided an answer to a similar question in
A simple foldRight type issue in Scala.
Questions are totally different but the reason is exactly the same.
I'm working on map3 from Functional Programming in Scala:
// Exercise 3: The apply method is useful for implementing map3, map4, and so on
// and the pattern is straightforward. Implement map3 and map4 using only
// unit, apply, and the curried available on functions.
def map3[A,B,C,D](fa: F[A],
fb: F[B],
fc: F[C])(f: (A, B, C) => D): F[D] = {
def foo: (A => B => C => D) = (f _).curried // compile-time error
def fooF: F[A => B => C => D] = unit(foo)
val x: F[B => C => D] = apply(fooF)(fa)
val y: F[C => D] = apply(x)(fb)
val z: F[D] = apply(y)(fc)
z
}
One(1) compile-time error occurs on the above, noted line:
[error] C:\...\Applicative.scala: _ must follow method; cannot follow f.type
[error] def foo: (A => B => C => D) = (f _).curried
[error]
^
I was able to successfully get the curried version of a function via this post - Using FunctionX#curried.
However, I don't understand the above compile-time error.
The error is because f here is a function, not a method; the f _ syntax is to turn methods into functions, which isn't necessary here. Simply write def foo: A => B => C => D = f.curried.
Dеar Scala,
scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b }
f1: ((Int, Int)) => Int = <function1>
scala> val f2: (Int, Int) => Int = { case (a, b) => a + b }
f2: (Int, Int) => Int = <function2>
huh?!
scala> f1(1, 2)
res2: Int = 3
Ok...
scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200)
takesIntInt2Int: (fun: (Int, Int) => Int)Int
scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200)
takesTuple2Int: (fun: ((Int, Int)) => Int)Int
scala> takesIntInt2Int(f2)
res4: Int = 300
scala> takesIntInt2Int(f1)
<console>:10: error: type mismatch;
found : ((Int, Int)) => Int
required: (Int, Int) => Int
takesIntInt2Int(f1)
^
scala> takesTuple2Int(f1)
res6: Int = 300
scala> takesTuple2Int(f2)
<console>:10: error: type mismatch;
found : (Int, Int) => Int
required: ((Int, Int)) => Int
takesTuple2Int(f2)
Right. And now, look at this!
scala> takesTuple2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesTuple2Int { case (a, b, c) => a + b + c }
^
scala> takesIntInt2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesIntInt2Int { case (a, b, c) => a + b + c }
Like, srsly? o_O Both result in required: (Int, Int) error.
Why then use case at all in such anonymous functions?
See section 8.5 of the Scala reference (http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf). The expression { case (a, b) => a + b } is interpreted differently based on the expected type. In your definition of f1 it created a PartialFunction[(Int, Int), Int] which was cast to a Function1[(Int, Int), Int], i.e. ((Int, Int)) => Int whereas in the definition of f2 it created a Function2[Int, Int, Int], i.e. (Int, Int) => Int.
These two interpretations relate to the two situations where you would commonly use case in an anonymous function.
One is for writing anonymous functions that accept tuples and work on their components, as you did with f1. An example would be the function you pass to the foreach or map method on a Map, e.g. Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }.
The second is for writing an anonymous function that does a match on its sole parameter. Your f2 is doing this, but not in any useful way. An example would be the anonymous function passed to collect, e.g. List(1, -2, 3) collect { case x if x > 0 => -x }.
Note that the two can be combined, that is functions like f1 can do complex matching as well. For example, Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }.
Edit: res2 works because of tupling. If an application doesn't type check, the compiler will try wrapping the args in a tuple before failing.
But that is tried just for applications; it's not a general conversion, as you discovered. It will not try to upgrade a value Function2[A, B, C] to Function1[(A, B), C].