Быстрое функциональное программирование: основные понятия

Что-то вроде обратного Бойцовского клуба для разработчиков

Обычно люди, изучающие функциональное программирование (также известное как FP), не затыкаются по этому поводу до такой степени, что было бы почти раздражительно, если бы это было не так чертовски круто. Представьте себе знаменитую сцену культового классического фильма 1999 года Бойцовский клуб, но полностью перевернувшуюся с ног на голову.

Правила Клуба функционального программирования:
1. Вы не молчите о функциональном программировании.
2. Вы НЕ молчите о функциональном программировании!

Некоторые люди также сравнивают функциональных программистов с энтузиастами кроссфита, но, в отличие от кроссфита, у функционального программирования нет 73,5% вероятности того, что вы получите травму, мешающую вам работать. Это на самом деле улучшает безопасность, читаемость и общую привлекательность кода, который вы пишете.

Swift ни в коем случае не является чисто функциональным языком программирования, таким как Haskell, это скорее красивый язык Франкенштейна / мультипарадигмы, который берет отдельные фрагменты других языков и объединяет их друг с другом.

В этой первой части мы рассмотрим более простые концепции функционального программирования и продемонстрируем, как язык Swift позволяет нам писать функциональный код.

Базовые концепты

Неизменность

let foo = 1

Самый простой для понимания: неизменяемость просто означает, что после того, как значение установлено, его нельзя изменить, и мы делаем это в Swift, используя ключевое слово let при создании значений.

Причина неизменности в том, что она позволяет нам как разработчикам писать поточно-ориентированный код. Мы можем работать с объектами, зная с полной уверенностью, что другие потоки в нашем приложении не могут изменять значения, когда мы их используем.

Типы значений

struct CGRect { }

Когда мы передаем значения вместо ссылок на значения, мы создаем более безопасный код. Структуры также являются отличным примером этого, почти все в стандартной библиотеке Swift - это структуры: Array, Dictionary, Int, Bool и т. Д. - это все структуры.

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

var box = CGRect.zero
var square = box.size
box.size.height = 10
// square: width: 0, height: 0
// box.size: width: 0, height: 10

Если бы CGRect и CGSize были ссылочными типами, а не типами значений, высота square также изменилась бы на 10, когда мы изменили высоту box.

box.size.height = 10
// square: width: 0, height: 10
// box.size: width: 0, height: 10

Чистые функции

func sum(_ a: Int, _ b: Int) -> Int { 
    return a + b 
}

Функция, возвращаемое значение которой определяется только входным значением / s, без каких-либо наблюдаемых побочных эффектов. Он делает одно и только одно - вычисляет возвращаемое значение, и ничего больше.

Даже если мы разместим журнал внутри функции sum() , это сделает его нечистой функцией, что очень заразительно при написании кода.

Таким образом, основная идея написания чистых функций состоит в том, чтобы исключить все возможные побочные эффекты, которые могут увеличить вероятность ошибок, и да, это также включает ведение журнала.

Первоклассные функции

func sayHello() {
    print("Hi!")
}
let greeting = sayHello
greeting()
// prints: Hi!

Создавая его, создатели Swift Overlord изо всех сил решили сделать почти все первоклассным гражданином. Когда говорят, что функции являются первоклассными, это означает, что мы можем назначать функции переменным, как, например, с Int или String.

Это позволяет нам писать функции, которые могут принимать другие функции в качестве аргументов, а также возвращать их, чтобы мы могли передавать их другим частям нашего кода.

Функции высшего порядка

Поскольку функции считаются первоклассными, это означает, что мы можем создавать функции «высшего порядка». Чтобы функция считалась более высокой по порядку, она должна соответствовать по крайней мере одной из следующих двух черт:

  • Используйте функцию в качестве аргумента
  • Вернуть функцию

Чтобы проиллюстрировать это на примере, давайте создадим функцию высшего порядка, которая принимает другую функцию в качестве аргумента:

func inside() -> Void { 
    print("Yo!")
}
// inside's structure: 
// () -> Void

У нас есть функция с именем inside, которая не принимает аргументов и ничего не возвращает, иначе известная как Void. В комментарии под ним я описал структуру функции, которую очень важно понять. Структура - это то, что компилятор будет анализировать для проверки совместимости при передаче ее другим функциям в качестве аргументов. Теперь давайте посмотрим на функцию, которая принимает другую функцию в качестве аргумента:

func outside(inner: () -> Void) { 
    inner()
}

Как видите, наша функция outside принимает один аргумент, который также является другой функцией. Если вы посмотрите на тип inner аргумента, вы увидите, что он имеет ту же структуру, что и наша inside функция. Поскольку параметры функции inside и аргумента inner одинаковы, мы можем передать inside в inner, и компилятор не подаст сигнал и не загорится.

Наконец, мы вызываем параметр inner из функции outside, и он, в свою очередь, вызывает функцию print(), которая была в теле inside:

outside(inside)
// prints: Yo!

Расширенные концепции

Цепочка, композиция и каррирование

Мы только начали поверхностно разбираться в функциональном программировании на Swift, нам еще многое предстоит осветить в следующих нескольких частях этой продолжающейся серии публикаций, в которые будут включены некоторые более сложные концепции, такие как три C выше. Они немного сложны, поэтому каждый, вероятно, получит отдельную публикацию, но, надеюсь, к настоящему времени вы лучше понимаете, как Swift включает в себя основные части парадигмы функционального программирования, чтобы сделать ваш код более надежным, безопасным и универсальным.

Сказав это, я хотел бы официально поприветствовать вас в Клубе функционального программирования. Пожалуйста, не забывайте практиковать Правила 1 и 2, пока вы с радостью ждете следующей части этой серии.

Образец кода этого сообщения можно найти на GitHub.

Если вам нравится то, что вы прочитали сегодня, вы можете проверить другие мои статьи или хотите связаться с нами, отправьте мне твит или подпишитесь на меня в Twitter, это действительно делает мой день. Я также организовываю Playgrounds Conference в Мельбурне, Австралия, и хочу увидеть вас на следующем мероприятии.