I'm following the excellent Functional Programming in Scala by Paul Chiusano and RĂșnar Bjarnason, and had a question to what I find is odd/unexpected behaviour.
I have defined a foldRight function like so
def foldRight[A,B](l: List[A], z: B)(f: (A,B) => B): B =
l match {
case Nil => z
case x :: xs => f(x, foldRight(xs, z)(f))
}
that works fine as long I pass in concrete arguments, e.g.:
foldRight((1 to 10).toList, 0)(_ + _)
val res6: Int = 55
If I define a similar function that takes the generic list
def sum[A](as: List[A]): Int = foldRight(as, 0)(_ + _)
something odd happens
def sum[A](as: List[A]): Int = foldRight(as, 0)(_ + _)
^
fold.scala:23: error: type mismatch;
found : Int
required: String
Initially, I was super puzzled by this error message given the only types in play are A, B and Int. However, would seem it simply attempts to make sense of + and generic A's by calling .toString on them as I read about here.
If that is the case though, why come it doesn't simply adds a1.toString + a2.toString + ... + an.toString + 0 = something0? String concatenation between String and Int in Scala is fully understood by the compiler.
Hope someone can help clarifying what's happening here.
However, would seem it simply attempts to make sense of + and generic A's by calling .toString
This is not what happens. The result is similar, but it's not calling .toString. You found the underlying problem though.
The sum function operates on a generic A on which you want to call the +method on.
But A doesn't have a + method (Remember that + in infix position is the same as x.+(y)). The compiler then searches the implicit scope for a function or class constructor to convert this A into something that has a + method. It finds it in any2stringadd.
Your method actually looks like
def sum[A](as: List[A]): Int = foldRight(as, 0)(any2Stringadd(_) + _)
Now the error makes sense. Because the + method of the any2Stringadd class expects a string as its argument. But your z argument is of type Int. You can see that, when you explicitly add the types to the inline function argument.
As other pointed out, this is not reconcilable without constraining the type parameter.
As others have said, you can't try to add instances of some type A that you know nothing about, since the Scala compiler gets confused and tries to implicitly turn your A objects into Strings, even though you have 0, which is an Int. However, you can get around this with typeclasses, like this.
trait Sum[T] {
def id: T
def add(_1: T, _2: T): T
}
implicit object IntSum extends Sum[Int] {
def id = 0
def add(i1: Int, i2: Int) = i1 + i2
}
def sum[A](as: List[A])(implicit sum: Sum[A]): A = foldRight(as, sum.id)(sum.add)
Here, IntSum is passed to the sum method implicitly, and its add method is used to sum your list together. You can define as many such implicit objects as you like for Double, String, etc.
Let's name some functions properly by thinking about what they are supposed to do:
def foldRight[A,B](l: List[A], z: B)(f: (A,B) => B): B =
l match {
case Nil => z
case x :: xs => f(x, foldRight(xs, z)(f))
}
def sumInts(numbers: List[Int]): Int = foldRight(numbers, 0)(_ + _)
def concatStrings(strings: List[String]): String = foldRight(strings, "")(_ + _)
def concatStringRepresentations[A](as: List[A]): String = foldRight(as, "")(_ + _)
concatStringRepresentations(List(List(), List(1,2,3), List(0))) // List()List(1, 2, 3)List(0)
concatStringRepresentations(List(1.0, 2.0, 3.0)) // 1.02.03.0
def sumIntRepresentations[A](as: List[A]): Int = foldRight(as, 0)(_ + _)
// --> type mismatch, found: String, required: Int, for second param of (_ + _)
This is what your sum function was probably supposed to be named.
To make it compile, we wish that there is
a method +: Int => Int defined for any type, or...
implicit conversions that convert any type to Int (something like toString with Int), or...
other implicit conversions that make sense, or...
something else, that can make this function succeed and is recognized by the compiler.
It turns out that Any can be implicitly converted to something that has a method +(other: String) => String that makes the String example work, but there is no implicit conversion from Any to something that has a method +(other: Int) => Int.
This could be explained in more detail and other answers already do that.
Opinions:
So, yes, the compiler gives a message that is confusing due to existence of implicit conversions. But let's look at the problem at hand which probably was our wishful thinking. Sometimes stuff just works like in the concatStringRepresentations function. It does not work in general, but in this special case with String it does.
Sometimes something works for a special case. And when we don't see that it is a special case, mistakes can happen, for instance when we apply it to something else.
Related
I'm reading the docs on implicits in Scala, and there is an example of a function with implicit conversion as parameter:
def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)
I understand how it works, but I don't understand what's the point of writing it like that instead of:
def getIndexExplicit[T](seq: Seq[T], value: T) = seq.indexOf(value)
As far as I know, if the conversion from the argument seq to type Seq[T] exists, the compiler would still allow the call to getIndexExplicit?
To illustrate my point, I prepared this simple example:
def equal42[T](a: T)(implicit conv: T => Int) = conv(a) == 42 // implicit parameter version
def equal42Explicit(a: Int) = a == 42 // just use the type in the signature
implicit def strToInt(str: String): Int = java.lang.Integer.parseInt(str) // define the implicit conversion from String to Int
And indeed, both functions seem to work in the same way:
scala> equal42("42")
res12: Boolean = true
scala> equal42Explicit("42")
res13: Boolean = true
If there is no difference, what's the point of explicitly defining the implicit conversion?
My guess is that in this simple case it makes no difference, but there must be some more complex scenarios where it does. What are those?
In your super-simple example:
equal42("42")
equal42Explicit("42")
is equal to
equal42("42")(strToInt)
equal42Explicit(strToInt("42"))
which in case of your definition make no difference.
BUT if it did something else e.g.
def parseCombined[S, T](s1: S, s2: S)
(combine: (S, S) => S)
(implicit parse: S => Option[T]): Option[T] =
parse(combine(s1, s2))
then when you would apply conversion matters:
implicit def lift[T]: T => Option[T] = t => Option(t)
implicit val parseInt: String => Option[Int] = s => scala.util.Try(s.toInt).toOption
implicit def parseToString[T]: T => Option[String] = t => Option(t.toString)
parseCombined[Option[Int], String]("1", "2") { (a, b) => a.zip(b).map { case (x, y) => x + y } } // Some("Some(3)")
parseCombined[String, Int]("1", "2") { _ + _ } // Some(12)
In the first case arguments were converted before passing (and then again inside), while in the other case they were converted only inside a function at a specific place.
While this case is somewhat stretched, it shows that having control over when conversion is made might matter to the final result.
That being said such usage of implicit conversions is an antipattern and type classes would work much better for it. Actually extension methods are the only non-controversial usages of implicit conversions because even magnet pattern - the only other use case that might be used on production (see Akka) - might be seen as issue.
So treat this example from docs as a demonstration of a mechanism and not as a example of good practice that should be used on production.
I was wondering how one would implement an infinite curried add function, for the case of explanation i would stick to scala.
I know how to prepare a simple curry like
def add(a: Int): Int => Int = {
def iadd(b: Int): Int = {
a + b
}
iadd
}
add(4)(5) // 9
How would i got about implementing add(5)(4)(x1)(x2)..(xn)
The Smart Way
The question is the comments is well-posed: when do you stop the currying and produce a result?
One solution is to stop the recursion by calling the function with zero arguments. Scala's overloading with let us do this.
add(1)(2)(3)(4)() // The () indicates that we're done currying
This is relatively straightforward. We just need a class with an apply that returns a new instance of itself
// A class with an apply method is callable like a function
class Adder(val acc: Int) {
def apply(a: Int): Adder =
new Adder(acc + a)
def apply(): Int =
acc
}
def add: Adder = new Adder(0)
println(add(1)(2)(3)(4)()) // 10
If you ever had a real reason to do this, this would be the way I would recommend. It's simple, easy to read, and adds very little boilerplate on top of the currying.
The Slightly Unhinged Way
But what fun is simple and logical? Let's get rid of those silly parentheses at the end, eh? We can do it with Scala's implicit conversions. First, we'll need to import the feature, so that Scala will stop warning us that what we're doing is silly and not a good idea.
import scala.language.implicitConversions
Then we make it so that Adder can be converted to Int
// Don't do this in real code
implicit def adderToInt(adder: Adder): Int =
adder()
Now, we don't need those parentheses at the end. We do, however, need to indicate to the type system that we want an Int.
val result: Int = add(1)(2)(3)(4)
println(result) // 10
Passing the result to a function which takes an Int, for instance, would also suffice.
Comments
Since you mentioned functional programming in general, I will note that you can do similar tricks in Haskell, using typeclasses. You can see this in action in the standard library with Text.PrintF. Note that since Haskell functions always take one argument, you'll need to have a sentinel value to indicate the "end" of the arguments (() may suffice, depending on how generic your argument types are).
If you want to reinterpret every integer n as function n.+, then just do it:
implicit class Add(val x: Int) extends AnyVal { def apply(i: Int) = x + i }
val add = 0
or even shorter (with implicit conversions):
implicit def asAdd(n: Int): Int => Int = n.+
val add = 0
Example:
add(1)(2)(3)(4) // res1: Int = 10
There is no such thing as "infinitely curryable", it's not a meaningful notion.
Well, this is not exactly infinite currying, but it gives you the something similar.
final class InfiniteCurrying[A, B] private (acc: A, op: (A, B) => A) {
final val run: A = acc
final def apply(b: B): InfiniteCurrying[A, B] =
new InfiniteCurrying(
acc = op(acc, b),
op,
)
}
object InfiniteCurrying {
def add(initial: Int): InfiniteCurrying[Int, Int] =
new InfiniteCurrying(
acc = initial,
op = (acc, b) => acc + b
)
}
import InfiniteCurrying._
val r = add(10)(20)(30)
r.run // res: Int = 60
I was wondering how it works if I want to defining a function that takes one or more parameters and a callable (a function), and why the annotation is like this.
I will take the code from this answer as example:
// Returning T, throwing the exception on failure
#annotation.tailrec
final def retry[T](n: Int)(fn: => T): T = {
util.Try { fn } match {
case util.Success(x) => x
case _ if n > 1 => retry(n - 1)(fn)
case util.Failure(e) => throw e
}
}
In this function there are a few interesting things:
The annotation tailrec.
Generic type function retry[T]
Parameter int
callable fn
My question is on point 4. Why and how the definition of this function takes two round brackets. If you want to pass a callable function to any function should you always use a round brackets next to the "list" of optional parameter? Why not put together with the parameters?
Thank you in advance
You can have multiple parameter lists in function declaration. It is mostly the same as merging all the parameters into one list (def foo(a: Int)(b: Int) is more or less equivalent to def foo(a: Int, b: Int)) with a few differences:
You can reference parameters from previous list(s) in declaration: def foo(a : Int, b: Int = a + 1) does not work, but def foo(a: Int)(b: Int = a +1) does.
Type parameters can be inferred between parameter lists: def foo[T](x: T, f: T => String): String ; foo(1, _.toString) doesn't work (you'd have to write foo[Int](1, _.toString), but def foo[T](x: T)(f: T => String); foo(1)(_.toString) does.
You can only declare the entire list as implicit, so, multiple lists are helpful when you need some parameters to be implicit, and not the others: def foo(a: Int)(implicit b: Configuration)
Then, there are some syntactical advantages - things you could do with the single list, but they'd just look uglier:
Currying:
def foo(a: Int)(b: Int): String
val bar: Int => String = foo(1)
You could write this with the single list too, but it wouldn't look as nice:
def foo(a: Int, b: Int): String
val bar: Int => String = foo(1, _)
Finally, to your question:
def retry[T](n: Int)(f: => T)
is nice, because parenthesis are optional around lists with just a single argument. So, this lets you write things like
retry(3) {
val c = createConnection
doStuff(c)
closeConnection(c)
}
which would look a lot uglier if f was merged into the same list.
Also, currying is useful:
val transformer = retry[Int](3)
Seq(1,2,3).map { n => transformer(n + 1) }
Seq(4,5,6).map { n => transformer(n * 2) }
To be honest you don't have to use multiple parameter lists in order to pass function as an argument. E.g.
def pass(string: String, fn: String => Unit): Unit = fn(string)
would totally work. However, how would you call it?
pass("test", s => println(s))
Some would find it clumsy. You would rather want to pass it like:
pass("test")(s => println(s))
or even
pass("test") { s =>
println(s)
}
to make it look as if function is a block appended to the pass called with one parameter.
With single parameter list you will be forced to write it like:
pass("test", println)
pass("test", s => println(s))
pass("test", { s => println(s) })
With last parameter curried you just get more comfortable syntax. In languages like Haskell, where currying happens automatically, you don't have to bother with syntactic design decisions like this one. Unfortunately Scala requires that you made these decisions explicitly.
If you want to pass a callable function to any function should you
always use a round brackets next to the "list" of optional parameter?
Why not put together with the parameters?
There is no such obligation, it's (mostly) a matter of style. IMO, it also leads to cleaner syntax. With two parameter lists, where the second one is the function yielding the result, we can call the retry method:
val res: Try[Int] retry(3) {
42
}
Instead, of we used a single parameter list, our method call would look like this:
val res: Try[Int] = retry(3, () => {
42
})
I find the first syntax cleaner, which also allows you to use retry as a curried method when only supplying the first parameter list
However, if we think of a more advanced use case, Scala type inference works between parameter lists, not inside them. That means that if we have a method:
def mapFun[T, U](xs: List[T])(f: T => U): List[U] = ???
We would be able to call our method without specifying the type of T or U at the call site:
val res: List[Int] = mapFun(List.empty[Int])(i => i + 1)
But if we used a single parameter list,
def mapFun2[T, U](xs: List[T], f: T => U): List[U] = ???
This won't compile:
val res2 = mapFun2(List.empty[Int], i => i + 1)
Instead, we'd need to write:
val res2 = mapFun2[Int, Int](List.empty[Int], i => i + 1)
To aid the compiler at choosing the right types.
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'm trying to improve my understanding of higher-kinded type in Scala. While I went back to the basic, i got stuck on the following:
def fooList[A <: Int](x: List[A]): List[A] = x.map{ e => e + 1 }
The Scala compiler does not accept it which, i do not understand. "A" must be a subclass of Int. hence whatever type under Int that shall be passed there should work. Why does it complain? Can someone advise me here ?
M
A really must be an Int in this case, because you can't create a sub-class of Int, but the compiler doesn't seem to want to prove that. That aside, since A <: Int, the + method of Int returns an Int.
So e + 1 is an Int and not an A (even if A must be an Int, anyway). Therefore, x.map(e => e + 1) returns a List[Int] and not a List[A]. In order to return List[A], you need some class A with a + method that also returns A, which you don't.