不能返回列表的头部

时间:2016-10-20 04:09:46

标签: f#

我只是想从列表中检索头部,但我收到的错误表明The type 'Government' is not compatible with the type 'seq<government>'.

type Government = {
    Id : Id;
    Name : string;
    Abbreviation : string;
    ParentId : string option;
}

type GovernmentStructure<'gov> = 
    | Root of Government : 'gov * SubGov : GovernmentStructure<'gov> list
    | Node of Government : 'gov * SubGov : GovernmentStructure<'gov> list
    | Leaf of Government : 'gov

let rec findGovernment (gov : Government) (governmentStructure : GovernmentStructure<Government> list) =

    [
        for x in governmentStructure do
            match x with
            | Root(gov', subGov) ->
                 if gov = gov' then yield gov' else yield! findGovernment gov subGov
            | Node(gov', subGov) ->
                 if gov = gov' then yield gov' else yield! findGovernment gov subGov
            | Leaf(gov') ->
                 if gov = gov' then yield gov'
    ] |> List.head // This is where I get the error

2 个答案:

答案 0 :(得分:3)

findGovernment返回单个项目(从List.head返回的项目),而不是集合。因此,您希望在递归调用时使用yield,而不是yield!

let rec findGovernment (gov : Government)
                       (governmentStructure : GovernmentStructure<Government> list) =
    [
        for x in governmentStructure do
            match x with
            | Root(gov', subGov) ->
                if gov = gov' then yield gov' else yield findGovernment gov subGov
            | Node(gov', subGov) ->
                if gov = gov' then yield gov' else yield findGovernment gov subGov
            | Leaf(gov') ->
                if gov = gov' then yield gov'
    ] |> List.head

答案 1 :(得分:3)

想一想:findGovernment函数有哪些返回类型?

如果你查看整个陈述,那么人们会认为它是Government - 因为你要回复调用List.head的结果可能是Government list

但是,如果您查看列表定义,则会有一行yield! findGovernment ...。由于yield!指令期望参数为seq<_>类型,因此findGovernment必须返回一系列内容。

那么它毕竟是什么回归?一个Government或其序列?编译器无法为您做出决定,所以它会抱怨。

我认为你的错误是过度工程 首先,我们只考虑一下问题:对于RootNode个案例,结果是该节点匹配,否则结果位于SubGov;对于Leaf情况,如果匹配则结果是叶子 让我们写下来:

match x with
| Root(g, _) | Node(g, _) when g = gov -> g
| Root(_,sub) | Node(_, sub) -> findGovernment gov sub
| Leaf g when g = gov -> g

但是等等,现在我们立即在这个算法中看到一个漏洞:如果查找值根本不在结构中怎么办?该函数应该返回什么?实际上有两个选项:return Government option,表示可能没有返回值,或者只是崩溃。让我们简单地让它崩溃,现在:

match x with
| Root(g, _) | Node(g, _) when g = gov -> g
| Root(_,sub) | Node(_, sub) -> findGovernment gov sub
| Leaf g when g = gov -> g
| _ -> failwith "Can't find it."

但是现在,仔细观察:每次你返回一些东西,你只是在将某些东西与gov进行比较之后才这样做。换句话说,此函数可以返回的唯一值是等于gov的值。所以问题是:为什么不返回gov

let findGovernment gov = gov

我知道,这看起来很愚蠢,但重点是:如果你把你的逻辑推向最终结论,而这个结论结果证明是愚蠢的,那就意味着逻辑开始有问题。