我可以定义标记的联合类型:
type Msg
= Sort (Product -> Float)
但我无法定义它:
type Msg
= Sort (Product -> comparable)
错误说:
类型Msg
必须声明其类型变量的可比性......
但可比较的是预定义的类型变量,对吗?
我该如何解决这个问题?
答案 0 :(得分:10)
这个问题有点像XY Problem。我想提供一种不同的方式来考虑在您的消息中传递排序函数(但需要注意的是我不熟悉您的代码库,只有您在问题中提供的示例)
向Msg
添加类型参数看起来有点乱,所以让我们退后一步。排序涉及以某种方式比较两个相同类型并返回第一个值是小于,等于还是大于第二个值。 Elm已经有Order
类型用于比较具有类型构造函数LT,EQ和GT的东西(对于Less Than,EQual和Greater Than)。
让我们将Msg
重构为以下内容:
type Msg
= Sort (Product -> Product -> Order)
现在我们不必向Msg
添加类型参数。但是,我们如何指定要排序的Product
哪个字段?我们可以使用currying。以下是:
让我们定义另一个名为comparing
的函数,该函数将函数作为其第一个参数和另外两个相同类型的参数,并返回Order
值:
comparing : (a -> comparable) -> a -> a -> Order
comparing f x y =
compare (f x) (f y)
请注意,第一个参数是一个类似于您的示例尝试在(Product -> comparable)
构造函数的Sort
参数中尝试的函数。这并非巧合。现在,通过使用currying,我们可以将comparing
函数部分应用于记录字段getter,例如.name
或.price
。要修改您的示例,onClick
处理程序可能如下所示:
onClick (Sort (comparing .name))
如果你走这条路,会有更多的重构。既然你有这个比较功能,你如何在update
函数中使用它?我们假设您的Model
有一个名为products
的字段,其类型为List Product
。在这种情况下,我们可以使用List.sortWith
函数对列表进行排序。您Sort
Msg
的更新案例如下所示:
case msg of
Sort comparer ->
{ model | products = List.sortWith comparer model.products } ! []
一些结束的想法和其他说明:
关于comparing
函数的这项业务直接来自Haskell,它满足了同样的需求。
不是像上面那样定义Sort
构造函数,我可能会将它抽象出来,因为它是如此常见的习语。您可以为这样的通用函数定义别名,然后重新定义Msg
,如下所示:
type alias Comparer a =
a -> a -> Order
type Msg
= Sort (Comparer Product)
为了更进一步说明这一切是如何连接的,comparing
的以下两种类型注释是相同的:
-- this is the original example from up above
comparing : (a -> comparable) -> a -> a -> Order
-- this example substitutues the `Comparer a` alias, which may help further
-- your understanding of how it all ties together
comparing : (a -> comparable) -> Comparer a
答案 1 :(得分:1)
您收到的错误是comparable
是未绑定的变量类型。您需要在右侧完全指定它(例如Product -> Int
)或指定您希望它在左侧是多态的。像这样:
type Msg a = Sort (Product -> a)
您在comparable
listSeq = [
[134, None, datetime.datetime(2016, 2, 12, 0, 0)],
[135, None, datetime.datetime(2016, 2, 12, 0, 0)],
[136, None, datetime.datetime(2016, 2, 12, 0, 0)],
[138, 1, datetime.datetime(2016, 2, 12, 0, 0)],
[139, None, datetime.datetime(2016, 2, 12, 0, 0)],
[140, None, datetime.datetime(2016, 2, 12, 0, 0)],
[141, None, datetime.datetime(2016, 2, 12, 0, 0)],
[142, 3, datetime.datetime(2016, 2, 12, 0, 0)],
[144, None, datetime.datetime(2016, 2, 12, 0, 0)],
[145, 2, datetime.datetime(2016, 2, 12, 0, 0)]
]
listSeq[:] = [x for x in listSeq if x[1] is not None]
提出的问题