在Elm中,“comparable”是什么意思?

16
我不太理解在Elm中comparable准确地是什么,Elm似乎跟我一样感到困惑。
在REPL中:
> f1 = (<)
<function> : comparable -> comparable -> Bool

因此,f1 接受可比较的内容。

> "a"
"a" : String
> f1 "a" "b"
True : Bool

所以看起来 String 是可比较的。

> f2 = (<) 1
<function> : comparable -> Bool

所以f2接受一个可比较的对象。

> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:

    comparable

    String

那么 String 是可以比较的,但也是不可比较的?
为什么 f2 的类型不是 number -> Boolf2 还可以接受哪些可比较的对象?

3个回答

10

通常在 Elm 的类型中看到一个类型变量时,该变量是未受限制的。当你提供特定类型的一些内容时,该变量将被替换为该特定类型:

通常情况下,在 Elm 的类型中看到一种类型变量,这个变量是没有限制的。然后,当您提供特定类型的某些内容时,该变量会被替换为该特定类型:

-- says you have a function:
foo : a -> a -> a -> Int
-- then once you give an value with an actual type to foo, all occurences of `a` are replaced by that type:
value : Float
foo value : Float -> Float -> Int

comparable是一个具有内置特殊含义的类型变量。这意味着它只能与“可比较”的类型匹配,例如IntString和其他几种类型。但在其他方面它应该表现相同。所以我认为类型系统中存在一个小错误,因为您会得到:

> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:

    comparable

    String

如果没有那个错误,你将会得到:

> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:

    Int

    String

编辑:我为这个错误开了一个问题


1
为了以后的参考,这个错误在2015年末得到了修复。comparable可以在这里找到:https://package.elm-lang.org/packages/elm/core/latest/Basics#compare - Charlie

6
比较任意两个可比较的值。可比较的值包括 String, Char, Int, Float, Time 或者包含可比较值的listtuple。这些也是作为字典键或集合成员的唯一值。
引用自elm文档这里
在旧版本的 Elm 中:
可比类型包括numberscharactersstringslists of comparable thingstuples of comparable things。请注意,具有7个或更多元素的元组不可比较; 你的元组为什么这么大?
这意味着:
[(1,"string"), (2, "another string")] : List (Int, String) -- is comparable

但是,拥有

(1, "string",  True)` : (Int, String, Bool) -- or...

[(1,True), (2, False)] : List (Int, Bool ) -- are ***not comparable yet***. 

这个问题在这里讨论:链接 注意:通常当人们尝试将一个联合类型作为字典中的时,会遇到comparable类型的问题。 联合类型的标签和构造函数是不可比较的。因此,以下代码甚至无法编译通过
type SomeUnion = One | Two | Three
Dict.fromList [ (One, "one related"), (Two, "two related") ] : Dict SomeUnion String

通常情况下,当您尝试这样做时,有一种更好的方法来处理您的数据结构。但在决定之前 - 可以使用 AllDict。请参考AllDict

1
看起来你只读了我的问题标题,而没有阅读完整的内容。我在提问时感到困惑是因为编译器中存在一个错误。被选为正确答案的回答提到了这个错误。https://github.com/elm-lang/elm-compiler/issues/1013 - Mark Bolusmjak
@z5h,是的,在这方面你是正确的。不过,我认为我的回答是相关的,因为当一个新手尝试理解“可比较”是什么时,这个问题是谷歌搜索结果中最先出现的。我的回答是为了帮助他们——因为我自己花了20分钟才明白“可比较”到底是什么——例如,我惊讶地发现Bools并不被认为是可比较的。所选答案解释说:“Int、String和其他一些类型”,并不是很具体。这就是为什么我包含了elm-docs片段的原因。 - AIon
这个答案已经过时了。那个引用和链接指向一个旧版本的elm-core(新版本在此处:https://package.elm-lang.org/packages/elm/core/latest/Basics#compare),而且Elm不能再有超过两个成员的元组。 - Charlie
1
@Charlie,“Elm不再支持具有两个以上成员的元组” - 这是什么意思? Elm接受(1,2,3)。它不接受(1,2,3,4),并强制您使用命名记录 - 这是一个好主意。您仍然可以通过使用((1,2,3,), 4 )来绕过它,但对于所有人来说,使用记录更好,因为它不会增加记住要在第3和第4位置上放置哪个值的认知负荷。我会更新答案。 - AIon
真是好眼力!我的意思是“Elm 不能再有超过三个成员的元组”。 - Charlie

3

我认为这个问题可以和这个联系起来。 IntString都是可比较的,因为字符串可以与字符串进行比较,整数可以与整数进行比较。一个能够接受任何两个可比较类型的函数应该具有这样的签名comparable -> comparable -> ... 但在函数的每次评估中,这两个可比较对象必须是相同的类型。

我相信上面的f2令人困惑的原因是1是一个number而不是具体类型(这似乎阻止了编译器识别可比较项必须是某种特定类型的事实,可能需要修复)。如果你这样做:

i = 4 // 2
f1 = (<) i   -- type Int -> Bool
f2 = (<) "a" -- type String -> Bool

当可以时,你会看到它实际上会折叠相当于正确的类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接