Відкрити головне меню

Генераторні списки (англ. 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. 
  • 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Редагувати

РештаРедагувати