我在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列表'。我明白,在第二个分支上,我有一个函数,它从列表映射到列表'MyType2列表',所以它是有意义的,编译器抱怨跨两个分支不一致的类型。
然而,假设第二个分支的输出与第一个分支的输出类型相同,我希望编译器没问题。我需要做些什么来"强迫"吗?评估该名单。Map函数使两种类型相等?如果是这样,我该如何做到这一点?
<解决方案/strong>
对于那些发现它有用的人来说,正如有用的答案所解释的那样,解决方案是我需要将原始列表管道到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
的阴影声明,而不是下划线。在这种情况下,也许用这种方式还是用下划线来完成并不重要,尽管我更喜欢这种方式——也许在重构过程中减少可能出现的错误,以及为了清晰——但在其他情况下,如果不这样做,就无法访问值,所以必须这样做。参考你在另一个答案中的评论;下划线只是告诉编译器你不需要使用该值的一种方式,所以你不需要为它命名。