F# имеет эквивалент взятию Haskell?

В Haskell существует функция, "берут список n", который возвращает первые n элементы из списка. Например, "сумма (берут 3 xs)" подводит итог первых трех элементов в списке xs. F# имеет эквивалент? Я ожидал, что это будет одной из функций Списка, но я не могу определить ничего, что, кажется, соответствует.

14
задан McMuttons 13 April 2010 в 20:08
поделиться

3 ответа

Да, это называется Seq.take . Использование похоже на использование Haskell's: Seq.take count source . Чтобы использовать его в списке, сначала используйте List.toSeq . (Обновление: очевидно из комментариев, в этом нет необходимости.)

16
ответ дан 1 December 2019 в 05:58
поделиться

Чтобы прояснить некоторые моменты, разница между Seq.take и Seq.truncate (как указано @ sepp2k) заключается в том, что второй из них даст вам последовательность, которая возвращает самое большее количество элементов, которые вы указали (но если длина последовательности меньше, это даст вам меньше элементов).

Сгенерированная последовательность Seq.take вызовет исключение, если вы попытаетесь получить доступ к элементу, превышающему длину исходного списка (обратите внимание, что функция Seq.take не работает » t немедленно генерировать исключение, потому что результатом является лениво сгенерированная последовательность).

Кроме того, вам не нужно явно преобразовывать список в последовательность. Под обложкой list <'a> - это класс .NET, который наследуется от типа seq <' a> , который является интерфейсом. Тип seq <'a> на самом деле является просто псевдонимом типа для IEnumerable <' a> , поэтому он реализуется всеми другими коллекциями (включая массивы, изменяемые списки и т. Д.) . Следующий код будет работать нормально:

let list = [ 1 .. 10 ]
let res = list |> Seq.take 5

Однако, если вы хотите получить результат типа list , вам необходимо преобразовать последовательность обратно в список (поскольку список является более конкретным типом чем последовательность):

let resList = res |> List.ofSeq

Я не уверен, почему библиотеки F # не предоставляют List.take или List.truncate .Я предполагаю, что целью было избежать повторной реализации всего набора функций для всех типов коллекций, поэтому те, в которых реализация последовательностей достаточно хороша при работе с более конкретным типом коллекции, доступны только в модуле Seq (но это только мое предположение ...)

44
ответ дан 1 December 2019 в 05:58
поделиться

Seq.take работает, как уже говорили другие, но все операции Seq в списке имеют свою цену . В случае с Seq.take это неудивительно, ведь список приходится копировать.

Примечательно, что, например, Seq.concat в списке занимает намного больше времени, чем List.concat. Я полагаю, это подразумевает, что вы не просто получаете доступ к списку как seq при вызове функции Seq.xxx, но что список также копируется / конвертируется в Seq за кулисами.

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

#time "on";;
let lists = [for i in 0..5000000 -> [i..i+1]];;
Seq.length (Seq.concat lists);;
List.length (List.concat lists);;

На моем компьютере версия List.length занимает около 1,9 секунды , тогда как версия Seq.length занимает около 3,8 секунды (самое короткое время из нескольких повторных тестов только длинных строк, исключая строку генерации списка).

1
ответ дан 1 December 2019 в 05:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: