Поговорили про базовые примитивы, списки и т. п., что с функции можно передавать там и так далее, что в List прячется много библиотечных функций, типа head, nth, length. Продолжим с конца прошлого файла.
In [1]:
13 :: []
Out[1]:
На самом деле всегда, когда мы пишем обычные списки, на самом деле это лишь синтаксический сахар для такой конструкции:
In [2]:
1 :: 2 :: 3 :: []
Out[2]:
Кроме того, можно перечислять:
In [3]:
[1..4]
Out[3]:
Можно вернуть голову списка, хвост. Интересно, как работает с пустыми!
In [11]:
List.head [1..5]
[1..2..5] // С шагом 2 от 1 до 5.
[1..-2..-4]
// List.head [] // Будет ошибка, а что же еще!
List.tail [13] // Это будет пустой список!
List.isEmpty []
Out[11]:
Давайте писать функцию проверки на пустоту самостоятельно.
In [15]:
List.empty = []
// let isEmpty x = if x = List.empty then true else false // Ужас.
let isEmpty x = x = List.empty
Сопоставление с образцом.
In [18]:
let isEmpty x =
match x with // Типа switch.
| [] -> true // Если пуской список.
| _ -> false // Подчеркивание, это как бы все, что угодно.
In [26]:
let isEmpty = function // Наперед, пока не вникаем.
| [] -> true
| _ -> false
Если хотим написать рекурсивную функцию, то используем let.
In [23]:
let rec length xs =
if List.isEmpty xs
then 0
else 1 + length (List.tail xs)
In [24]:
let rec length xs =
match xs with
| [] -> 0
| y :: ys -> 1 + length ys
Есть замечательный модуль Seq, представляющих некоторые последователности. В F# нет бесконечных списков (в отличие от Haskell), однако есть бесконечные последовательности. Это похоже на генераторы в Python.
In [25]:
[1, 2, 3, 4] // Список из кортежа (1, 2, 3, 4)
Out[25]:
In [27]:
Seq.take 4 (Seq.initInfinite (fun i -> i + 1)) // Тоже пока не вникаем.
// Интерпретатор остановился на первых четырех элементов.
Out[27]:
Упражнение написать take. Это поможет понять рекурсию.
In [30]:
let rec take n xs =
if n = 0 then []
else (List.head xs) :: (take (n - 1) (List.tail xs))
take 4 [1..10]
Out[30]:
In [37]:
let (a, b, c) = (1, 2, 3) // todo понять.
In [38]:
List.min ['a'..'z'] // Так тоже можно!
Out[38]:
In [39]:
// todo раньше есть реализация get.
let elem what list = get list what > 0
Но вообще можно использовать стандартную.
In [41]:
List.exists (fun x -> x = 2) [1..8]
Out[41]:
In [59]:
let rec sum list =
match list with
| [] -> 0
| y::ys -> y + (sum ys)
let max a b = if a > b then a else b
let rec maxEl list =
match list with
| [] -> int -Operators.infinity // Говнокодим, как можем!
| y::ys -> max y (maxEl ys)
sum [1..5]
maxEl [1..5]
maxEl [1]
Out[59]:
In [61]:
int -Operators.infinity // А что это на самом деле? Нижнее ограничение int.
Out[61]:
Описать функцмю, которая для данного $n$ создает список из всех попарных чисел от 1 до $n$. То есть $n^2$ элементов.
Подсказка: используем конкатенацию: [1;2;3] @ [5;6;7].
In [75]:
// Сначала напишем прибавление ко всем элементам 1.
let rec add x n =
match x with
| [] -> []
| y::ys -> (y + n) :: (add ys n)
let rec listSq x =
match x with
| [] -> []
| y::ys -> (add [y] (List.length x)) @ (listSq ys)
listSq [3..5] // Вызываем дьявола.
Out[75]:
In [ ]: