I am following "Purescript by Example" book, and is implementing the code in Chapter 5. But I get a compilation error that I don't understand.
I get compilation error on this line (the code compiles without this line):
showPicture = map showShape
The error is:
No instance found for Prelude.Functor _67
And the error explanation does not make it clear for me. Why do I get this error?
I have these dependencies installed in my bower file:
"dependencies": {
"purescript-console": "^0.1.0"
"purescript-foldable-traversable": "~0.4.0",
"purescript-globals": "~0.2.0",
"purescript-math": "~0.2.0"
}
You need to add a type signature.
The map function implies that you are using a Functor (in this case Array). So the general type of your function is
showPicture :: forall f. (Functor f) => f Shape -> f String
You probably meant the more specific type
showPicture :: Picture -> Array String
However, psc does not yet infer constraints, so you need a type signature to guide it. Hopefully psc will infer constraints before the 1.0 release, but for now, this is the workaround.
Related
Consider the following simple snippet of PureScript code
a :: Int
a = 5
b :: Int
b = 7
c = a + b
main ∷ Effect Unit
main = do
logShow c
The program successfully infers the type of C to be Int, and outputs the expected result:
12
However, it also produces this warning:
No type declaration was provided for the top-level declaration of c.
It is good practice to provide type declarations as a form of documentation.
The inferred type of c was:
Int
in value declaration c
I find this confusing, since I would expect the Int type for C to be safely inferred. Like it often says in the docs, "why derive types when the compiler can do it for you?" This seems like a textbook example of the simplest and most basic type inference.
Is this warning expected? Is there a standard configuration that would suppress it?
Does this warning indicate that every variable should in fact be explicitly typed?
In most cases, and certainly in the simplest cases, the types can be inferred unambiguously, and indeed, in those cases type signatures are not necessary at all. This is why simpler languages, such as F#, Ocaml, or Elm, do not require type signatures.
But PureScript (and Haskell) has much more complicated cases too. Constrained types are one. Higher-rank types are another. It's a whole mess. Don't get me wrong, I love me some high-power type system, but the sad truth is, type inference works ambiguously with all of that stuff a lot of the time, and sometimes doesn't work at all.
In practice, even when type inference does work, it turns out that its results may be wildly different from what the developer intuitively expects, leading to very hard to debug issues. I mean, type errors in PureScript can be super vexing as it is, but imagine that happening across multiple top-level definitions, across multiple modules, even perhaps across multiple libraries. A nightmare!
So over the years a consensus has formed that overall it's better to have all the top-level definitions explicitly typed, even when it's super obvious. It makes the program much more understandable and puts constraints on the typechecker, providing it with "anchor points" of sorts, so it doesn't go wild.
But since it's not a hard requirement (most of the time), it's just a warning, not an error. You can ignore it if you wish, but do that at your own peril.
Now, another part of your question is whether every variable should be explicitly typed, - and the answer is "no".
As a rule, every top-level binding should be explicitly typed (and that's where you get a warning), but local bindings (i.e. let and where) don't have to, unless you need to clarify something that the compiler can't infer.
Moreover, in PureScript (and modern Haskell), local bindings are actually "monomorphised" - that's a fancy term basically meaning they can't be generic unless explicitly specified. This solves the problem of all the ambiguous type inference, while still working intuitively most of the time.
You can notice the difference with the following example:
f :: forall a b. Show a => Show b => a -> b -> String
f a b = s a <> s b
where
s x = show x
On the second line s a <> s b you get an error saying "Could not match type b with type a"
This happens because the where-bound function s has been monomorphised, - meaning it's not generic, - and its type has been inferred to be a -> String based on the s a usage. And this means that s b usage is ill-typed.
This can be fixed by giving s an explicit type signature:
f :: forall a b. Show a => Show b => a -> b -> String
f a b = s a <> s b
where
s :: forall x. Show x => x -> String
s x = show x
Now it's explicitly specified as generic, so it can be used with both a and b parameters.
I want to use sttp library with guice(with scalaguice wrapper) in my app. But seems it is not so easy to correctly bind things like SttpBackend[Try, Nothing]
SttpBackend.scala
Try[_] and Try[AnyRef] show some other errors, but still have no idea how it should be done correctly
the error I got:
kinds of the type arguments (scala.util.Try) do not conform to the expected kinds of the type parameters (type T).
[error] scala.util.Try's type parameters do not match type T's expected parameters:
[error] class Try has one type parameter, but type T has none
[error] bind[SttpBackend[Try, Nothing]].toProvider[SttpBackendProvider]
[error] ` ^
SttpBackendProvider looks like:
def get: SttpBackend[Try, Nothing] = TryHttpURLConnectionBackend(opts)
complete example in scastie
interesting that version scalaguice 4.1.0 show this error, but latest 4.2.2 shows error inside it with converting Nothing to JavaType
I believe you hit two different bugs in the Scala-Guice one of which is not fixed yet (and probably even not submitted yet).
To describe those issues I need a fast intro into how Guice and Scala-Guice work. Essentially what Guice do is have a mapping from type onto the factory method for an object of that type. To support some advanced features types are mapped onto some internal "keys" representation and then for each "key" Guice builds a way to construct a corresponding object. Also it is important that generics in Java are implemented using type erasure. That's why when you write something like:
bind(classOf[SttpBackend[Try, Nothing]]).toProvider(classOf[SttpBackendProvider])
in raw-Guice, the "key" actually becomes something like "com.softwaremill.sttp.SttpBackend". Luckily Guice developers have thought about this issue with generics and introduced TypeLiteral[T] so you can convey the information about generics.
Scala type system is more reach than in Java and it has some better reflection support from the compiler. Scala-Guice exploits it to map Scala-types on those more detailed keys automatically. Unfortunately it doesn't always work perfectly.
The first issue is the result of the facts that the type SttpBackend is defined as
trait SttpBackend[R[_], -S]
so it uses it expects its first parameter to be a type constructor; and that originally Scala-Guice used the scala.reflect.Manifest infrastructure. AFAIU such higher-kind types are not representable as Manifest and this is what the error in your question really says.
Luckily Scala has added a new scala.reflect.runtime.universe.TypeTag infrastructure to tackle this issue in a better and more consistent way and the Scala-Guice migrated to its usage. That's why with the newer version of Scala-Guice the compiler error goes away. Unfortunately there is another bug in the Scala-Guice that makes the code fail in runtime and it is a lack of handling of the Nothing Scala type. You see, the Nothing type is a kind of fake one on the JVM. It is one of the things where the Scala type system is more reach than the Java one. There is no direct mapping for Nothing in the JVM world. Luckily there is no way to create any value of the type Nothing. Unfortunately you still can create a classOf[Nothing]. The Scala-to-JVM compiler handles it by using an artificial scala.runtime.Nothing$. It is not a part of the public API, it is implementation details of specifically Scala over JVM. Anyway this means that the Nothing type needs additional handling when converting into the Guice TypeLiteral and there is none. There is for Any the cousin of Nothing but not for Nothing (see the usage of the anyType in TypeConversions.scala).
So there are really two workarounds:
Use raw Java-based syntax for Guice instead of the nice Scala-Guice one:
bind(new TypeLiteral[SttpBackend[Try, Nothing]]() {})
.toInstance(sttpBackend) // or to whatever
See online demo based on your example.
Patch the TypeConversions.scala in the Scala-Guice as in:
private[scalaguice] object TypeConversions {
private val mirror = runtimeMirror(getClass.getClassLoader)
private val anyType = typeOf[Any]
private val nothingType = typeOf[Nothing] // added
...
def scalaTypeToJavaType(scalaType: ScalaType): JavaType = {
scalaType.dealias match {
case `anyType` => classOf[java.lang.Object]
case `nothingType` => classOf[scala.runtime.Nothing$] //added
...
I tried it locally and it seems to fix your example. I didn't do any extensive tests so it might have broken something else.
I have a type class defined like this :
class Repo e ne | ne -> e, e -> ne where
eTable :: Table (Relation e)
And when I try to compile it I get this :
* Couldn't match type `Database.Selda.Generic.Rel
(GHC.Generics.Rep e0)'
with `Database.Selda.Generic.Rel (GHC.Generics.Rep e)'
Expected type: Table (Relation e)
Actual type: Table (Relation e0)
NB: `Database.Selda.Generic.Rel' is a type function, and may not be injective
The type variable `e0' is ambiguous
* In the ambiguity check for `eTable'
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method:
eTable :: forall e ne. Repo e ne => Table (Relation e)
In the class declaration for `Repo'
|
41 | eTable :: Table (Relation e)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I was expecting everything to be unambiguous since I've explicitly stated that e determines ne and vice versa.
However, if I try to define my class like this just for the testing purposes, it compiles :
data Test a = Test a
class Repo e ne | ne -> e, e -> ne where
eTable :: Maybe (Test e)
I'm not quite sure what is the deal with Table and Relation types that causes this.
Test is injective, since it is a type constructor.
Relation is not injective, since it is a type family.
Hence the ambiguity.
Silly example:
type instance Relation Bool = ()
type instance Relation String = ()
instance Repo Bool Ne where
eTable :: Table ()
eTable = someEtable1
instance Repo String Ne where
eTable :: Table ()
eTable = someEtable2
Now, what is eTable :: Table () ? It could be the one from the first or the second instance. It is ambiguous since Relation is not injective.
The source of the ambiguity actually has nothing to do with ne not being used in the class (which you headed off by using functional dependencies).
The key part of the error message is:
Expected type: Table (Relation e)
Actual type: Table (Relation e0)
NB: `Database.Selda.Generic.Rel' is a type function, and may not be injective
Note that it's the e that it's having trouble matching up, and the NB message drawing your attention to the issue of type functions and injectivity (you really have to know what that all means for the message to be useful, but it has all the terms you need to look up to understand what's going on, so it's quite good as programming error messages go).
The issue it's complaining about is a key difference between type constructors and type families. Type constructors are always injective, while type functions in general (and type families in particular) do not have to be.
In standard Haskell with no extensions, the only way you can build compound type expressions was using type constructors, such as the left-hand side Test in your data Test a = Test a. I can apply Test (of kind * -> *) to a type like Int (of kind *) to get a type Test Int (of kind *). Type constructors are injective, which means for any two distinct types a and b, Test a is a distinct type from Test b1. This means that when type checking you can "run them backwards"; if I've got two types t1 and t2 that are each the result of applying Test, and I know that t1 and t2 are supposed to be equal, then I can "unapply" Test to get the argument types and check whether those are equal (or infer what one of them is if it was something I hadn't figured out yet and the other is known, or etc).
Type families (or any other form of type function that isn't known to be injective) don't provide us that guarantee. If I have two types t1 and t2 that are supposed to be equal, and they're both the result of applying some TypeFamily, there's no way to go from the resulting types to the types that TypeFamily was applied to. And in particular, there's no way to conclude from the fact that TypeFamily a and TypeFamily b are equal that a and b are equal as well; the type family might just happen to map two distinct types a and b to the same result (the definition of injectivitiy is that it doesn't do that). So if I knew which type a was but didn't know b, knowing that TypeFamily a and TypeFamily b are equal doesn't give me any more information about what type b should be.
Unfortunately, since standard Haskell only has type constructors, Haskell programmers get well-trained to just presume that the type checker can work backwards through compound types to connect up the components. We often don't even notice that the type checker needs to work backwards, we're so used to just looking at type expressions with similar structure and leaping to the obvious conclusions without working through all the steps that the type checker has to go through. But because type checking is based on working out the type of every expression both bottom-up2 and top-down3 and confirming that they are consistent, type checking expressions whose types involve type families can easily run into ambiguity problems where it looks "obviously" unambiguous to us humans.
In your Repo example, consider how the type checker will deal with a position where you use eTable, with (Int, Bool) for e, say. The top-down view will see that it's used in a context where some Table (Relation (Int, Bool)) is required. It'll compute what Relation (Int, Bool) evaluates to: say it's Set Int, so we need Table (Set Int). The bottom-up pass just says eTable can be Table (Relation e) for any e.
All of our experience with standard Haskell tells us that this is obvious, we just instantiate e to (Int, Bool), Relation (Int, Bool) evaluates to Set Int again and we're done. But that's not actually how it works. Because Relation isn't injective there could be some other choice for e for which gives us Set Int for Relation e: perhaps Int. But if we choose e to be (Int, Bool) or Int we need to look for two different Repo instances, which will have different implementations for eTable, even though their type is the same.
Even adding a type annotation every time you use eTable like eTable :: Table (Relation (Int, Bool)) doesn't help. The type annotation only adds extra information to the top-down view, which we often already have anyway. The type-checker is still stuck with the problem that there could be (whether or not there actually are) other choices of e than (Int, Bool) which lead to eTable matching that type annotation, so it doesn't know which instance to use. Any possible use of eTable will have this problem, so it gets reported as an error when you're defining the class. It's basically for the same reason you get problems when you have a class with some members whose types don't use all of the type variables in the class head; you have to consider "variable only used under a type family" as much the same as "variable isn't used at all".
You could address this by adding a Proxy argument to eTable so that there's something fixing the type variable e that the type checker can "run backwards". So eTable :: Proxy e -> Table (Relation e).
Alternatively, with the TypeApplications extension you now can do as the error message suggests and turn on AllowAmbiguousTypes to get the class accepted, and then use things like eTable #(Int, Bool) to tell the compiler which choice for e you want. The reason this works where the type annotation eTable :: Table (Relation (Int, Bool)) doesn't work is the type annotation is extra information added to the context when the type checker is looking top-down, but the type application adds extra information when the type checker is looking bottom-up. Instead of "this expression is required to have a type that unifies with this type" it's "this polymorphic function is instantiated at this type".
1 Type constructors are actually even more restricted than just injectivity; applying Test to any type a results in a type with known structure Test a, so the entire universe of Haskell types is straightforwardly mirrored in types of the form Test t. A more general injective type function could instead do more "rearranging", such as mapping Int to Bool so long as it didn't also map Bool to Bool.
2 From the type produced by combining the sub-parts of the expression
3 From the type required of the context in which it is used
I'm playing around trying to understand classes in Haskell.
I wrote a silly few lines of code to get the hang of it. I wrote a class called Slang that has one function. When I make Integer an instance of my class, it works fine. But when I make String an instance of my class it won't compile. I've been fidgeting with the program based on what the error output tells me but to no avail. I have idea why it work...
Here is the code followed by the error:
module Practice where
class Slang s where
slangify :: s -> String
instance Slang Integer where
slangify int = "yo"
instance Slang String where -- When I take this segment out, it works fine
slangify str = "bro"
ERROR:
Prelude> :load Practice
[1 of 1] Compiling Practice ( Practice.hs, interpreted )
Practice.hs:9:10:
Illegal instance declaration for `Slang String'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Slang String'
Failed, modules loaded: none.
Prelude>
The problem is that String is not a base type like Integer. What you are trying to do is actually
instance Slang [Char] where
slangify str = "bro"
However, Haskell98 forbids this type of typeclass in order to keep things simple and to make it harder for people to write overlapping instances like
instance Slang [a] where
-- Strings would also fit this definition.
slangify list = "some list"
Anyway, as the error message suggests, you can get around this restriction by enabling the FlexibleInstances extension.
I did some research in my Haskell literature (aka my current Bible) and found an example that effectively solves my problem.
Basically, in this workaround you set Char to be an instance of the class (in the book's example it's called Visible) and then you can set [chars] aka a String, to be an instance of the class as well ONLY WITH the stipulation that the type variable chars be an instance of `Visible'.
It's easier to understand if you look at the code below:
module Practice where
class Visible a where
toString :: a -> String
size :: a -> Int
instance Visible Char where
toString ch = [ch]
size _ = 1
instance Visible a => Visible [a] where
toString = concat . map toString
size = foldr (+) 1 . map size
My GHCi load and function call:
*Practice> :l Practice
[1 of 1] Compiling Practice ( Practice.hs, interpreted )
Ok, modules loaded: Practice.
*Practice> size "I love Stack!"
14
*Practice>
Eureka!
I have a beginners Scala question. I have a class, Sample which extends the trait SampleAPI. Now I'm trying to build a sequence of Sample instances using seq. I will look something like this:
var samples: Seq[SampleAPI] = Seq()
for(...) {
samples :+= new Sample(...))
}
This gives me the following compiler error: "type mismatch; found : Seq[java.lang.Object] required: Seq[se.uu.medsci.queue.setup.SampleAPI]"
So I tried:
samples :+= (new Sample(sampleName, this, illuminaXMLReportReader)).asInstanceOf[SampleAPI]
Which instead throws a runtime exception, saying that Sample cannot be bast to SampleAPI. I guess that this comes down to a problem in my understanding of the use of traits in Scala. Any help in figuring this out would be much appreciated.
Is the compiler error coming up on this line?
samples :+= new Sample(...))
If so, I think the problem is that your Sample class doesn't actually extend SampleAPI.
What's happening has to do with the contravariant type parameter of the List type in Scala. If you start with a List[SampleAPI], then add a Sample to that list, it needs to find the least-upper-bound on the types included in the list to use as the new type parameter. If Sample is a SampleAPI, then the least-upper-bound is just SampleAPI and you get a List[SampleAPI] as the result of the :+= operation. However, if Sample is not a SampleAPI then the least-upper-bound on the two types is just Object, hence your compiler error saying that it was expecting a Seq[SampleAPI] but found a Seq[Object].