Любое серьезное программирование на любом языке всегда будет включать списки. Таким образом, вам будет приятно узнать, что F# очень и очень хорошо поддерживает списки с помощью своего модуля List. Список в F# — это упорядоченная, неизменная серия элементов одного типа.
В F# есть несколько путей, которыми Вы можете создать список.
В последнем примере, показанном выше, показано, как использовать цикл for для создания списка, что очень круто, но в наборе инструментов F # есть что-то еще более крутое и мощное, а именно «List Comprehensions».
List Comprehensions(понимание списков?) — это мощный метод, который позволяет вам создавать списки, используя в значительной степени стандартный F#, который включает функции / циклы / условия и т.д.
Давайте продолжим смотреть на пример того, как мы могли бы создавать списки.
Мы можем использовать оператор cons «::» для добавления значений в существующий список, поэтому предположим, что у нас был этот список:
Другим весьма полезным оператором является оператор «@», который позволяет объединять списки одного типа. Так, например, если бы у нас было это:
Я не думаю, что перебарщиваю, когда говорю, что модуль List является ключевым модулем в F#. Фактически, документация MSDN для него очень хороша по сравнению с другими в F#. Поэтому я не думаю, что смогу добавить много полезного к примерам, найденным на MSDN, но я приведу здесь несколько для вашего удобства, но для получения дополнительной информации вы должны изучить MSDN.
IsEmpty
bool
true — если в списке нет элементов
Item
‘T
Элемент, который находится по специфическому индексу
Length
int
Количество элементов
Tail
‘T list
Список без первого элемента:
Возвращает новую коллекцию, содержащую только элементы коллекции, для которой данный предикат возвращает true. Вот тривиальный пример, который выбирает только четные числа из списка для создания нового списка
Возвращает первый элемент, для которого данная функция возвращает true. В этом примере, поскольку список от 1 до 100 содержит 5, 5 — это 1-е число, которое делится на 5, поэтому это возвращаемое значение:
Проверяет, все ли элементы коллекции удовлетворяют данному предикату. В этом примере весь список должен содержать 0, чтобы получить истинное возвращаемое значение.
Применяет данную функцию к каждому элементу коллекции. Целое число, переданное функции, указывает на индекс элемента.
Сортирует указанный список, используя данную функцию сравнения.
В модуле списка есть множество полезных функций, это лишь малая часть того, что можно найти.
Никакое обсуждение списков не будет полным без разговора о рекурсии.Рекурсия — это то, чему будет посвящен целый пост, но сейчас давайте рассмотрим, что нужно, чтобы написать рекурсивную функцию, которая работает над списком в F#.
Обратите внимание на использование ключевого слова rec , которое сообщает компилятору F #, что эта функция будет рекурсивной. Без этого ключевого слова рекурсивный вызов функции — Вы получите сообщение о ошибке компиляции, хотя и с не очень понятным текстом о ошибке.
Итак, давайте посмотрим результаты выполнения примера, показанного чуть выше со следующим списком [1; 2; 3; 4; 5]
Можно видеть, что все работает просто отлично, и оно прекращает работу, когда значение соответствует пустому списку, как и ожидалось.
Создаем список
В F# есть несколько путей, которыми Вы можете создать список.
- Создаём пустой список
- Создаем простой список с элементами от 1 до 10
- Создаем список с нечетными номерами в промежутке от 1 до 10
- Используем цикл for для создания списка
let prettyPrint desc list =
printfn desc
printfn "%A" list
//empty list
let listEmpty = []
//simple list
let list1 = [1 .. 10 ]
//simple list, with step value
let list2 = [1 ..2..10 ]
//using for loops to create lists
let list3 = [for i in 1 .. 10 -> i*2 ]
prettyPrint "let listEmpty = []" listEmpty
prettyPrint "let list1 = [ 1 .. 10 ]" list1
prettyPrint "let list2 = [ 1 .. 2..10 ]" list2
prettyPrint "[ for i in 1 .. 10 -> i*2 ]" list3
В последнем примере, показанном выше, показано, как использовать цикл for для создания списка, что очень круто, но в наборе инструментов F # есть что-то еще более крутое и мощное, а именно «List Comprehensions».
List Comprehensions(понимание списков?) — это мощный метод, который позволяет вам создавать списки, используя в значительной степени стандартный F#, который включает функции / циклы / условия и т.д.
Давайте продолжим смотреть на пример того, как мы могли бы создавать списки.
let is2 x = match x with
| 2 -> "YES"
| _ -> "NO"
//yield directly
let list1 = [
yield 1;
yield 2;
yield 3;
]
//yield numbers between 1 and 20 where we use the
//Math.Pow function to return a new number
let list2 = [for i in 1.0 .. 20.0 do
yield Math.Pow(i,2.0)
]
//yield only numbers between 1 and 20 that
//can be divided by 5
let list3 = [
for i in 1 .. 20 do
if i % 5 = 0 then
yield i
]
//yields YES/NO strings depending on
//whether source int = 2 or not
let list4 = [for i in 1 .. 5 ->
is2 i
]
Некоторые полезные операторы списков
Оператор Cons
Мы можем использовать оператор cons «::» для добавления значений в существующий список, поэтому предположим, что у нас был этот список:
let list1 = [1;2;3;4]
let list2 = 42 :: list1
Оператор конкатенации
Другим весьма полезным оператором является оператор «@», который позволяет объединять списки одного типа. Так, например, если бы у нас было это:
let list1 = [1;2;3;4]
let list2 = [5;6;7;8]
let list3 = list1 @ list2
Модуль List
Я не думаю, что перебарщиваю, когда говорю, что модуль List является ключевым модулем в F#. Фактически, документация MSDN для него очень хороша по сравнению с другими в F#. Поэтому я не думаю, что смогу добавить много полезного к примерам, найденным на MSDN, но я приведу здесь несколько для вашего удобства, но для получения дополнительной информации вы должны изучить MSDN.
Свойства
Head
‘T
Первый элементEmpty
‘T list
Возвращает пустой список, заданного типаIsEmpty
bool
true — если в списке нет элементов
Item
‘T
Элемент, который находится по специфическому индексу
Length
int
Количество элементов
Tail
‘T list
Список без первого элемента:
let list1 = [ 1; 2; 3 ]
// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))
Фильтр(filter)
Возвращает новую коллекцию, содержащую только элементы коллекции, для которой данный предикат возвращает true. Вот тривиальный пример, который выбирает только четные числа из списка для создания нового списка
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
Поиск(find)
Возвращает первый элемент, для которого данная функция возвращает true. В этом примере, поскольку список от 1 до 100 содержит 5, 5 — это 1-е число, которое делится на 5, поэтому это возвращаемое значение:
Для всех(forall)
Проверяет, все ли элементы коллекции удовлетворяют данному предикату. В этом примере весь список должен содержать 0, чтобы получить истинное возвращаемое значение.
let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])
Применить ко всех(Iteri)
Применяет данную функцию к каждому элементу коллекции. Целое число, переданное функции, указывает на индекс элемента.
let data = ["Cats";"Dogs";"Mice";"Elephants"]
data |> List.iteri (fun i x -> printfn "item %d: %s" i x)
Сортировать по(SortWith)
Сортирует указанный список, используя данную функцию сравнения.
let list1 = [ ""; "&"; "&&"; "&&&"; ""; "|"; "||"; "|||" ]
printfn "Before sorting: "
list1 |> printfn "%A"
//custom sorting function
let sortFunction (string1:string) (string2:string) =
if (string1.Length > string2.Length) then
1
else if (string1.Length printfn "After sorting:\n%A"
В модуле списка есть множество полезных функций, это лишь малая часть того, что можно найти.
Небольшой взгляд на рекурсию над списками
Никакое обсуждение списков не будет полным без разговора о рекурсии.Рекурсия — это то, чему будет посвящен целый пост, но сейчас давайте рассмотрим, что нужно, чтобы написать рекурсивную функцию, которая работает над списком в F#.
let printIt desc x =
printfn "%A %A" desc x
let rec printList list =
match list with
| h :: t ->
printIt "head=" h
printIt "tail=" t
printList t
| [] -> ()
printList [1;2;3;4;5]
Обратите внимание на использование ключевого слова rec , которое сообщает компилятору F #, что эта функция будет рекурсивной. Без этого ключевого слова рекурсивный вызов функции — Вы получите сообщение о ошибке компиляции, хотя и с не очень понятным текстом о ошибке.
Итак, давайте посмотрим результаты выполнения примера, показанного чуть выше со следующим списком [1; 2; 3; 4; 5]
Можно видеть, что все работает просто отлично, и оно прекращает работу, когда значение соответствует пустому списку, как и ожидалось.
Комментарии (3)
Nikolai46
18.10.2019 17:41Обратите внимание на использование ключевого слова rec
Не знаю как кому, но для меня вот эти непонятные сокращения (fun/rec/elif) сильно демотивируют от использования языка.
tweekaz Автор
<фото>
</фото>
Несмотря на то, что с разметкой все нормально, почему-то часть поплыла.
Могу только извиниться за это :(
TheShock
Просто оберните инлайн куски кода в тег code: