1

I am trying currently trying to solve some Scala problem set for getting to know with the language. I am stuck with problem 11 where my solution will not compile. My question is: Why is this illegal in Scala?

def countPackSingle[A](list: List[A]): List[Any] = {
  pack(list) map {ls => {
    case head :: Nil => head
    case head :: tail => List(tail.size + 1, head)
  }}
}

IntelliJ is happy about this definition, but the compiler complains:

missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)

Expected type was: ?

pack(list) map {ls => {
                      ^

I do not really get what this message is trying to tell me. Can the scala compiler not infere the type of ls? When I specify the type by ls: List[A], the problem however remains.

At this occasion: Why can I specify the type for the argument ls when using curly braces { } but not when using parenthesises ( )? Until today, I am looking for a good resource explaining the difference in Scala. So far, I believed it only makes a real difference when using the literals to create parial functions via `case and on some other rare occasions.

Thanks for help!

Community
  • 1
  • 1
Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192

1 Answers1

4

This structure:

{
  case head :: Nil => head
  case head :: tail => List(tail.size + 1, head)
}

is a syntactic sugar for a partial function, that's why compiler throws you this message, scalac thinks that you are trying to make a PartilFunction[List[A], List[A]]. To fix this issue you have three ways:

1) Complete this to pattern matching construct:

pack(list) map { ls => ls match {
    case head :: Nil => head
    case head :: tail => List(tail.size + 1, head)
  }
}

2) Use underscore syntax:

pack(list) map { _ match {
    case head :: Nil => head
    case head :: tail => List(tail.size + 1, head)
  }
}

which is actually the same. Now, if you want, you can ascribe a type for ls, but scala can successfully infer it.

3) Use inline syntax:

pack(list) map {
  case head :: Nil => head
  case head :: tail => List(tail.size + 1, head)
}

It is possible because PartialFunction is a subclass of Function, so it is possible to use partial function directly instead of plain function.

And you have no point in the result type List[Any]. 1) this type is not good, cause you loose all your type information and 2) you function is not tailrecursive, so you can drop it and let scalac infer it for you

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
4lex1v
  • 21,367
  • 6
  • 52
  • 86
  • @raphw That's what the compiler is trying to tell you, check [SLS 8.5](http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf) – 4lex1v Sep 27 '13 at 13:09
  • On second look: Shouldn't the first partial function literal result in a `PartialFunction[List[A], Any]` type? And shouldn't the return type be of `List[Any]` because of that? – Rafael Winterhalter Sep 27 '13 at 13:27
  • @raphw I didn't try to solve this problems, so this depends on your `pack` function and what's the task says, my answer was in general theory in your case it can be different, so it's better to drop some explicit types and let scalac to this for you. – 4lex1v Sep 27 '13 at 13:31
  • 3) inline syntax: `def countPackSingle[A](list: List[A]): List[Any] = { pack(list) map { case head :: Nil => head case head :: tail => List(tail.size + 1, head) } }` – om-nom-nom Sep 27 '13 at 13:32
  • @Alexlv, In fact, since `PartialFunction` is a subclass of `Function`, there is a third way: `pack(list) map { case head :: Nil => ... ; case head :: tail => ... }`, i.e. use that partial function directly. Heh, it seems @om-nom-nom was several seconds quickier :) – Vladimir Matveev Sep 27 '13 at 13:32
  • @VladimirMatveev just a few seconds late :-) – om-nom-nom Sep 27 '13 at 13:33
  • @VladimirMatveev Scala is a very flexible language and there are even more solutions for this and many other cases, to write them all takes time, so you are free to add you solutions for a greater good =) – 4lex1v Sep 27 '13 at 13:44
  • @AlexIv, ok, I'll add inline variant to the answer. – Vladimir Matveev Sep 27 '13 at 13:47