In a project I'm working on with a colleague, we are usign the UrlParser module and we stumbled in this error:
The type annotation for ourParser does not match its definition.
The type annotation is saying:
UrlParser.Parser a a
But I am inferring that the definition has this type:
UrlParser.Parser (String -> ∞) (String -> ∞)
Hint: A type annotation is too generic. You can probably just switch
to the type I inferred. These issues can be subtle though, so read
more about it.
Our code is something like
ourParser : UrlParser.Parser a a
ourParser =
UrlParser.oneOf
[ UrlParser.s "home"
, UrlParser.s "detail" </> UrlParser.string
]
The main question is: what is this ∞ symbol? Where is it defined? If I try to copy/paste it in my function definition I get a syntax error, as if Elm actually doesn't know what that character is...
The following question is: how such an error happens with my code?
The second parser in your list of alternatives combines
UrlParser.s "detail" : Parser a a
UrlParser.string : Parser (String -> b) b
using
(</>) : Parser u v -> Parser v w -> Parser u w
As you can hopefully see, the following types must match up:
u ~ a
v ~ a
v ~ (String -> b)
w ~ b
The resulting type is
UrlParser.s "detail" </> UrlParser.string : Parser (String -> b) b
The first parser in your list of alternatives has type
UrlParser.s "home" : Parser c c
Because you're building a list of these, they must have the same general type. As such, c ~ (String -> b), but also c ~ b. What you have here is a loop, resulting in an infinite type. That is what the infinity symbol means.
The error text is indeed misleading, because infinite types are not supported in Elm's type system (because they make no sense). This sounds like a bug, as Elm should explain that infinite types always point to a programming mistake.
The documentation for oneOf shows how parsers of different types could be combined through the use of format.
In any case, you need to turn your first parser into something of the type Parser (String -> c) c. From the types, it looks like applying format "some string" to the first parser would already suffice, but I don't know enough about Elm or the UrlParser to give any guarantees about that.
Related
I would like to make a function that given a function type (e.g. String -> Nat -> Bool), would return a list of types corresponding to that function type (e.g. [String, Nat, Bool]). Presumably the signature of such a function would be Type -> List Type, but I am struggling to determine how it would be implemented.
I don't believe it could be done in general, because you cannot patter-match on functions. Neither can you check for the type of a function. That is not what dependent types are about. Just like in Haskell or OCaml the only thing you can actually do with a function is apply it to some argument. However, I devised some trick which might do:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = [a, b]
Now the problem is that a -> b is the only signature that would match any arbitrary function. But, of course it does not behave the way you'd like for functions with arity higher than one:
> myFun (+)
[Integer, Integer -> Integer] : List Type
So some sort of recursive call to itself would be necessary to extract more argument types:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = a :: myFun b
The problem here is that b is an arbitrary type, not necessarily a function type and there is no way I can figure out to dynamically check whether it is a function or not, so I suppose this is as much as you can do with Idris.
However, dynamic checking for types (at least in my opinion) is not a feature to be desired in a statically typed language. After all the whole point of static typing is to specify in advance what kind of arguments a function can handle and prevent calling functions with invalid arguments at compile time. So basically you probably don't really need it at all. If you specified what you grander goal was, someone would likely have shown you the right way of doing it.
I have a following piece of Elm code (getProjectView function is omitted for brievity):
type Model = Maybe List Project
model : Model
model = Nothing
getView : Model -> Html any
getView model =
case model of
Just projects ->
ul [] (List.map getProjectView projects)
Nothing -> p [] [ text "Still loading..." ]
When I try to compile the following snippet, the compiler fails with the following error:
-- TYPE MISMATCH --------- E:\dev\irrelephant-code\client\elm\Views\Projects.elm
Tag `Maybe.Just` is causing problems in this pattern match.
32| Just projects ->
^^^^^^^^^^^^^
The pattern matches things of type:
Maybe a
But the values it will actually be trying to match are:
Model
Indicating that compiler can't deduce that this Nothing is a value of type Model (which in turn is an alias of type Maybe List Project).
What am I doing wrong here? Is there a way to explicitly mark this Nothing as a value of the Model type?
I am using elm v0.18.0
You want to define model as a type alias of Maybe (List Product). Right now, with the type keyword, you are defining a new union/tag type with one value, Maybe, which expects to arguments, of type List and Product.
A working example is https://ellie-app.com/3MhPcgGzXqRa1/0
I have a a data type in idris:
data L3 = Rejected | Unproven | Proven
which I verified to be a ring with unity, a lattice, a group and some other properties too.
Now I want to create an object, which preserves the expressions of the statements I inject in it. I started out with four categories to represent all the operations, so I get a nice syntax tree out of it. Eg:
Om [Proven, Unproven, Op [Proven, Oj [Unproven, Proven]]
This is not the real representation, I stripped some of the needed ugly parts, but it gives an idea of what I try to achieve, the above is equivalent to:
meet Proven (meet Unproven (Proven <+> (join Unproven Proven)))
I recognized I could join the data types together into one. To get there I created a function, which will pick the correct class instance:
%case data Operator = Join | Meet | Plus | Mult
classChoice : (x: Operator) -> (Type -> Type)
classChoice Join = VerifiedJoinSemilattice
classChoice Meet = VerifiedMeetSemilattice
classChoice Plus = VerifiedGroup
classChoice Mult = VerifiedRing
So I could assure that anything in the type represents one of those four operations:
%elim data LogicSyntacticalCategory : classChoice op a => (op : Operator) -> (a : Type) -> Type where
LSCEmpty : LogicSyntacticalCategory op a
It will complain with:
When elaborating type of logicCategory.LSCEmpty:
Can't resolve type class classChoice op ty
Now my question: How can I assure that the objects in my data type are verified and join the four separate data types into one. I really would like to ensure this is true during construction. I can understand it has difficulties resolving the type class now, but I want Idris to ensure it can do it later during construction. How can I do this?
Code isn't really needed, I am quite happy with a direction of thought.
Two minor problems first: ... -> a -> ... should be ... -> (a : Type) -> ..., and syntactical is how it's written.
Warning: I'm working with Idris 0.9.18 and don't know how to write Elab proofs yet.
Repository: https://github.com/runKleisli/idris-classdata
In normal functions with these same type signatures, you have the opportunity to assist the type class resolution with tactics while defining the functions. But with the data type and its constructors, you only have the opportunity to declare them, so you have no such opportunity to assist in resolution. It would appear such guided resolution was needed here.
It appears that classChoice op a needs an instance proved before the LogicSyntacticleCategory op a in the definition of LSCEmpty makes sense, and that it did not get this instance. Class constraints in the data type's type like this are usually automatically introduced into the context of the constructor, like an implicit argument, but this seems to have failed here, and an instance is assumed for a different type than the one required. That instance assumed for the constructor not satisfying the goal introduced by declaring a LogicSyntacticleCategory op a seems to be the error. In one of the examples in the repository, these unexpectedly mismatched goal and assumption seem able to automatically pair, but not under the circumstances of the data type & constructor declarations. I can't figure out the exact problem, but it seems not to apply to plain function declarations with the same conditions on the type signature.
A couple solutions are given in the repository, but the easiest one is to replace the constraint argument, saying an instance of classChoice op a is required, with an implicit argument of type classChoice op a, and to evaluate LogicSyntacticleCategory like
feat : Type
feat = ?feat'
feat' = proof
exact (LogicSyntacticleCategory Mult ZZ {P=%instance})
If you are set on having a constraint argument in your main interface to the data type, you can wrap the definition of LogicSyntacticleCategory : (op : Operator) -> (a : Type) -> {p : classChoice op a} -> Type with the function
logicSyntacticleCategory : classChoice op a => (op : Operator) -> (a : Type) -> Type
logicSyntacticleCategory = ?mkLogical
mkLogical = proof
intros
exact (LogicSyntacticleCategory op a {P=constrarg})
and when you want to make a type of the form LogicSyntacticleCategory op a, evaluate like before, but with
feat' = proof
exact (logicSyntacticleCategory Mult ZZ)
exact Mult
exact ZZ
compute
exact inst -- for the named instance (inst) of (classChoice Mult ZZ)
where the last line is dropped for anonymous instances.
One can return a type in a function in Idris, for example
t : Type -> Type -> Type
t a b = a -> b
But the situation came up (when experimenting with writing some parsers) that I wanted to use -> to fold a list of types, ie
typeFold : List Type -> Type
typeFold = foldr1 (->)
So that typeFold [String, Int] would give String -> Int : Type. This doesn't compile though:
error: no implicit arguments allowed
here, expected: ")",
dependent type signature,
expression, name
typeFold = foldr1 (->)
^
But this works fine:
t : Type -> Type -> Type
t a b = a -> b
typeFold : List Type -> Type
typeFold = foldr1 t
Is there a better way to work with ->, and if not is it worth raising as a feature request?
The problem with using -> in this way is that it's not a type constructor but a binder, where the name bound for the domain is in scope in the range, so -> itself doesn't have a type directly. Your definition of t for example wouldn't capture a dependent type like (x : Nat) -> P x.
While it is a bit fiddly, what you're doing is the right way to do this. I'm not convinced we should make special syntax for (->) as a type constructor - partly because it really isn't one, and partly because it feels like it would lead to more confusion when it doesn't work with dependent types.
The Data.Morphisms module provides something like this, except you have to do all the wrapping/unwrapping around the Morphism "newtype".
I'm trying to do the exercises in Real World Haskell in a TDD fashion, using HUnit. As you probably guessed I haven't gotten far yet so I'm an absolute beginner when it comes to Haskell. Given the following code how can I resolve the following error ghci produces:
Ambiguous type variable a' in the constraints:
Show a'
arising from a use of assertEqual' at List_Test.hs:6:27-58
Eq a' arising from a use of `assertEqual' at List_Test.hs:6:27-58
Probable fix: add a type signature that fixes these type variable(s)
List_Test.hs:
module List_Test
where
import List
import Test.HUnit
fromEmptyList = TestCase $ assertEqual "" [] (toList (Nil))
main = runTestTT fromEmptyList
List.hs:
module List
where
data List a = Cons a (List a)
| Nil
deriving (Show)
toList Nil = []
toList (Cons a b) = (:) a (toList b)
I've tried adding type constraints to both the List declaration and the toList definition without success. A internet search did also not provide any information.
The issue is partially that GHC does not know that toList Nil will return an empty list.
*List> :i toList
toList :: List a -> [a] -- Defined at List.hs:7:0-5
It only knows that it will return a list of type a, but it has no idea what a is -- hence the "ambiguous type variable a" message. One way to work around this is to just specify the type of list that toList will return:
fromEmptyList = TestCase $ assertEqual "" [] (toList (Nil) :: [Int])
Changing that, and removing the first two lines of List_Test (it will not look for a main function in a named module that is not named Main), gave me this result:
$ runghc List_Test.hs
Cases: 1 Tried: 1 Errors: 0 Failures: 0