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.
Related
This code :
def compose[A, B, C](f: B => C, g: A => B): A => C =
a => f(g(a)) //> compose: [A, B, C](f: B => C, g: A => B)A => C
def f(a : Int) = a + 1 //> f: (a: Int)Int
def g(a : Int) = a + 1 //> g: (a: Int)Int
compose[Int,Int,Int](f(1) , g(1))
causes compiler error :
Multiple markers at this line - type mismatch; found : Int required: Int => Int - type mismatch; found : Int
required: Int => Int
But since f and g are functions which take an Int and return an Int, does this not match function definition of f: B => C as B & C will be typed to an Int ?
You should compose functions (you're composing Ints).
As a result you get another function which is the composition.
Then you can pass the parameter to the composed function.
compose[Int,Int,Int](f , g)(1)
BTW, there's a compose (and andThen) method in Scala
(f _).compose(g)(1)
https://twitter.github.io/scala_school/pattern-matching-and-functional-composition.html
I tried running the below code:
val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
found in this thread in the REPL and IntellijIDEA but it's apparently invalid.
From the REPL:
scala> val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
<console>:1: error: ')' expected but ':' found.
val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
^
Anyone knows why? My scala version is 2.10.1
Thank you
You write the type as if you were writing:
val a: 5 = 5
What you want is more like
val f = (a: Int) => (b: Int) => (c: Int) => a+b+c
To elaborate further the REPL will write
f: Int => (Int => (Int => Int)) = <function1>
Because function definition is right associative you could the type of f explicitly as follows
f: Int => Int => Int => Int = (a: Int) => (b: Int) => (c: Int) => a+b+c
If you explicitly give the function type like this the compiler does not need information about what a,b, and c are and you could simply write a => b => c => a+b+c instead.
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 )
Here's my function:
def partial1[A, B, C](a: A, f: (A, B) => C): B => C = (b: B) => f(a, b)
> partial1: [A, B, C](a: A, f: (A, B) => C)B => C
Here I invoke the function partial1:
def fun(a: Int, b: Int) = a + b
> fun: (a: Int, b: Int)Int
val r = partial1(1, fun)
> r : Int => Int = <function1>
r(fun(1,3))
> res0: Int = 5
So r is a function which takes a function as parameter and returns a Function1 (a function with 1 parameter). Should Int => Int not be Int, Int since two Ints are the function parameters?
Why can't I implement Partial1 like partial1(1,(fun(1,3))) which causes compiler error : type mismatch; found : Int required: (?, ?) => ? ?
First of all, partial1 isn't a partial function. It's a function that returns another function so it's a higher-order function.
The compile error you're getting is because partial1 expects a function (A, B) => C, but you're passing fun(1,3), which evaluates to an Int. And Int is not the same as (Int, Int) => Int.
class ex03 {
def partial1[A,B,C](a:A, f:(A,B) => C): B => C = f(a,_)
}
class ex03Test extends UnitSpec {
behavior of "partial1"
it should "return 6" in {
val e = new ex03
val multiplyByTwo = e.partial1(2, (a:Int, b:Int) => a * b)
multiplyByTwo(3) mustBe 6
}}
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].