Функції

Знайомство

Час переходити до активних дій! Функції у ClojureScript - це так звані об’єкти першого класу: за своєю поведінкою вони не відрізняються від інших типів. Такі функції можна передавати як аргументи або отримати як значення. Контекст при цьому завжди визначається статично. У певних ситуаціях ClojureScript підтримує динамічне визначення контексту, але про це ми поговоримо в іншому розділі.

За більш детальною інформацією щодо визначення контексту направляємо читачів до статті з Вікіпедії), у якій вичерпно роз’яснюються різні типи визначення контексту.

Для виклику функцій у ClojureScript використовується типова для діалектів Lisp префіксна нотація:

(inc 1)
;; => 2

У наведеному прикладі inc - це функція та частина середовища виконання (рантайму) ClojureScript, а 1 - перший аргумент функції inc.

(+ 1 2 3)
;; => 6

Символ + представляє функцію додавання. На відміну від мов родини ALGOL, де знаком + позначається оператор додавання, що допускає лише два параметри, у ClojureScript символ + означає функцію, кількість параметрів якої не обмежена.

Префіксна нотація має значні переваги, в тому числі досить неочевидні. ClojureScript не розрізняє функції та оператори, кожен оператор - це функція. Префіксна нотація знімає обмеження на кількість аргументів будь-якого “оператора”, а також повністю усуває проблему їхнього пріоритету.

Визначення власних функцій

Неіменовану (анонімну) функцію можна визначити за допомогою спеціальної форми fn. Це один з існуючих типів визначення функції. У наступному прикладі функція приймає два параметри та повертає їх середнє значення.

(fn [param1 param2]
  (/ (+ param1 param2) 2.0))

Функцію можна визначити та викликати в одному виразі:

((fn [x] (* x x)) 5)
;; => 25

Приступимо до створення іменованих функцій. Але спочатку спитаємо себе, що таке іменована функція? Все дуже просто: у ClojureScript, функції - це об’єкти першого класу, що поводяться як будь-які інші значення, тому іменування функції - це її поєднання з певним символом.

(def square (fn [x] (* x x)))

(square 12)
;; => 144

Також у ClojureScript існує макрос defn - синтаксичний цукор для більш виразного визначення функцій:

(defn square
  "Return the square of a given number."
  [x]
  (* x x))

Рядок, між ім’ям функції та вектором параметрів, називається документаційним рядком (docstring). Ці рядки будуть використані програмами, що автоматично створюють веб-документацію з сирцевих файлів.

Мультиарні функції

ClojureScript підтримує можливість визначення мультиарних функції - функцій зі змінною кількістю аргументів (термін “арність” вказує на допустиму кількість аргументів функції ). За синтаксисом мультиарні функції відрізняються від звичайних наявністю більш ніж одного тіла функції.

Розглянемо на прикладі:

(defn myinc
  "Self defined version of parameterized `inc`."
  ([x] (myinc x 1))
  ([x increment]
   (+ x increment)))

Рядок : ([x] (myinc x 1)) означає, що за наявності лише одного аргументу слід викликати функцію myinc із цим аргументом та числом 1 - у якості другого аргументу. Друге тіло функції ([x increment] (+ x increment)) означає, що якщо аргументів два, слід повернути результат додавання цих аргументів.

Наведемо приклади використання мультиарної функції, яку ми щойно визначили. Зверніть увагу: якщо ми викличемо функцію із невірною кількістю аргументів, компілятор повідомить про помилку.

(myinc 1)
;; => 2

(myinc 1 3)
;; => 4

(myinc 1 3 3)
;; Compiler error

ЗАУВАЖЕННЯ: Концепція арності знаходиться за межами тем цієї книги, але ви можете ознайомитися з нею за цим посиланням: Вікіпедія.

Варіативні функції

Інший спосіб обходження із невизначеною кількістю аргументів - це створення варіативних функцій. Варіативні функції - такі функції, що приймають довільну кількість аргументів:

(defn my-variadic-set
  [& params]
  (set params))

(my-variadic-set 1 2 3 1)
;; => #{1 2 3}

Синтаксис варіативної функції передбачає символ & на початку вектора аргументів.

Скорочений синтаксис анонімних функцій

Для визначення анонімних функцій, ClojureScript пропонує скорочений синтаксис із використанням макросу читання #() (як правило, використовується із однорядковими функціями). Макроси читання - це спеціальні вирази, що трансформуються у відповідну мовну форму під час компіляції. У цьому випадку - у вираз, що використовує спеціальну форму fn.

(def average #(/ (+ %1 %2) 2))

(average 3 4)
;; => 3.5

Попередній вираз є скороченим записом наступного:

(def average-longer (fn [a b] (/ (+ a b) 2)))

(average-longer 7 8)
;; => 7.5

Символи %1, %2... %N - це прості маркери позицій параметрів. Вони будуть імпліцитно оголошені під час інтерпретації макросу та конвертовані у вираз fn .

Якщо функція приймає лише один аргумент, можна опустити число після символу %&. Наприклад, функцію, що підносить число до другого степеня #(* %1 %1)) , можна записати так: #(* % %)).

Синтаксис також дозволяє використання варіативної форми із символом %& :

(def my-variadic-set #(set %&))

(my-variadic-set 1 2 2)
;; => #{1 2}

results matching ""

    No results matching ""