F# Match 在 'T list' 与 ''a list -> 'b list' 之间的类型比较失败
F# Match is failing type comparison between 'T list' vs ''a list -> 'b list'
我在 f# 中有以下非常简单的函数:
let private addOnsFromDto (addOns: MyType1 []) =
let typedList = List.empty<MyType2>
match addOns with
| null -> typedList
| _ -> List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2)
f# 编译器抱怨此错误消息:
All branches of a pattern match expression must return values of the same type as the first branch, which here is 'MyType2 list'. This branch returns a value of type 'MyType1 list -> MyType2 list'.
我知道在第一个分支上我有一个 'MyType2 list'。我知道在第二个分支上我有一个从列表映射到列表的函数 'MyType2 list' 所以编译器抱怨两个分支的类型不一致是有道理的。
但是,鉴于第二个分支的输出与第一个分支的输出类型相同,我希望编译器可以正常工作。我是否需要做一些事情来“强制” List.map 函数的评估,以便这两种类型是等价的?如果是这样,我该如何实现?
解决方案
对于任何认为有用的解决方案,正如有用的答案所解释的那样,我需要将原始列表通过管道传输到 map 函数中,以便提供两个参数。
let private addOnsFromDto (addOns: MyType1 []) =
let typedList = List.empty<MyType2>
match addOns with
| null -> typedList
| _ -> addOns
|> Array.toList
|> List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2)
List.map
接受两个参数,但您只提供了一个。您需要将输入列表添加为参数:
List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2) addOns
或者更通俗地说:
addOns |> List.map (fun a -> MyType2.create a.Prop1 a.Prop2)
错误信息This branch returns a value of type 'MyType1 list -> MyType2 list'.
实际上是在告诉你这里缺少一个参数。这就是部分应用程序的工作原理。如果您没有提供足够的参数,您通常会收到这样的消息,其中包含一个带箭头的类型。缺少的参数是MyType1 list
类型的addOns
的数据,所以addOns需要先从MyType1 array
转换为MyType1 list
。
这就是我得出的结论。我已经包含了虚拟类型,因此它可以自行编译。还删除了类型注释以方便阅读。当您提出问题时,如果您能提供可编译的代码就好了。
type MyType1 = { Prop1: int; Prop2: float }
type MyType2 = { Prop1: int; Prop2: float }
with
static member create p1 p2 = { MyType2.Prop1 = p1; Prop2 = p2 }
let private addOnsFromDto (addOns: MyType1 array) =
match addOns with
| null -> []
| addOns ->
addOns
|> Array.toList
|> List.map (fun a -> MyType2.create a.Prop1 a.Prop2)
更新,附加说明:我在最后一个匹配案例中使用了阴影声明 addOns
而不是下划线。在这种情况下,以这种方式还是使用下划线可能并不重要,尽管出于某些原因我更喜欢这种方式 - 也许在重构过程中减少可能的错误并为了清晰起见确实有点重要 - 但在其他情况下你不这样做无需以这种方式访问该值,因此您必须这样做。参考您在其他答案中的评论;下划线只是告诉编译器您不需要使用该值的一种方式,因此您不需要为其命名。
我在 f# 中有以下非常简单的函数:
let private addOnsFromDto (addOns: MyType1 []) =
let typedList = List.empty<MyType2>
match addOns with
| null -> typedList
| _ -> List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2)
f# 编译器抱怨此错误消息:
All branches of a pattern match expression must return values of the same type as the first branch, which here is 'MyType2 list'. This branch returns a value of type 'MyType1 list -> MyType2 list'.
我知道在第一个分支上我有一个 'MyType2 list'。我知道在第二个分支上我有一个从列表映射到列表的函数 'MyType2 list' 所以编译器抱怨两个分支的类型不一致是有道理的。
但是,鉴于第二个分支的输出与第一个分支的输出类型相同,我希望编译器可以正常工作。我是否需要做一些事情来“强制” List.map 函数的评估,以便这两种类型是等价的?如果是这样,我该如何实现?
解决方案
对于任何认为有用的解决方案,正如有用的答案所解释的那样,我需要将原始列表通过管道传输到 map 函数中,以便提供两个参数。
let private addOnsFromDto (addOns: MyType1 []) =
let typedList = List.empty<MyType2>
match addOns with
| null -> typedList
| _ -> addOns
|> Array.toList
|> List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2)
List.map
接受两个参数,但您只提供了一个。您需要将输入列表添加为参数:
List.map<MyType1 , MyType2> (fun a -> MyType2.create a.Prop1 a.Prop2) addOns
或者更通俗地说:
addOns |> List.map (fun a -> MyType2.create a.Prop1 a.Prop2)
错误信息This branch returns a value of type 'MyType1 list -> MyType2 list'.
实际上是在告诉你这里缺少一个参数。这就是部分应用程序的工作原理。如果您没有提供足够的参数,您通常会收到这样的消息,其中包含一个带箭头的类型。缺少的参数是MyType1 list
类型的addOns
的数据,所以addOns需要先从MyType1 array
转换为MyType1 list
。
这就是我得出的结论。我已经包含了虚拟类型,因此它可以自行编译。还删除了类型注释以方便阅读。当您提出问题时,如果您能提供可编译的代码就好了。
type MyType1 = { Prop1: int; Prop2: float }
type MyType2 = { Prop1: int; Prop2: float }
with
static member create p1 p2 = { MyType2.Prop1 = p1; Prop2 = p2 }
let private addOnsFromDto (addOns: MyType1 array) =
match addOns with
| null -> []
| addOns ->
addOns
|> Array.toList
|> List.map (fun a -> MyType2.create a.Prop1 a.Prop2)
更新,附加说明:我在最后一个匹配案例中使用了阴影声明 addOns
而不是下划线。在这种情况下,以这种方式还是使用下划线可能并不重要,尽管出于某些原因我更喜欢这种方式 - 也许在重构过程中减少可能的错误并为了清晰起见确实有点重要 - 但在其他情况下你不这样做无需以这种方式访问该值,因此您必须这样做。参考您在其他答案中的评论;下划线只是告诉编译器您不需要使用该值的一种方式,因此您不需要为其命名。