【问题标题】:F# Match is failing type comparison between 'T list' vs ''a list -> 'b list'F# Match 在 'T list' 与 ''a list -> 'b list' 之间的类型比较失败
【发布时间】:2021-09-24 22:31:03
【问题描述】:

我在 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 列表”的函数,因此编译器抱怨两个分支之间的类型不一致是有道理的。

但是,鉴于第二个分支的输出与第一个分支的输出类型相同,我希望编译器正常。我是否需要做一些事情来“强制”评估 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 接受两个参数,而不是一个。

标签: .net f#


【解决方案1】:

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)

【讨论】:

  • 谢谢。我误解了 match 语句中的 | _ -&gt; 语法是将 addOns 变量传递到 map 函数中!
【解决方案2】:

错误信息This branch returns a value of type 'MyType1 list -&gt; 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 的阴影声明,而不是下划线。在这种情况下,无论是采用这种方式还是使用下划线,都可能无关紧要,尽管出于某种原因,我更喜欢这种方式——也许在重构过程中减少可能的错误以及为了清晰起见,这在某种程度上很重要——但在其他情况下,你不需要如果不这样做,就无法访​​问该值,因此您必须这样做。参考您在另一个答案中的评论;下划线只是告诉编译器您不需要使用该值的一种方式,因此您不需要为其命名。

【讨论】:

  • 谢谢 - 这种类型的错误通常与部分应用程序相关的解释非常有帮助。我以前见过几次,但我认为我以前不理解这一点。下次我会知道去哪里看的!
猜你喜欢
  • 2016-09-16
  • 1970-01-01
  • 2019-10-23
  • 2018-04-30
  • 2019-12-09
  • 2021-07-06
  • 2012-06-07
  • 2011-12-18
  • 1970-01-01
相关资源
最近更新 更多