4
votes

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?

1

1 Answers

6
votes

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.