Liste anlama - List comprehension

Bir liste anlama bir sözdizimsel bazılarında mevcut yapı Programlama dilleri var olana göre bir liste oluşturmak için listeler. Matematiksel biçimini takip eder set-oluşturucu gösterimi (anlamak) kullanımından farklı olarak harita ve filtre fonksiyonlar.

Genel Bakış

Aşağıdaki örneği düşünün set-oluşturucu gösterimi.

veya sıklıkla

Bu okunabilir " tüm sayıların kümesidir "2 kez " ÖYLE Kİ kümesinin ELEMANI veya ÜYESİ doğal sayılar (), VE kare büyüktür ."

En küçük doğal sayı olan x = 1, x koşulunu karşılayamaz.2> 3 (koşul 12> 3 yanlıştır) yani 2 · 1 S'ye dahil değildir. Sonraki doğal sayı olan 2 koşulu karşılar (22> 3) diğer her doğal sayı gibi. Böylece x, 2, 3, 4, 5 ... 'den oluşur. S tüm "2 çarpı x" sayılarından oluşur S = {4, 6, 8, 10, ...} ile verilir. S, başka bir deyişle, 2'den büyük tüm çift sayıların kümesidir.

Örneğin bu açıklamalı versiyonunda:

  • bir girdi kümesinin üyelerini temsil eden değişkendir.
  • bu örnekte doğal sayılar kümesi olan girdi kümesini temsil eder
  • bir yüklem girdi kümesinin üyeleri üzerinde filtre görevi gören ifade.
  • yüklem ifadesini karşılayan girdi kümesinin üyelerinden yeni kümenin üyelerini üreten bir çıktı ifadesidir.
  • kaşlı ayraçlar sonucun bir küme olduğunu gösterir
  • dikey çubuk "BÖYLE BU" olarak okunur. Çubuk ve iki nokta üst üste ":" birbirinin yerine kullanılır.
  • virgüller yüklemleri ayırır ve "VE" olarak okunabilir.

Bir liste anlama, bir girdiden sırayla bir listenin oluşturulmasını temsil eden aynı sözdizimsel bileşenlere sahiptir liste veya yineleyici:

  • Bir girdi listesinin üyelerini temsil eden bir değişken.
  • Bir giriş listesi (veya yineleyici).
  • İsteğe bağlı bir yüklem ifadesi.
  • Ve yüklemi karşılayan yinelenebilir girdinin üyelerinden çıktı listesinin üyelerini üreten bir çıktı ifadesi.

Çıktı listesinin üyelerinin oluşturulma sırası, girdideki öğelerin sırasına bağlıdır.

İçinde Haskell's liste anlama sözdizimi, bu set-oluşturucu yapısı aşağıdaki gibi benzer şekilde yazılır:

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

İşte liste [0..] temsil eder , x ^ 2> 3 yüklemi temsil eder ve 2 kere çıktı ifadesini temsil eder.

Liste anlayışları, sonuçları belirli bir sırayla verir (setlerin üyelerinin aksine); ve liste anlayışları olabilir oluşturmak bir listenin üyeleri, listenin tamamını oluşturmak yerine sırayla, böylece örneğin sonsuz bir listenin üyelerinin önceki Haskell tanımına izin verir.

Tarih

İlgili yapıların varlığı, "Liste Anlama" teriminin kullanımından önce gelir. SETL programlama dili (1969), liste anlamalarına benzer bir küme oluşturma yapısına sahiptir. Örneğin, bu kod, 2'den 2'ye kadar olan tüm asal sayıları yazdırır. N:

baskı ([[2..N] 'de n | {2..n - 1} | n mod m> 0]' da tüm m);

bilgisayar cebir sistemi AXIOM (1973), işleyen benzer bir yapıya sahiptir. Canlı Yayınlar.

Bu tür yapılar için "anlama" teriminin ilk kullanımı Çubuk Burstall ve John Darlington işlevsel programlama dilinin açıklaması NPL 1977'den beri. "Fonksiyonel Programlama Dillerinin Bazı Tarihi" retrospektifinde,[1] David Turner hatırlıyor:

NPL, Burstall tarafından POP2'de uygulandı ve Darlington’ın program dönüşümü üzerine çalışması için kullanıldı (Burstall & Darlington 1977). Dil, birinci dereceden, güçlü (ancak polimorfik değil) tipli, tamamen işlevsel, değere göre çağrı idi. Ayrıca "set ifadeleri" de vardı, ör.

setofeven (X) <= <: x: x in X & hatta (x):>}}

Turner, "listeyi anlama" terimine ekli bir dipnotta, ayrıca

Başlangıçta bunları aradım ZF ifadeleri, Zermelo-Frankel küme teorisine bir referans - Phil Wadler daha iyi terimi kim icat etti liste anlama.

Burstall ve Darlington'ın NPL ile çalışması 1980'lerde birçok işlevsel programlama dilini etkiledi, ancak hepsi liste anlayışlarını içermiyordu. Turner'ın etkili, saf, tembel, işlevsel programlama dili bir istisna idi Miranda, 1985'te piyasaya sürüldü. Daha sonra geliştirilen standart saf tembel işlevsel dil Haskell liste anlamaları da dahil olmak üzere Miranda'nın birçok özelliğini içerir.

Veritabanları için bir sorgu notasyonu olarak anlaşmalar önerildi[2] ve Kleisli veritabanı sorgu dili.[3]

Farklı programlama dillerinde örnekler

Benzer yapılar

Monad anlayışı

Haskell'de bir monad anlayışı liste anlayışının diğerlerine genellemesidir fonksiyonel programlamada monadlar.

Anlayışı ayarlayın

Python dilinin 3.x ve 2.7 sürümleri, Ayarlamak anlayışlar. Formda anlamaları listelemeye benzer şekilde, set anlamaları listeler yerine Python setleri oluşturur.

>>> s = {v için v içinde 'ABCDABCD' Eğer v değil içinde 'CB'}>>> Yazdır(s){'A', 'D'}>>> tip(s)<sınıf 'Ayarlamak'>>>>

Raket set anlayışları, listeler yerine Raket setleri oluşturur.

(için / set ([v "ABCDABCD"] #: sürece (üye v (string-> list "CB")))         v))

Sözlük anlama

Python dilinin 3.x ve 2.7 sürümleri için yeni bir sözdizimi sözlük Formda anlamaları listelemeye benzer ancak Python oluşturan anlamalar dicts listeler yerine.

>>> s = {anahtar: val için anahtar, val içinde numaralandırmak('ABCD') Eğer val değil içinde 'CB'}>>> s{0: 'A', 3: 'D'}>>>

Racket hash table anlayışları, Racket hash tabloları oluşturur (Racket sözlük türünün bir uygulaması).

(/ hash için ([(val anahtar) (endeksli "ABCD")]           #: sürece (üye val (string-> list "CB")))  (değerler anahtar val))

Paralel liste anlama

Glasgow Haskell Derleyici adlı bir uzantısı var paralel liste anlama (Ayrıca şöyle bilinir zip-anlama) Bu, listeyi anlama sözdizimi içinde niteleyicilerin birden çok bağımsız dalına izin verir. Virgülle ayrılan niteleyiciler bağımlı ("iç içe geçmiş") iken, borularla ayrılan niteleyici dalları paralel olarak değerlendirilir (bu, herhangi bir çok iş parçacıklılık biçimini ifade etmez: yalnızca şubeler sıkıştırılmış ).

- düzenli liste anlamaa = [(x,y) | x <- [1..5], y <- [3..5]]-- [(1,3),(1,4),(1,5),(2,3),(2,4) ...- sıkıştırılmış liste anlayışıb = [(x,y) | (x,y) <- zip [1..5] [3..5]]-- [(1,3),(2,4),(3,5)]- paralel liste anlamac = [(x,y) | x <- [1..5] | y <- [3..5]]-- [(1,3),(2,4),(3,5)]

Racket'in anlama standart kitaplığı, anlamlarının paralel ve iç içe versiyonlarını içerir ve adında "for" vs "for *" ile ayrılır. Örneğin, "için / vektör" ve "* / vektör için" vektör anlayışları, diziler üzerinde paralel yerine iç içe yineleme ile vektörler oluşturur. Aşağıdakiler, Haskell listesini anlama örnekleri için Raket kodudur.

> (için * / liste ([x (aralık içi 1 6)] [y (aralık içi 3 6)]) (liste x y))'((1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 3) (3 4) (3 5) (4 3) (4 4) (4 5) (5 3) (5 4) (5 5))> (için / liste ([x (aralık içi 1 6)] [y (aralık içi 3 6)]) (liste x y))'((1 3) (2 4) (3 5))

Python'da aşağıdakileri yapabiliriz:

# düzenli liste anlama>>> a = [(x, y) için x içinde Aralık(1, 6) için y içinde Aralık(3, 6)][(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), ...# paralel / sıkıştırılmış liste anlama>>> b = [x için x içinde zip(Aralık(1, 6), Aralık(3, 6))][(1, 3), (2, 4), (3, 5)]

Julia'da hemen hemen aynı sonuçlar şu şekilde elde edilebilir:

# düzenli dizi anlayışı>>> a = [(x, y) için x içinde 1:5 için y içinde 3:5]# paralel / sıkıştırılmış dizi anlayışı>>> b = [x için x içinde zip(1:3, 3:5)]

Julia'da listeler yerine tek farkımız dizilerimiz olmasıdır.

XQuery ve XPath

Orijinal NPL kullanımı gibi, bunlar da temelde veritabanı erişim dilleridir.

Bu, anlama kavramını daha önemli hale getirir, çünkü tüm listeyi almak ve üzerinde çalışmak hesaplama açısından olanaksızdır (ilk 'listenin tamamı' bütün bir XML veritabanı olabilir).

XPath'te ifade:

/kütüphane/kitap//paragraf[@style="bölümdeki ilk"]

kavramsal olarak, her adımın bir liste oluşturduğu ve sonraki adımın, önceki adımın çıktısındaki her öğeye bir filtre işlevi uyguladığı bir dizi "adım" olarak değerlendirilir.[4]

XQuery'de tam XPath mevcuttur, ancak FLWOR Daha güçlü bir anlama yapısı olan ifadeler de kullanılır.[5]

için $b içinde //kitapnerede $b[@pages < 400]tarafından sipariş $b//Başlıkdönüş  <shortBook><title>{$b//Başlık}</title><firstPara>{($kitap//paragraf)[1]}</firstPara></shortBook>

Burada XPath // kitabı bir dizi (aka liste) oluşturmak için değerlendirilir; where cümlesi işlevsel bir "filtre" dir, sıralama sonucu sıralar ve <shortBook>...</shortBook> XML pasajı aslında diğer işlevsel dillerde bulunan 'eşleme' yaklaşımını kullanarak dizideki her öğe için XML oluşturan / dönüştüren anonim bir işlevdir.

Dolayısıyla, başka bir işlevsel dilde yukarıdaki FLWOR ifadesi şu şekilde uygulanabilir:

harita(  newXML(kısa kitap, newXML(Başlık, $1.Başlık), newXML(firstPara, $1...))  filtre(    lt($1.sayfaları, 400),    xpath(//kitap)  ))

C # içinde LINQ

C # 3.0 adında bir grup ilgili özelliğe sahiptir LINQ, nesne numaralandırmalarını işlemek için bir dizi sorgu işleci tanımlayan.

var s = Sayılabilir.Aralık(0, 100).Nerede(x => x * x > 3).Seçiniz(x => x * 2);

Ayrıca SQL'i anımsatan alternatif bir anlama sözdizimi sunar:

var s = itibaren x içinde Sayılabilir.Aralık(0, 100) nerede x * x > 3 seç x * 2;

LINQ, tipik liste anlama uygulamaları üzerinde bir yetenek sağlar. Anlamanın kök nesnesi, IQueryable arayüz, sadece anlamanın zincirlenmiş yöntemlerini yürütmek yerine, tüm komut dizisi bir soyut sözdizimi ağacı (AST) nesnesi, yorumlamak ve yürütmek için IQueryable nesnesine iletilir.

Bu, diğer şeylerin yanı sıra, IQueryable'ın

  • uyumsuz veya verimsiz bir anlayışı yeniden yazmak
  • AST'yi yürütmek için başka bir sorgu diline (örneğin SQL) çevirin

C ++

C ++, liste anlamalarını doğrudan destekleyen herhangi bir dil özelliğine sahip değildir, ancak operatör aşırı yükleme (ör. aşırı yükleme |, >>, >>=) "gömülü" sorgu için anlamlı sözdizimi sağlamak için başarıyla kullanıldı alana özgü diller (DSL). Alternatif olarak, liste anlamaları kullanılarak oluşturulabilir. deyimi sil-kaldır bir kaptaki öğeleri ve bunları dönüştürmek için her biri için STL algoritmasını seçmek için.

#Dahil etmek <algorithm>#Dahil etmek <list>#Dahil etmek <numeric>kullanma ad alanı std;şablon<sınıf C, sınıf P, sınıf T>C anlamak(C&& kaynak, sabit P& yüklem, sabit T& dönüşüm){  // hedefi başlat  C d = ileri<C>(kaynak);  // öğeleri filtrele  d.silmek(remove_if(başla(d), son(d), yüklem), son(d));  // dönüşümü uygula  her biri için(başla(d), son(d), dönüşüm);  dönüş d;}int ana(){  liste<int> Aralık(10);      // aralık, tümü sıfır olan 10 öğeden oluşan bir listedir  iota(başla(Aralık), son(Aralık), 1);      // aralık artık 1, 2, ..., 10 içerir  liste<int> sonuç = anlamak(      Aralık,      [](int x) { dönüş x * x <= 3; },      [](int &x) { x *= 2; });      // sonuç artık 4, 6, ..., 20 içeriyor}

C ++ 'ya, set oluşturucu gösterimine benzer liste anlama yapıları / sözdizimi sağlamak için biraz çaba vardır.

  • İçinde Boost. Aralık [1] kütüphane bağdaştırıcı kavramı vardır [2] Bu, herhangi bir aralığa uygulanabilir ve filtreleme, dönüştürme vb. yapabilir. Bu kitaplıkla, orijinal Haskell örneği (Boost.Lambda kullanılarak) [3] anonim filtreleme ve dönüştürme işlevleri için) (Tam örnek ):
    sayma_aralığı(1,10) | filtrelenmiş( _1*_1 > 3 ) | dönüştürülmüş(ret<int>( _1*2 ))
  • Bu[6] uygulama bir makro kullanır ve << operatörünü aşırı yükler. Bir 'if' içinde geçerli herhangi bir ifadeyi değerlendirir ve herhangi bir değişken adı seçilebilir. Öyle değil iş parçacığı güvenli, ancak. Kullanım örneği:
liste<int> N;liste<çift> S;için (int ben = 0; ben < 10; ben++)    N.Geri itmek(ben);S << list_comprehension(3.1415 * x, x, N, x * x > 3)
  • Bu[7] uygulama, sınıfları ve operatör aşırı yüklemesini kullanarak kafa / kuyruk dilimleme sağlar ve | listeleri filtreleme operatörü (işlevleri kullanarak). Kullanım örneği:
bool hatta(int x) { dönüş x % 2 == 0; }bool x2(int &x) { x *= 2; dönüş doğru; }liste<int> l, t;int x, y;için (int ben = 0; ben < 10; ben++)     l.Geri itmek(ben);(x, t) = l | x2;(t, y) = t;t = l < 9;t = t < 7 | hatta | x2;
  • Gömülü Sorgu ve Geçiş Dili (LEESA[8]), operatör aşırı yüklemesini kullanarak X-Path benzeri sorgular gerçekleştiren C ++ 'da yerleşik bir DSL'dir. Sorgular, bir XSD'den xml-to-c ++ bağlama kullanılarak elde edilen zengin biçimde yazılmış xml ağaçlarında yürütülür. Kesinlikle dize kodlaması yoktur. Xml etiketlerinin adları bile sınıflardır ve bu nedenle yazım hatalarının bir yolu yoktur. Bir LEESA ifadesi, veri modelinde bulunmayan yanlış bir yol oluşturursa, C ++ derleyicisi kodu reddeder.
    Bir xml kataloğu düşünün.
<catalog>  <book>    <title>Hamlet</title>    <price>9.99</price>    <author>      <name>William Shakespeare</name>      <country>İngiltere</country>    </author>  </book>  <book>...</book>...</catalog>

LEESA şunları sağlar: >> XPath'ler / ayırıcı için. XPath'in // ağaçtaki ara düğümleri "atlayan" ayırıcısı, Stratejik Programlama olarak bilinen yöntem kullanılarak LEESA'da uygulanır. Aşağıdaki örnekte, katalog_, kitap_, yazar_ ve isim_ sırasıyla katalog, kitap, yazar ve isim sınıflarının örnekleridir.

// Eşdeğer X-Yolu: "katalog / kitap / yazar / ad"std::vektör<isim> yazar_isimleri = değerlendirmek(kök, katalog_ >> kitap_ >> yazar_ >> isim_);// Eşdeğer X-Yolu: "katalog // adı"std::vektör<isim> yazar_isimleri = değerlendirmek(kök, katalog_ >> Torunları(katalog_, isim_));// Eşdeğer X-Yolu: "katalog // yazar [ülke ==" İngiltere "]"std::vektör<isim> yazar_isimleri = değerlendirmek(kök, katalog_  >> Torunları(katalog_, yazar_)                         >> Seçiniz(yazar_, [](sabit yazar & a) { dönüş a.ülke() == "İngiltere"; })                         >> isim_);

Ayrıca bakınız

  • SEÇ FROM ve WHERE cümleleri ile birlikte ifadesi SQL

Notlar ve referanslar

  1. ^ Turner, David (2012). "İşlevsel programlama dillerinin bazı geçmişi" (PDF). Uluslararası Fonksiyonel Programlamada Trendler Sempozyumu, Springer, Berlin, Heidelberg. s. 1–20.
  2. ^ Kavramalar, DBPL'ler için bir sorgu notasyonu
  3. ^ Kleisli sorgu sisteminin işlevsel cesareti
  4. ^ "2.1 Konum Adımları". XML Yol Dili (XPath). W3C. 16 Kasım 1999. Arşivlenen orijinal 9 Aralık 2012 tarihinde. Alındı 24 Aralık 2008.
  5. ^ "XQuery FLWOR İfadeleri". W3Okullar. Arşivlenen orijinal 2011-10-08 tarihinde.
  6. ^ "Önişlemci Makrolarını Kullanarak C ++ 'da Tek Değişkenli Liste Anlama". Arşivlenen orijinal 2011-08-21 tarihinde. Alındı 2011-01-09.
  7. ^ "C ++ liste anlayışları". Arşivlenen orijinal 2017-07-07 tarihinde. Alındı 2011-01-09.
  8. ^ "Gömülü Sorgu ve Geçiş Dili (LEESA)".

Haskell

OCaml

Python

Ortak Lisp

Clojure

Aksiyom

Dış bağlantılar