Set.union F#麻烦

时间:2016-02-15 02:43:09

标签: f#

我有Set<String*String>,我正在尝试编写一个函数,该函数接受该Set的所有元素并返回Set<String>。我的想法是使用Set.fold,并有一个空集累加器并采用两个集合的并集,但我遇到了问题。这是代码:

type Chart = Set<Country*Country>;;

let countriesInChart (chart : Chart) =
  Set.fold(fun (x,y) set -> Set.union [x;y] set ) chart []

但是我收到了这个错误

        Set.fold(fun (x,y) set -> Set.union [x;y] set ) chart [];;
  --------------------------------^^^^^^^^^^^^^^^^^^^
error FS0001: This expression was expected to have type
    'a * 'b    
but here has type
    Set<'c>    

2 个答案:

答案 0 :(得分:4)

查看您的类型和功能签名。

Set.fold'State -> 'T -> 'State作为folder函数。 'State是您要折叠的类型,它将是最终的返回值,因此在这种情况下,您希望它的类型为Set<Country>

这意味着你的lambda不能正确,因为第一个参数是一个元组。所以我们应该切换那个lambda的参数:

let countriesInChart (chart : Chart) =
    Set.fold(fun set (x,y) -> Set.union [x;y] set ) chart []

编译给我们

(96,39): error FS0001: This expression was expected to have type
    Set<'a>
but here has type
    'b list
在这种情况下,

(96,39)是Set.union函数,当然没有正确使用,因为它需要两个集合,但我们传递一个集合和一个列表。我们可以使用Set.ofList

从列表中创建一个集合
let countriesInChart (chart : Chart) =
    Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart []

同样,我们得到了一个不同的错误,所以我们可能正在取得进展:

(96,80): error FS0001: This expression was expected to have type
    Set<(Country * Country) * (Country * Country)>
but here has type
    'a list

(96,80)是该行末尾的空列表 - 当然,这是错误的,因为Set.fold的第三个参数需要是Set<'T>。空列表的集合替换为Set.empty,所以让我们继续:

let countriesInChart (chart : Chart) =
    Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart Set.empty

它汇编!但正如您所发现的那样,它会返回Set<Country * Country>而不只是Set<Country>

这样的情况是,当类型推断使得查看正在发生的事情变得有点困难时,我们应该继续添加类型注释,我们确切地知道类型需要什么。最明显的地方是函数的返回类型:

let countriesInChart (chart : Chart) : Set<Country> =
    Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart Set.empty

现在错误是:

(96,74): error FS0001: Type mismatch. Expecting a
    Set<Country>    
but given a
    Chart    
The type 'Country' does not match the type 'Country * Country'

该错误是针对Set.fold的第二个参数,原因是再一次,参数的顺序错误。 Set.fold的签名是('State -> 'T -> 'State) -> 'State -> Set<'T> -> 'State。如果我们查看已有的内容,则'State在这种情况下为Set<Country>'TCountry * Country。这意味着Set.empty需要成为第二个chart最后一个参数,所以我们到达

let countriesInChart (chart : Chart) =
    Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) Set.empty chart

函数式编程最重要的规则是:让类型引导你! ; - )

答案 1 :(得分:0)

试试这个:

let f (chart: Chart) =
  Set.fold (fun (x:Set<string>) (a,b) -> x |> Set.add a |> Set.add b) Set.empty chart

我不确定类型注释是否必要,但它确实强制输出为Set<string>