不能在case语句中使用将可扩展记录参数作为参数传递的函数



我正试图使用可扩展记录从一些记录中提取一些信息。如果我创建了一个采用可扩展记录类型并返回字符串的函数,并在case语句中使用它,那么就没有问题(在下面的示例中为namedToString(。然而,如果我试图使用作为参数传递的函数(stringFromNamed(,我会收到一个错误:

This business value is a: 
Business  
But stringFromNamed needs the 1st argument to be:  
Named a -> String (edited)  

来自下面的示例代码:

type alias Named a =
{ a | name : String }
type alias Person =
Named { address : String }
type alias Business =
Named { employeeCount : Int }
type Change
= PersonUpdate Person
| BusinessUpdate Business
namedToString : Named a -> String
namedToString changeFields =
changeFields.name
changeToString : (Named a -> String) -> Change -> String
changeToString stringFromNamed change =
case change of
PersonUpdate person ->
-- This works
namedToString person
BusinessUpdate business ->
-- This will cause the error
stringFromNamed business

此示例仅包含所需的代码,但更完整的示例可在https://ellie-app.com/77nCPLh55j3a1

问题的原因是什么?我如何实现传递函数的目标,该函数将从可扩展记录中提取一些信息?

我在Elm编译器repo中发现了这个问题:https://github.com/elm/compiler/issues/1959

这似乎是编译器中的一个错误,如果您只想将一种类型的外部记录传递给函数参数,可以解决这个问题。您可以通过删除上例中的高阶函数changeToString的类型签名来完成此操作。

不幸的是,如果我们想从函数参数(例如stringFromNamed(执行相同的操作,在每种情况下都会返回错误,因此必须找到另一种解决方法。

我正在使用的解决方法是创建一个新的记录类型,该类型正好包括可扩展记录中的字段,然后从遵循可扩展记录类型的其他记录的字段中创建一个实例。只有几个案例和只有一个字段的可扩展记录不是什么大问题,但这并不能很好地扩展。以下示例:

type alias Named a =
{ a | name : String }

type alias OnlyNamed =
Named {}

type alias Person =
Named { address : String }

type alias Business =
Named { employeeCount : Int }

type Change
= PersonUpdate Person
| BusinessUpdate Business

type Msg
= UpdateCurrentChange Change

namedToString : Named a -> String
namedToString changeFields =
changeFields.name

changeToString : (OnlyNamed -> String) -> Change -> String
changeToString stringFromNamed change =
case change of
PersonUpdate { name } ->
stringFromNamed  { name = name }
BusinessUpdate { name } ->
stringFromNamed  { name = name }

我认为问题是您传递的函数使用Named a,而Elm不知道a指的是什么,所以它最终决定它是类型不匹配的。如果将类型注释更改为(Named Business -> String) -> Change -> String,它将编译并工作。

最新更新