2016-10-09 3 views
4

Я хочу, чтобы получить последний элемент списка и моя логика заключается в обратном список и получить его голова:Получить последний элемент списка в F #

module Program1 = 

    let last list = 
     let newList=List.rev list; 
     List.head newList; 
     newList 

    let mainP1()= 
     let list= [ 1; 2; 3] 
     printfn "Ultimul element al listei %A este %A" list (last list) 

, но это дает мне эту ошибку

Error  Type mismatch. Expecting a 
    unit list  
but given a 
    int list  
The type 'unit' does not match the type 'int' 

Может ли кто-нибудь мне помочь?

+1

Там есть встроенная функция для этого: 'List.last'. Это домашнее задание? –

ответ

5

Здесь довольно много распаковать.

Первый, ваша функция не возвращает то, что вы хотите вернуть. Посмотрите, что последняя строка там, та, которая говорит newList? Это возвращаемое значение вашей функции. Последняя строка тела функции - это возвращаемое значение. Таким образом, вы возвращаете обратный список, а не последний элемент.

Второй, так как вы не возвращает результат List.head вызова, вы игнорируя его. Не делайте ничего с этим результатом. Не обращая внимания. И компилятор F # пытается помочь вам здесь: если вы игнорируете значение, это означает, что вы делаете что-то неправильно, и F # будет жаловаться (выдавать предупреждение), если вы это сделаете.

Но есть одно исключение из этого правила: вы можете игнорировать значение типа unit. Логика идет, если у вас есть значение типа unit, вы должны получить его в результате создания побочного эффекта. Потому что, если не было побочного эффекта, и нет никакого результирующего значения (unit означает «нет значения»), то в чем смысл?

Итак, компилятор думает так: если вы проигнорировали значение, то это значение должно быть типа unit. А так как List.head newList имеет тип unit, то newList должен быть типа unit list. И поэтому list должен быть типа unit list. И поэтому ваша функция имеет тип unit list -> unit list (то есть она принимает параметр unit list в качестве параметра и возвращает результат unit list).

И так как вы пытаетесь передать int list в функцию, которая принимает unit list, компилятор не выдержит это: Expecting a unit list but given a int list.

И, наконец,, переходящий список, чтобы получить его последнее значение, настолько расточительно! Вы перераспределяете целую кучу памяти, которая вам действительно не нужна. Менее расточительный способ добиться этого - использование рекурсии. Подумайте об этом так: последний элемент одноэлементного списка состоит в том, что один элемент, а последний элемент более длинного списка - последний элемент его хвоста. Мы можем написать, что прямо в F #:

let rec last list = 
    match list with 
    | [x] -> x // The last element of one-element list is the one element 
    | _::tail -> last tail // The last element of a longer list is the last element of its tail 
    | _ -> failwith "Empty list" // Otherwise fail 

Плюс, есть готовая функция List.last, что вы можете просто использовать (если это не домашнее задание, и в этом случае следует отметить, что в этом вопросе).

let mainP1()= 
    let list= [ 1; 2; 3] 
    printfn "Ultimul element al listei %A este %A" list (List.last list) 

Остерегайтесь, однако, что не может быть последний элемент в списке - если список пуст. В этом случае List.last (а также List.head) будет сбой с исключением, что, как правило, не очень хорошая идея.Если вам нужно обработать случай пустого списка, смотрите на List.tryLast вместо:

let mainP1()= 
    let list= [1; 2; 3] 
    match List.tryLast list with 
    | Some x -> printfn "Ultimul element al listei %A este %A" list x 
    | None -> printfn "Lista %A este goală" list 
+3

Неизменяемый связанный список aka 'FSharp.Collections.List <'T>' не так эффективен для случайного доступа: весь список должен быть пройден, следовательно, O (n). 'List.rev' не лучше или хуже этого. – kaefer

+0

@kaefer ты прав. По какой-то причине у меня создалось впечатление, что F # там обманывает производительность, [как это происходит с List.map] (https://github.com/fsharp/fsharp/blob/84b6da1bfcdc748ba1a79444f70e04708c6d3324/src/fsharp/FSharp.Core/ local.fs # L238), но, по-видимому, это не так. Я удалю этот пункт из ответа. –

Смежные вопросы