Шаблоны функций
Вы взяли часто используемые выражения и превратили их в функции. Теперь ваш код выглядит лучше и читать его стало легче. Когда вы приобретете достаточный опыт использования функций, настанет время обратить внимание на существующие эффективные шаблоны. Используя эти шаблоны, вы получаете код, который проще читать и поддерживать.
Сравнение декларативного и императивного подходов
Работу над кодом, вы, скорее всего, начинаете с записи выражения. Затем вы пишете еще одно выражение, потом другое и т. д. Вам нужно решить проблему, и вы подбираете конкретное решение. Этот подход называется императивным подходом. В нем ничего плохого нет, поскольку он решает возникшую проблему. Но есть еще один маршрут, который является декларативным подходом. Пример декларативного подхода — это запрос к базе данных с помощью SQL.
В нем используются выражения, аналогичные следующему:
SELECT *
FROM Students s
WHERE s.Location = "Ohio"
Что делает этот код декларативным, заключается в том, что вы просите о том, что хотите, но вы не указываете , как вы хотите решить проблему. Вы оставляете как для SQL.
Этот подход также можно применить к F#. В следующем коде используется декларативный подход:
let studentsFromOhio =
allStudents
|> filterLocation "Ohio"
В представленном выше коде вы работаете с данными и указываете, что вам нужно, не уточняя, как это должно быть сделано. Когда ваш код выглядит так, как в приведенном выше примере, его легко читать и понимать. Чтобы этого добиться, рассмотрим некоторые полезные шаблоны, поддерживаемые в F#.
Функциональные шаблоны
В F# есть некоторые полезные шаблоны, которые можно использовать для более функционального подхода. Рассмотрим следующие из них.
- Композиция: композиция объединяет несколько функций в одну функцию.
- Конвейер: конвейер начинается со значения, а затем последовательно вызывает несколько функций, используя выходные данные одной функции в качестве входных данных для следующей функции.
Создание
Композиция — это объединение функций и применение их друг за другом в определенном порядке. Оператор композиции применяется к двум функциям и возвращает новую функцию.
Когда вы пишете код, вам часто приходится вызывать одну функцию, а сразу после нее другую. Например, вы хотите упорядочить список и отфильтровать все продукты со скидкой.
В следующем примере вызывается функция add2(), а ее результат передается в функцию multiply3().
let add2 a = a + 2
let multiply3 a = a * 3
let addAndMultiply a =
let sum = add2 a
let product = multiply3 sum
product
printfn "%i" (addAndMultiply 2) // 12
Этот шаблон настолько распространен, что в языке F# есть отдельный оператор для него. Оператор >> позволяет объединить несколько функций в одну более крупную функцию. Оператор >> можно использовать для упрощения приведенного выше кода, например следующим образом:
let add2 a = a + 2
let multiply3 a = a * 3
let addAndMultiply = add2 >> multiply3
printfn "%i" (addAndMultiply 2) // 12
Объединенная функция addAndMultiply() применяет функции, которые она включает, слева направо. В этом примере сначала выполняется функция add2(), а затем multiply3().
Трубопровод
Оператор конвейера |> получает функцию и аргумент и возвращает значение. Давайте на следующем примере рассмотрим, чем конвейер отличается от композиции:
let list = [4; 3; 1]
let sort (list: int list) = List.sort list
let print (list: int list)= List.iter(fun x-> printfn "item %i" x) list
list |> sort |> print // item 1 item 3 item 4
В последней строке кода вы начинаете со списка целых чисел, используя list, который служит входными данными для первой функции sort(). Результат этой операции передается в print(). Главное отличие между конвейером и композицией заключается в том, что в конвейере сначала указываются данные (в данном случае список целых числе), а затем набор функций.