Не удается вернуть начало списка

#f#

#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
  

Ответ №1:

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. Да, а также мне пришлось заключить функцию и ее аргументы в круглые скобки как yield (findGovernment gov subGov), чтобы она работала, что изначально меня сбило с толку. Не уверен, почему это так.

2. @user1206480 : Он компилируется чисто, без скобок здесь

Ответ №2:

Подумайте об этом: какой тип возврата имеет ваша findGovernment функция?

Если вы посмотрите на инструкцию целиком, то можно было бы ожидать, что это будет Government — поскольку вы возвращаете результат вызова List.head чего-то, что предположительно является Government list .

Однако, если вы заглянете внутрь определения списка, там есть строка yield! findGovernment ... . Поскольку yield! инструкция ожидает, что аргумент будет иметь тип seq<_> , из этого следует, что findGovernment должен возвращать последовательность чего-либо.

Так что же он возвращает в конце концов? Один Government или их последовательность? Компилятор не может решить за вас, поэтому он жалуется.

Я думаю, что ваша ошибка заключается в чрезмерной разработке.
Сначала давайте просто подумаем о проблеме: для Root и Node случаев результатом является этот узел, если он совпадает, в противном случае результат находится где-то в 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
  

Я знаю, это кажется глупым, но в этом суть: если вы доводите свою логику до окончательного вывода, и этот вывод оказывается глупым, это означает, что с логикой с самого начала было что-то не так.