Спискові вирази

стаття-список у проєкті Вікімедіа

Спискові вирази (англ. list comprehension) — синтаксична конструкція доступна в деяких мовах програмування, яка призначена для створення списків застосуванням операцій над уже наявними списками. Вона відповідає математичній нотації побудови множини і замінює використання функцій map та filter.

Опис ред.

Розгляньмо наступний приклад запису множини:

 

Це можна прочитати як, «  множина всіх чисел виду „2 на  “, де   — елемент з множини натуральних чисел ( ), такий що   у квадраті більше, ніж  

В мові Haskell такий запис множини можна відтворити таким списковим виразом:

s = [ 2*x | x <- [1..], x^2 > 3 ]

Тут список [1..] представляє  , x^2>3 представляє предикат, а 2*x — вихідний вираз.

Спискові вирази дають результати в означеному порядку (на відміну від членів множини) і можуть ґенерувати елементи за потребою, а не одразу весь список, дозволяючи таким чином, наприклад, попереднє означення членів нескінченної множини.

Історія ред.

Мова програмування SETL (кінець 1960-тих) мала інструкції конструювання множин, і система комп'ютерної алґебри AXIOM (1973) мала подібні конструкції, які обробляли потоки, але вперше термін «comprehension» для таких конструкцій був використаний Родом Бурсталом та Джоном Дарлінґтоном в описі мови програмування NPL (1977).

Smalltalk block context messages, якими є спискові вирази, були в цій мові щонайменше з часів Smalltalk-80.

Робота Бурстала та Дарглінґтона з NPL вплинула на багато мов програмування протягом 1980-тих, але не всі з них включали спискові вирази. Винятком була впливова лінива чисто функціональна мова програмування Miranda, випущена в 1985-тому. Розроблена пізніше, теж цілком функціональна мова з лінивими обчисленнями Haskell, увібрала багато особливостей Міранди, включно з списковими виразами. Мова програмування Python теж зазнала сильного впливу лінивих функціональних мов і ввела спискові вирази. Чисті функціональні мови залишаються нішевими, у той час як Python став значно популярнішим і представив спискові вирази ширшій авдиторії.

Спискові вирази пропонувались як нотація запитів до баз даних[1] і були реалізовані в мові запитів Kleisli[2].

Приклади в різних мовах програмування ред.

Далі йтимуть приклади синтаксису спискових виразів у різних мовах програмування: Хоча в оригінальному прикладі використовується нескінченний список, виразити його можуть не всі мови, тому в деяких ми покажемо як використати підмножину   замість підмножини  .

C# ред.

var s =
from x in Enumerable.Range(0, 100)
where x * x > 3
select x * 2;

чи

var s = Enumerable.Range(0, 100).Where(x => x*x > 3).Select(x => x*2);

Ceylon ред.

{ for (x in 0..100) if ( x**2 > 3) x * 2 }

Clojure ред.

Clojure ґенерує нескінченні ліниві послідовності (подібно до Гаскеля, чи ґенераторів Пайтона). Використовуйте take щоб отримати перші N результатів нескінченної послідовности.

(take 20 (for [x (iterate inc 0) :when (> (* x x) 3)] (* 2 x)))

CoffeeScript ред.

 (x * 2 for x in [0..20] when x*x > 3)

Common Lisp ред.

Спискові вирази можуть виражатись за допомогою ключового слова collect макроса loop. Умови виражаються за допомогою if, як показано нижче:

(loop for x from 0 to 100 if (> (* x x) 3) collect (* 2 x))

Нескінченна лінива послідовність може створюватись різними способами, наприклад за допомогою об'єктів CLOS чи макросом yield.

Erlang ред.

 S = [2*X || X <- lists:seq(0,100), X*X > 3].

F# ред.

Вирази мають форму [for x in collection do ... yield expr] для списків та seq {for x in collection do ... yield expr} для послідовностей.

> seq { for x in 0..100 do
          if x*x > 3 then yield 2*x } ;;
val it : seq<int> = seq [4; 6; 8; 10; ...]

Groovy ред.

Groovy підтримує вирази для таких колекцій в Java як list, set, map.

s = (1..100).grep { it ** 2 > 3 }.collect { it * 2 }

Змінна «it» є скороченням неявного параметра замикання. Наступний код є еквівалентом попереднього

s = (1..100).grep { x -> x ** 2 > 3 }.collect { x -> x * 2 }

Haskell ред.

s = [ 2*x | x <- [0..], x^2 > 3 ]

Perl 6 ред.

my @s = ($_ * 2 if $_ ** 2 > 3 for ^100);

чи:

my @s = gather { for ^100 { take 2 * $_ if $_ ** 2 > 3 } };

PowerShell ред.

0..100 | Where {$_ * $_ -gt 3} | ForEach {$_ * 2}

Python ред.

S = [2*x for x in range(101) if x**2 > 3]



Див. також ред.

Посилання ред.

  • List Comprehension in The Free On-line Dictionary of Computing, Editor Denis Howe.
  • Trinder, Phil (1992). Comprehensions, a query notation for DBPLs. Proceedings of the third international workshop on Database programming languages: bulk types & persistent data, Nafplion, Greece. с. 55—68.
  • Wadler, Philip (1990). Comprehending Monads. Proceedings of the 1990 ACM Conference on LISP and Functional Programming, Nice. Архів оригіналу за 29 березня 2008. Процитовано 22 липня 2011.
  • Wong, Limsoon (2000). The Functional Guts of the Kleisli Query System. Proceedings of the fifth ACM SIGPLAN international conference on Functional programming. International Conference on Functional Programming. с. 1—10.

Haskell ред.

OCaml ред.

Python ред.

Common Lisp ред.

Clojure ред.

Axiom ред.

Решта ред.