在我与同事合作的项目中,我们使用了UrlParser
模块,我们偶然发现了这个错误:
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.
我们的代码就像
ourParser : UrlParser.Parser a a
ourParser =
UrlParser.oneOf
[ UrlParser.s "home"
, UrlParser.s "detail" </> UrlParser.string
]
主要问题是:这个∞
符号是什么?它在哪里定义?如果我尝试在我的函数定义中复制/粘贴它,我会收到语法错误,好像Elm实际上并不知道该字符是什么......
以下问题是:我的代码如何发生此类错误?
答案 0 :(得分:5)
备选列表中的第二个解析器组合
UrlParser.s "detail" : Parser a a
UrlParser.string : Parser (String -> b) b
使用
(</>) : Parser u v -> Parser v w -> Parser u w
正如您所希望看到的,以下类型必须匹配:
u ~ a
v ~ a
v ~ (String -> b)
w ~ b
结果类型是
UrlParser.s "detail" </> UrlParser.string : Parser (String -> b) b
备选列表中的第一个解析器类型为
UrlParser.s "home" : Parser c c
因为您正在构建这些列表,所以它们必须具有相同的常规类型。因此,c ~ (String -> b)
,还有c ~ b
。你在这里有一个循环,导致无限类型。这就是无穷大符号的意思。
错误文本确实具有误导性,因为Elm的类型系统不支持无限类型(因为它们毫无意义)。这听起来像一个错误,因为Elm应该解释无限类型总是指向编程错误。
documentation for oneOf
显示了如何通过使用format
来组合不同类型的解析器。
在任何情况下,您都需要将第一个解析器转换为Parser (String -> c) c
类型的解析器。从类型来看,将format "some string"
应用于第一个解析器似乎已经足够了,但我对Elm或UrlParser的了解不足以对此提供任何保证。