I'm new in Scala and programming in general.. I have troubles with the Scala map function..
The simple signature of the map function is: def map[B](f: (A) ⇒ B): List[B]
So i guess the B of map[B] is generic and i can explicit set the type of the result?
If i try to run the code:
val donuts1: Seq[Int] = Seq(1,2,3)
val donuts2: List[Int] = {
donuts1.map[Int](_ => 1)
}
i got the error message "expression of type int doesn't conform to expexted type B"
I don't understand the problem here.. Could someone explain the problem?
Thank you!
The map() signature quoted in your question is a simplified/abbreviated version of the full signature.
final def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
So if you want to specify the type parameters (which is almost never needed) then you have to specify both.
val donuts1: List[Int] = List(1,2,3)
val donuts2: List[Int] = donuts1.map[Int,List[Int]](_ => 1)
//donuts2: List[Int] = List(1, 1, 1)
and i can explicit set the type of the result?
Not really. The type parameter has to agree with what the f function/lambda returns. If you specify the type parameter then you're (usually) just asking the compiler to confirm that the result type is actually what you think it should be.
Related
I have the following function
def f[T](l:List[T], v:T)
this works without errors for
f(List(1,2,3), "this is a string")
even when T is not same in both parameters. Is it possible to rewrite the function so that the compiler gives me an error when T is not same in both parameters? (I cant rely on the user to explicitly specify the type in function f[Int])
[Apologies for the horrible title]
Type unification happens only within a parameter list. You can use separate parameter lists, although this only ensures that v.type <:< T, not that v.type =:= T.
def f[T](l:List[T])(v:T): List[T] = v :: l
f(List(1,2,3))("this is a string")
Error:(81, 20) type mismatch;
found : String("this is a string")
required: Int
f(List(1,2,3))("this is a string")
Another option is using an implicit, although it requires a type cast:
def f[T, U](l: List[T], v: U)(implicit ev: T =:= U): List[T] =
v.asInstanceOf[T] :: l
val l1 = List("a", "b", "c")
val l2: List[Any] = List("a", "b", "c")
val s1 = "d"
val s2: Any = "d"
f(l1, s1) // compiles
f(l2, s2) // compiles
f(l1, s2) // Cannot prove that String =:= Any.
f(l2, s1) // Cannot prove that Any =:= String.
First things first, Scala handles type classes in such situations by finding the common supertype that could be generalized as T. In your example, you have Int and String whom common super is Any. So def f[T](l:List[T], v:T): T = v invoked with f(List(1, 2, 3), "scala") yields Any = "scala".
Now, there are several ways you could handle that depending on the desired behaviour. This question contains neat answers for the opposite question (ensuring type difference) Enforce type difference . On the other hand, you could resolve to using ClassTag or introducing some implicits that would allow you to distinguish types. Nevertheless, regardless of the approach your method most likely will require following definition def f[U, T](l: List[U], v: T) and implement one of the abovementioned type guards.
I want to create a set with the first character from a set of strings. Seems like I should be able to map easily but I can't figure out the correct syntax or find it on SO or the rest of the web. Here's where I'm at:
val mySetOfStrings = scala.collection.immutable.Set[String]()
def charSet: Set[Char] = mySetOfStrings.map[Char]((s: String) => s.head)
//IDE tells me "Expression of type Char doesn't conform to expected type B"
Thanks.
The IDE error isn't correct, but manually supplying type parameters to map is going to cause you problems, because the signature of map is really:
final def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
So the actual compiler error is:
<console>:12: error: wrong number of type parameters for method map: [B, That](f: String => B)(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[String],B,That])That
strings.map[Char](_.head)
^
Note that there are two type parameters, and not one. The compiler will infer Char on its own, though.
scala> val strings = Set("abc", "def", "ijk")
scala> strings.map(_.head)
res1: scala.collection.immutable.Set[Char] = Set(a, d, i)
Manually supplying the type parameters would have to look like this:
scala> strings.map[Char, Set[Char]](_.head)
res6: Set[Char] = Set(a, d, i)
scala> Set("foo", "bar", "baz").map( s => s.head )
res0: scala.collection.immutable.Set[Char] = Set(f, b)
You usually don't supply the type arguments to the map method yourself.
If you want to ignore empty strings in the input then you can use:
mySetOfStrings.flatMap(_.headOption)
Another approach to bypassing empty strings,
mySetOfStrings.flatMap(_.take(1))
I was looking at the definition of toArray for hashmaps :
http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.HashMap
It has
toArray: Array[A]
def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]
I don't quite understand this - the first bit says you get an Array[A], but the second part says you get Array[B]? Neither of these are what I expect - Array[(A,B)]
When I check it myself :
scala> val x = scala.collection.mutable.HashMap[String, Int]()
x: scala.collection.mutable.HashMap[String,Int] = Map()
scala> x.put("8", 7)
res0: Option[Int] = None
scala> x foreach println
(8,7)
scala> x.toArray
res2: Array[(String, Int)] = Array((8,7))
why isn't it like toList?
toList: scala.List[(A, B)]
The scaladoc has all kinds of subtle bugs. The problem here is that you are seeing the "simplified" version of the method signature (meant as a way to convey the essential part of the signature and hide things such as CanBuildFrom in map/flatMap methods, which are really an implementation detail).
The simplification got a little awry here, and does not seem to make much sense.
If you click on the "full signature" link, you'll see that the real signature looks like:
def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]
In fact this is still wrong, as we certainly cannot have a type B where B >: (A, B). It should be more like :
def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C]
The problem is that there are actually two Bs: the first one comes from the HashMap class declaration itself (HashMap[A, +B]) while the other one comes from the methods toArray defined in its base class
TraversableOnce (def toArray[B >: A](implicit arg0: ClassTag[B]): Array[B]). It just happens that the scaladoc generator failed to dedup the two instances of B
The API you see in the the Scaladoc of toArray:
def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]
Is equivalent to:
def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C]
The choice of the type variable B is indeed unfortunate (and maybe even a Scaladoc bug, I'm not sure if you are allowed to write that).
It basically means you'll get an array of the most specific supertype of (A,B) for which a ClassTag is available. The ClassTag is required in order to create the Array.
This basically means that if at compile-time, the-run time type of the Map you are converting is fully known, you will get a Array[(A,B)]. However, if you have up-casted your Map somewhere, the run-time type of the resulting Array will depend on the up-casted type, and not on the runtime type. This is different behavior than toList and due to the JVMs restrictions on how native arrays can be created.
The Scaladoc is just wrong because it inherits toArray from TraversableOnce, where the type of the collection is A and the return value is B. The Array[A] thing is left over from TraversableOnce where A is whatever TraversableOnce is traversing (in this case, actually (A,B) for a different definition of A and B); and although it fills the (A,B) in properly in the long form, it still uses B as the new return variable instead of a different letter like C.
Kind of confusing! It actually should read
def toArray[C >: (A,B)](...[C]): Array[C]
and the short form should be
toArray: Array[(A,B)]
just like you expect.
Why does this code produce an error
def test[A](a: List[A], f: A => A) = a.map(f)
println(test(List(1,2,3), _*2))
error: missing parameter type for expanded function ((x$2) => x$2.$times(2))
shouldn't Scala be able to tell that A is Int?
You need a second parameter list for this to work. I'm not sure how this is defined in the spec, however I have seen this before.
scala> def test[A](a: List[A])(f: A => A) = a.map(f)
test: [A](a: List[A])(f: (A) => A)List[A]
scala> test(List(1))(_+1)
res1: List[Int] = List(2)
This is the example, how to make it work in your case without changing anything.
scala> println(test(List(1,2,3), (i: Int) => i * 2 ))
Scala's type inference is limited, sometimes you should help!
Here is the article Making the most of Scala's (extremely limited) type inference
Sometime I stumble into the semi-mysterious notation of
def f[T](..) = new T[({type l[A]=SomeType[A,..]})#l] {..}
in Scala blog posts, which give it a "we used that type-lambda trick" handwave.
While I have some intutition about this (we gain an anonymous type parameter A without having to pollute the definition with it?), I found no clear source describing what the type lambda trick is, and what are its benefits. Is it just syntactic sugar, or does it open some new dimensions?
Type lambdas are vital quite a bit of the time when you are working with higher-kinded types.
Consider a simple example of defining a monad for the right projection of Either[A, B]. The monad typeclass looks like this:
trait Monad[M[_]] {
def point[A](a: A): M[A]
def bind[A, B](m: M[A])(f: A => M[B]): M[B]
}
Now, Either is a type constructor of two arguments, but to implement Monad, you need to give it a type constructor of one argument. The solution to this is to use a type lambda:
class EitherMonad[A] extends Monad[({type λ[α] = Either[A, α]})#λ] {
def point[B](b: B): Either[A, B]
def bind[B, C](m: Either[A, B])(f: B => Either[A, C]): Either[A, C]
}
This is an example of currying in the type system - you have curried the type of Either, such that when you want to create an instance of EitherMonad, you have to specify one of the types; the other of course is supplied at the time you call point or bind.
The type lambda trick exploits the fact that an empty block in a type position creates an anonymous structural type. We then use the # syntax to get a type member.
In some cases, you may need more sophisticated type lambdas that are a pain to write out inline. Here's an example from my code from today:
// types X and E are defined in an enclosing scope
private[iteratee] class FG[F[_[_], _], G[_]] {
type FGA[A] = F[G, A]
type IterateeM[A] = IterateeT[X, E, FGA, A]
}
This class exists exclusively so that I can use a name like FG[F, G]#IterateeM to refer to the type of the IterateeT monad specialized to some transformer version of a second monad which is specialized to some third monad. When you start to stack, these kinds of constructs become very necessary. I never instantiate an FG, of course; it's just there as a hack to let me express what I want in the type system.
The benefits are exactly the same as those conferred by anonymous functions.
def inc(a: Int) = a + 1; List(1, 2, 3).map(inc)
List(1, 2, 3).map(a => a + 1)
An example usage, with Scalaz 7. We want to use a Functor that can map a function over the second element in a Tuple2.
type IntTuple[+A]=(Int, A)
Functor[IntTuple].map((1, 2))(a => a + 1)) // (1, 3)
Functor[({type l[a] = (Int, a)})#l].map((1, 2))(a => a + 1)) // (1, 3)
Scalaz provides some implicit conversions that can infer the type argument to Functor, so we often avoid writing these altogether. The previous line can be rewritten as:
(1, 2).map(a => a + 1) // (1, 3)
If you use IntelliJ, you can enable Settings, Code Style, Scala, Folding, Type Lambdas. This then hides the crufty parts of the syntax, and presents the more palatable:
Functor[[a]=(Int, a)].map((1, 2))(a => a + 1)) // (1, 3)
A future version of Scala might directly support such a syntax.
To put things in context: This answer was originally posted in another thread. You are seeing it here because the two threads have been merged. The question statement in the said thread was as follows:
How to resolve this type definition: Pure[({type ?[a]=(R, a)})#?] ?
What are the reasons of using such construction?
Snipped comes from scalaz library:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
object Pure {
import Scalaz._
//...
implicit def Tuple2Pure[R: Zero]: Pure[({type ?[a]=(R, a)})#?] = new Pure[({type ?[a]=(R, a)})#?] {
def pure[A](a: => A) = (Ø, a)
}
//...
}
Answer:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
The one underscore in the boxes after P implies that it is a type constructor takes one type and returns another type. Examples of type constructors with this kind: List, Option.
Give List an Int, a concrete type, and it gives you List[Int], another concrete type. Give List a String and it gives you List[String]. Etc.
So, List, Option can be considered to be type level functions of arity 1. Formally we say, they have a kind * -> *. The asterisk denotes a type.
Now Tuple2[_, _] is a type constructor with kind (*, *) -> * i.e. you need to give it two types to get a new type.
Since their signatures do not match, you cannot substitute Tuple2 for P. What you need to do is partially apply Tuple2 on one of its arguments, which will give us a type constructor with kind * -> *, and we can substitue it for P.
Unfortunately Scala has no special syntax for partial application of type constructors, and so we have to resort to the monstrosity called type lambdas. (What you have in your example.) They are called that because they are analogous to lambda expressions that exist at value level.
The following example might help:
// VALUE LEVEL
// foo has signature: (String, String) => String
scala> def foo(x: String, y: String): String = x + " " + y
foo: (x: String, y: String)String
// world wants a parameter of type String => String
scala> def world(f: String => String): String = f("world")
world: (f: String => String)String
// So we use a lambda expression that partially applies foo on one parameter
// to yield a value of type String => String
scala> world(x => foo("hello", x))
res0: String = hello world
// TYPE LEVEL
// Foo has a kind (*, *) -> *
scala> type Foo[A, B] = Map[A, B]
defined type alias Foo
// World wants a parameter of kind * -> *
scala> type World[M[_]] = M[Int]
defined type alias World
// So we use a lambda lambda that partially applies Foo on one parameter
// to yield a type of kind * -> *
scala> type X[A] = World[({ type M[A] = Foo[String, A] })#M]
defined type alias X
// Test the equality of two types. (If this compiles, it means they're equal.)
scala> implicitly[X[Int] =:= Foo[String, Int]]
res2: =:=[X[Int],Foo[String,Int]] = <function1>
Edit:
More value level and type level parallels.
// VALUE LEVEL
// Instead of a lambda, you can define a named function beforehand...
scala> val g: String => String = x => foo("hello", x)
g: String => String = <function1>
// ...and use it.
scala> world(g)
res3: String = hello world
// TYPE LEVEL
// Same applies at type level too.
scala> type G[A] = Foo[String, A]
defined type alias G
scala> implicitly[X =:= Foo[String, Int]]
res5: =:=[X,Foo[String,Int]] = <function1>
scala> type T = World[G]
defined type alias T
scala> implicitly[T =:= Foo[String, Int]]
res6: =:=[T,Foo[String,Int]] = <function1>
In the case you have presented, the type parameter R is local to function Tuple2Pure and so you cannot simply define type PartialTuple2[A] = Tuple2[R, A], because there is simply no place where you can put that synonym.
To deal with such a case, I use the following trick that makes use of type members. (Hopefully the example is self-explanatory.)
scala> type Partial2[F[_, _], A] = {
| type Get[B] = F[A, B]
| }
defined type alias Partial2
scala> implicit def Tuple2Pure[R]: Pure[Partial2[Tuple2, R]#Get] = sys.error("")
Tuple2Pure: [R]=> Pure[[B](R, B)]