I have a type class instance and want to use it implicitly but got following error message:
Error:(10, 29) not enough arguments for method format: (implicit p: ch.micarna.interface.Printable[ch.micarna.cats.Cat])String.
Unspecified value parameter p.
val v = Printable.format(cat)
Error:(10, 29) could not find implicit value for parameter p: ch.micarna.interface.Printable[ch.micarna.cats.Cat]
val v = Printable.format(cat)
The implementation of the type class looks as follow:
As you can see on the image, the implementation is imported from the package import ch.micarna.instances._ where type class for Cat type is implemented.
What am I doing wrong?
Related
I have a rather simple piece of code that does not compile, as a type can apparently not be inferred. I would like to understand why it does not, as I have plenty of type annotations, and it should work. The code is
object MyApp {
trait A {
type V
val value: V
}
case class ConcreteA(value: Int) extends A { type V=Int }
def convert[T<:A](v: T#V): T = ConcreteA(v.asInstanceOf[Int]).asInstanceOf[T] // brief method with casts for illustration purposes only
def main(args: Array[String]) {
val i: Int = 10
val converted: ConcreteA = convert(i)
}
}
(It compiles if I add an explicit [ConcreteA] on the convert-call)
The error I get is
MyApp.scala:19: error: no type parameters for method convert: (v: T#V)T exist so that it can be applied to arguments (Int)
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Int
required: ?T#V
val converted: ConcreteA = convert(i)
^
MyApp.scala:19: error: type mismatch;
found : Int
required: T#V
val converted: ConcreteA = convert(i)
^
MyApp.scala:19: error: type mismatch;
found : T
required: MyApp.ConcreteA
val converted: ConcreteA = convert(i)
^
three errors found
Can anyone explain this to me?
Edit: I expected Scala to deduce that T is ConcreteA here. I did so because the result of the convert call goes into a val type annotated as such.
The problem, as far as I know, is that type inference works using the Unification algorithm, which simply will try to satisfy the constraints for the given values. It will first try to prove that the input v satisfy the type T#V, but at this moment, it does not have any information about T thus it simply fails before checking if the result type satisfy the condition.
If you explicitly specify that T is ConcreteA then it will be able to continue.
However, you can make it work by postponing the type checking of the arguments after the inference, using Generalized Type Constraints.
def convert[T <: A, V](v: V)(implicit ev: V <:< T#V): T = ???
val converted: ConcreteA = convert(10)
// converted: ConcreteA = ConcreteA(10)
val converted: ConcreteA = convert("hey")
// Compile error: Cannot prove that String <:< T#V.
In this case the value v does not have any restrictions, thus the compiler simple bind V to the type of v which it already knows what it is. Then, it checks the return type T which it knows must be a ConcreteA, which satisfy the constraint that it must be a subtype of A, thus it pass.
After having solved the inference, the compiler attempts to solve the implicits. In this case, it needs to obtain (prove) that V <:< T#V, which in the first case works, but in the second fails.
I wrote the following simple example and expected it to be compiled fine:
abstract class TestObject extends App{
type Type
def method[F[_]](ft: F[Type], t: Test[F]{
type Type = TestObject#Type
}) = t.doSomeAction(ft) //ERROR
}
trait Test[F[_]]{
type Type
def doSomeAction(t: F[Type]) = println(t)
}
ideone demo
But the compiler prints the following error message:
Error:(8, 23) type mismatch;
found : ft.type (with underlying type F[TestObject.this.Type])
required: F[t.Type]
(which expands to) F[TestObject#Type]
Note: TestObject.this.Type <: t.Type, but type F is invariant in type _.
You may wish to define _ as +_ instead. (SLS 4.5)
}) = t.doSomeAction(ft)
I do not really understand it since Test#Type = TestObject#Type.
So the problem is that TestObject#Type captures an existential type which is not what you want. you want to ensure that the Type of specific instances line up. you can do this like this:
https://scalafiddle.io/sf/wpI8iGg/0
or more commonly with the Aux-Pattern
https://scalafiddle.io/sf/wpI8iGg/1
I'm a bit confused about understanding of what type in scala means.
In documents I read that List[Int] is a type and List is a type constructor.
but what keyword type means when I write the following?
val ls: scala.collection.immutable.List.type = scala.collection.immutable.List
And how this type related to type that can be defined as a field in a trait for example.
In a scala val assignment like the above:
val name: Tpe = expression
Tpe is the type of the identifier name. Hence:
val x: List.type = List
The type of the List object (aka List module or List companion) is List.type. This indicates that it is a singleton. All of this is completely orthogonal to the concept of a type constructor in type theory.
Type Constructors
In type theory, List (note: not the companion) is both a type (denoted *) and a type constructor (denoted * -> *) because when you supply a type argument to List (e.g. Int) then you have a type (i.e. List[Int]). Scala provides syntax for this construction. For example:
def foo[F[_]]: F[Int]
^^^^ ^^^
| + supply a type argument to F[_]
|
+ the type constructor F[_]
But you cannot really implement such a method unless you know more about F. For example, if there is a implicit scalaz.Monad[F], you might use the Monad.pure value to construct your F[Int] like so:
def foo[F[_]: Monad]: F[Int] = Monad[F].pure(1)
In Scala
Scala does let you pass around List as a type constructor as a type parameter to such a method. For example:
scala> def foo[F[_]]: F[Int] = ???
foo: [F[_]]=> F[Int]
scala> lazy val x = foo[List]
x: List[Int] = <lazy>
However the List you are supplying in foo[List] is not the companion
Note the declaration of foo will result in the following warning:
<console>:11: warning: higher-kinded type should be enabled
by making the implicit value scala.language.higherKinds visible.
This can be achieved by adding the import clause 'import
scala.language.higherKinds'
or by setting the compiler option -language:higherKinds.
See the Scaladoc for value scala.language.higherKinds for a discussion
why the feature should be explicitly enabled.
def foo[F[_]]: F[Int] = ???
^
what keyword type means when I write the following
type is a member defined on object in Scala.
Suppose you have a class and its companion object:
class Foo(a: String)
object Foo {
def apply(a: String) = new Foo(a)
}
Now suppose you want to write a method that accepts the object Foo as an input. What's its type?
If you write this:
def someMethod(fooObj: Foo) = fooObj.apply("x") // doesn't compile
it's not going to compile. Foo refers to the type of an instance of the class (i.e. the one returned by new Foo("x") or Foo("x")). That's why objects have a type member that can refer to their own type:
def someMethod(fooObj: Foo.type) = fooObj.apply("x") // compiles!
In your specific example List.type is the type of the companion object of List. Here's a couple of examples that I hope will clarify what it means:
val listObj: List.type = List
val anEmptyList: List[Int] = listObj.empty[Int] // List()
val aListOfIntegers: List[Int] = listObj.range(1, 4) // List[(1, 2, 3)
And how this type related to type that can be defined as a field in a trait for example.
The type keyword defines a type member. .type is a type member. Conceptually it's like every object in Scala has a type member named type, like this:
object Foo {
type type = Foo
}
Obviously this won't compile, but it gives you an idea of what it may look like.
In type-level programming you’d think of a List[+A] being a type constructor:
That is:
-List[+A] takes a type parameter (A),
-by itself it’s not a valid type, you need to fill in the A somehow - "construct the type",
-by filling it in with String you’d get List[String] which is a concrete type.
In Scala it is not valid to say something is of type List. Scala is more strict here, and won’t allow us to use just a List in the place of a type, as it’s expecting a real type - not a type constructor.
In brief:
List[+A] is a type constructor whereas List[String] is a real type.
scala> case class Data[+T](val value:T=null)
defined class Data
scala> val foo=Data[ArrayBuffer[Data[Any]]]()
foo: Data[scala.collection.mutable.ArrayBuffer[Data[Any]]] = Data(null)
scala> foo.value+=Data[String]()
java.lang.NullPointerException
... 33 elided
I would like to have a Data class that is instantiated either as Data[String], Data[ArrayBuffer[Data[Any]]] or Data[Map[String,Data[Any]]]. In the above example I try to instantiate it as Data[ArrayBuffer[Data[Any]]] and add a Data[String] to its arraybuffer. Of course I get a null pointer exception because value is null. But the point of this example that it at least compiles and runs.
Now, in the Data constructor I would like to instantiate value as either a Data[String], an ArrayBuffer[Data[Any]] or Map[String,Data[Any]] depending on the type of the initially null value returned by the getClass method. However for this I need value to be a var, so that I can modify it after examining the type of its null value.
However I get this error:
scala> case class Data[+T](var value:T=null)
<console>:11: error: covariant type T occurs in contravariant position in type T of value value_=
case class Data[+T](var value:T=null)
Make your Data invariant in T. Just remove the +: Data[T] - this should compile.
Better yet, rethink your design to get rid of nulls and mutable variables - they both smell.
Edit: after reading your comments, I understand better what you are trying to do. Consider something like this for example as one of the options.
sealed trait Node
case class ListNode(list: Seq[Node]) extends Node
case class MapNode(map: Map[String, Node]) extends Node
case class LeafNode(data: String) extends Node
Now you can parse your document with something like (this is "pseudocode", adjust it to whatever xml-parsing library you are using):
def parseNode(tag: XMLTag): Node = tag.tagType match {
case LIST =>
val subNodes = tag.getNestedTags.map(parseNode)
ListNode(subNodes)
case MAP =>
val subNodes = tag.getNestedTags.map { tag =>
tag.name -> parseNode(tag)
}
MapNode(subNodes.toMap)
case _ =>
LeafNode(tag.text)
}
http://like-a-boss.net/2012/09/17/variance-in-scala.html#variance_and_type_safety
Variance and type safety
When defining a generic class with a var field we can get compile time errors:
scala> class Invariant[T](var t: T)
defined class Invariant
scala> class Covariant[+T](var t: T)
<console>:7: error: covariant type T occurs in contravariant position in type T of value t_=
class Covariant[+T](var t: T)
^
scala> class Contravariant[-T](var t: T)
<console>:7: error: contravariant type T occurs in covariant position in type => T of method t
class Contravariant[-T](var t: T)
Let’s break it down a little. Why doesn’t the compiler allow getters in the Covariant class?
scala> abstract trait Covariant[+T] {
| def take(t: T): Unit
| }
<console>:8: error: covariant type T occurs in contravariant position in type T of value t
def take(t: T): Unit
^
scala> abstract trait Contravariant[-T] {
| def take(t: T): Unit
| }
defined trait Contravariant
Why? Let’s think about usages of covariance let’s say that we have a class:
class Printer[+T] {
| def print(t: T): Unit = ???
| }
<console>:8: error: covariant type T occurs in contravariant position in type T of value t
def print(t: T): Unit = ???
If the print method can print Dogs does it make sense (in general) that it should also print Animals? Maybe sometimes but in the general sense if we want to generalize the Printer class we should use contravariance. The compiler is smart enough to check this type of usage for us.
Let’s think about the second use case: returning a generic parameter:
scala> class Create[-T] {
| def create: T = ???
| }
<console>:8: error: contravariant type T occurs in covariant position in type => T of method create
def create: T = ???
And again - does it make sense that Create should generalize by contravariance? If Create returns instances of the Animal class should we be able to use it in every place that expects Create[Dog]? The scala compiler is smart enough that it explodes in our face if we try it.
I can make it work this way:
package data
case class Data[+T](val value:T)
{
println(value.getClass)
}
This way I have to explicitly initialize value from the constructor. Nothing wrong with this, just I find it a bit too verbose.
import data.Data
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.Map
object Run extends App
{
val a=Data[ArrayBuffer[Data[Any]]](ArrayBuffer[Data[Any]]())
a.value+=Data[String]("bar")
println(a.value)
val m=Data[Map[String,Data[Any]]](Map[String,Data[Any]]())
m.value+=("foo"->Data[String]("bar"))
println(m.value)
}
This prints:
class scala.collection.mutable.ArrayBuffer
class java.lang.String
ArrayBuffer(Data(bar))
class scala.collection.mutable.HashMap
class java.lang.String
Map(foo -> Data(bar))
The program only compiles with Data having +T type parameter, otherwise I get the error:
type mismatch;
[error] found : data.Data[String]
[error] required: data.Data[Any]
[error] Note: String <: Any, but class Data is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error] a.value+=Data[String]("bar")
I'm having some trouble understanding scala's type bounds system. What I'm trying to do is make a holder class that holds items of type T that can iterate over items of type A. What I have so far is:
class HasIterable[T <: Iterable[A], A](item:T){
def printAll = for(i<-item) println(i.toString)
}
val hello = new HasIterable("hello")
The class itself successfully compiles but attempting to create the hello value gives me this error:
<console>:11: error: inferred type arguments [java.lang.String,Nothing] do
not conform to class HasIterable's type parameter bounds [T <: Iterable[A],A]
val hello = new HasIterable("hello")
^
I would have expected hello to resolve as a HasIterable[String, Char] in that case. How is this problem solved?
String itself is not a subtype of Iterable[Char], but its pimp, WrappedString, is. In order to allow your definition to make use of implicit conversions, you need to use a view bound (<%) instead of an upper type bound (<:):
class HasIterable[T <% Iterable[A], A](item:T){
def printAll = for(i<-item) println(i.toString)
}
Now your example will work:
scala> val hello = new HasIterable("hello")
hello: HasIterable[java.lang.String,Char] = HasIterable#77f2fbff