리스트 이해

List comprehension

목록 이해는 기존 목록을 기반으로 목록을 만들기 위해 일부 프로그래밍 언어에서 사용할 수 있는 구문 구조입니다.지도 및 필터 함수의 사용과는 다른 수학적 세트빌더 표기법(세트 이해)의 형식을 따릅니다.

개요

다음 예시는 set-builder 표기법에 대해 생각해 보겠습니다.

또는 자주

이는 " S 모든 숫자의 집합이며 "\ x xdisplaystyle x 자연수 의 요소 또는 멤버(N\displaystyle \이며x 제곱은보다 ."라고 읽을 수 있습니다.

가장 작은 자연수 x = 1은 x > 3 조건을2 만족시키지 못하기 때문에(조건2 1 > 3은 거짓이다), 2 · 1은 S에 포함되지 않는다.다음 자연수 2는 다른 모든 자연수와 마찬가지로 조건(22>3)을 만족한다.따라서 x는 2, 3, 4, 5로 구성됩니다.세트 때부터S는 모든 숫자 "2 곱하기 x"로 구성되며, S = {4, 6, 8, 10, ...로 지정됩니다. 즉, S는 2보다 큰 모든 짝수의 집합입니다.

이 예의 주석 버전에서는 다음과 같습니다.

  • x 입력 세트의 멤버를 나타내는 변수입니다.
  • 은 입력 세트를 나타냅니다.이 예에서는 자연수의 집합입니다.
  • 2> x > 입력 세트의 멤버에 대한 필터로서 기능하는 술어 표현입니다.
  • x 2x)는 술어식을 만족하는 입력 세트의 멤버로부터 새로운 세트의 멤버를 생성하는 출력식입니다.
  • {\ 중괄호는 결과가 집합임을 나타냅니다.
  • \mid , {\displaystyle 막대는 "SUCH THAT"로 읽힙니다막대와 콜론 ":"는 서로 바꾸어 사용합니다.
  • 쉼표는 술어를 구분하여 "AND"로 읽을 수 있습니다.

목록 이해에는 입력 목록 또는 반복자에서 순서대로 목록 생성을 나타내는 동일한 구문 구성 요소가 있습니다.

  • 입력 목록의 멤버를 나타내는 변수.
  • 입력 리스트(또는 반복기).
  • 옵션의 술어 표현식.
  • 그리고 술어를 만족시키는 입력 반복 가능한 멤버로부터 출력 리스트의 멤버를 생성하는 출력식.

출력 목록의 멤버 생성 순서는 입력 항목 순서에 따라 결정됩니다.

Haskell의 목록 이해 구문에서 이 set-builder 구문은 다음과 같이 작성됩니다.

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

여기 리스트[0..]N.x^2>3술어를 나타냅니다.2*x는 출력식을 나타냅니다.

목록 통합은 정의된 순서로 결과를 제공합니다(세트 멤버와 달리). 목록 통합은 목록 전체를 생성하는 것이 아니라 목록의 멤버를 순서대로 생성할 수 있습니다. 따라서 예를 들어 무한 목록의 멤버에 대한 이전 Haskell 정의를 허용합니다.

역사

"목록 이해"라는 용어를 사용하기 전에 관련 구조가 존재해야 합니다.SETL 프로그래밍 언어(1969)는 목록 통합과 유사한 집합 구성 구조를 가지고 있습니다.예를 들어, 이 코드는 2부터 2까지의 모든 소수를 인쇄합니다.N:

print([n in [2..])N] {2 . n - 1 } n mod m > 0 ]의 모든 m ;

컴퓨터 대수 시스템 AXIOM(1973)은 스트림을 처리하는 유사한 구조를 가지고 있다.

이러한 구조에 대해 "이해"라는 용어를 처음 사용한 것은 1977년부터 기능 프로그래밍 언어 NPL에 대한 Rod Burstall과 John Darlington의 설명에서였다.David Turner는 회고전 "기능 프로그래밍 언어의 역사"[1]에서 다음과 같이 회상합니다.

NPL은 Burstall에 의해 POP2에 구현되어 Darlington의 프로그램 변환 작업에 사용되었습니다(Burstall & Darlington 1977).이 언어는 1차적(다형적이지는 않지만) 유형으로 되어 있으며, 순수하게 기능하며, 값별로 호출됩니다.또한 다음과 같은 "set expressions"도 있습니다.

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

"목록 이해"라는 용어에 첨부된 각주에서 터너는 또한 다음과 같이 언급한다.

나는 처음에 이 ZF 표현들을 Zermelo-Frankel 집합론에 대한 언급이라고 불렀다.- 더 나은 용어 목록 이해를 만든 사람은 Phil Wadler였다.

Burstall과 Darlington의 NPL 관련 작업은 1980년대에 많은 기능적 프로그래밍 언어에 영향을 미쳤지만, 모두 목록 통합을 포함하지는 않았다.예외는 1985년에 출시된 터너의 영향력 있고 순수하고 게으른 기능적인 프로그래밍 언어 미란다였다.이후에 개발된 표준 순수 게으름 함수 언어 Haskell은 목록 이해를 포함한 미란다의 많은 특징을 포함한다.

통합은 데이터베이스에 대한[2] 쿼리 표기법으로 제안되었으며 클라이슬리 데이터베이스 쿼리 [3]언어로 구현되었다.

다른 프로그래밍 언어의 예

유사 구조

모나드 이해

해스켈에서 모나드 이해는 함수 프로그래밍의 다른 모나드에 대한 목록 이해의 일반화이다.

이해도를 설정하다

Python 언어 버전 3.x 및 2.7에서는 set compreptions 구문이 도입되었습니다.목록 압축과 유사한 형태로, set compensions는 목록 대신 Python 집합을 생성합니다.

>>> s = {v 위해서 v  'ABCD' 한다면 v 것은 아니다.  'CB'} >>> 인쇄물(s) {'A', 'D'} >>> 유형(s) < >학급 '세트'> >>> 

라켓 세트를 통합하면 리스트 대신 라켓 세트가 생성됩니다.

(용/세트 ([v ABCD] #:단, (멤버v (string-> 리스트"CB")))          v)) 

사전 이해

Python 언어 버전 3.x와 2.7은 사전 압축에 대한 새로운 구문을 도입했습니다.이 구문은 목록 압축과 형식이 비슷하지만 목록 대신 Python dicts를 생성합니다.

>>> s = {열쇠:  위해서 열쇠,   열거하다('ABCD') 한다면  것은 아니다.  'CB'} >>> s {0: 'A', 3: 'D'} >>> 

라켓 해시 테이블 수집은 라켓 해시 테이블을 생성합니다(라켓 사전 유형의 구현 중 하나).

(대상/대상 ([( 열쇠) (사내의 "ABCD)]            #:단, (멤버 (string-> 리스트"CB")))   (가치열쇠 )) 

병렬 리스트 이해

Glasgow Haskell 컴파일러에는 목록 이해 구문 내에서 수식자의 여러 독립된 분기를 허용하는 병렬 목록 이해(zip-compreption이라고도 함)라는 확장 기능이 있습니다.쉼표로 구분된 한정자는 종속("내포")인 반면 파이프로 구분된 한정자 브랜치는 병렬로 평가됩니다(이는 어떤 형태의 멀티스레드도 참조하지 않으며 브랜치가 압축됨을 의미합니다).

--정기적인 리스트 이해 a = [(x,y)   x <-> [1..5], y <-> [3..5]] -- [(1,3),(1,4),(1,5),(2,3),(2,4) ...  -- 압축된 목록 이해 b = [(x,y)   (x,y) <-> 지퍼 [1..5] [3..5]] -- [(1,3),(2,4),(3,5)]  -- 병렬 목록 이해 c = [(x,y)   x <-> [1..5]   y <-> [3..5]] -- [(1,3),(2,4),(3,5)] 

Racket의 컴포메이션 표준 라이브러리에는 이름의 "for"와 "for*"로 구분되는 컴포메이션의 병렬 및 중첩 버전이 포함되어 있습니다.예를 들어 "for/vector" 및 "for*/vector"는 시퀀스에 대해 병렬 대 중첩 반복을 통해 벡터를 생성합니다.다음은 Haskell 목록 이해 예제의 라켓 코드입니다.

> (대상*/리스트 ([x (범위 내의 1 6)] [y (범위 내의 3 6)]) (목록.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)) > (대상/목록 ([x (범위 내의 1 6)] [y (범위 내의 3 6)]) (목록.x y)) '((1 3) (2 4) (3 5)) 

Python에서는 다음과 같이 할 수 있습니다.

규칙적인 목록 이해 수 >>> a = [(x, y) 위해서 x  범위(1, 6) 위해서 y  범위(3, 6)] [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), ...  병렬/지퍼링 목록 이해 수 >>> b = [x 위해서 x  지퍼(범위(1, 6), 범위(3, 6))] [(1, 3), (2, 4), (3, 5)] 

줄리아에서도 실질적으로 다음과 같은 결과를 얻을 수 있습니다.

정기적인 어레이 이해 수 >>> a = [(x, y) 위해서 x  1:5 위해서 y  3:5]  병렬/ZIP 어레이 이해 수 >>> b = [x 위해서 x  지퍼(1:3, 3:5)] 

줄리아에는 목록 대신 배열이 있다는 것만 다를 뿐이죠

XQuery 및 XPath

원본 NPL사용처럼, 이러한 근본적으로database 접속 언어들이다.

때문에 computationally고 그 위에(초기'entire 목록'가 있을 것으로 전체 XML데이터베이스)는 전체 목록 검색할 타당하지 않다고 이 이해 개념은 더욱 중요하게 만들어 준다.

XPath, 식에서는:

/도서관///단락[스타일@='first-in-chapter의] 

개념적으로"단계"의 각 단계이며, 다음 단계는 이전 단계의 출력물에 명시된 각 요소로 필터 기능 적용되는 목록을 생성하는 시리즈로 평가됩니다.[4]

XQuery에는, 온갖 XPath지만, FLWOR 성명도 사용된다, 이것 보다 더 강력한 이해 건축물 사용할 수 있습니다.[5]

위해서 $b  // 어디에 $b[페이지 @ < > 400] 명령에 의해 $b//직함 돌아가다   <>shortBook>.     <>title>.{$b//직함}<>/title>.     <>firstPara>.{($//단락)[1]}<>/firstPara>.   <>/shortBook>. 

여기에 XPath//book 시퀀스(목록aka)을 만듭니다. 그 조항은 기능"필터", 종류로 주문한 결과는 평가를 받습니다.<shortBook>...</shortBook>XML 스니펫은 실제로 다른 기능 언어에 있는 '맵' 접근 방식을 사용하여 시퀀스의 각 요소에 대해 XML을 구축/변환하는 익명 함수입니다.

그 때문에, 다른 기능 언어에서는, 상기의 FLWOR 스테이트먼트는 다음과 같이 실장할 수 있습니다.

지도(   새로운 XML(쇼트북, 새로운 XML(직함, $1.직함), 새로운 XML(제1파라, $1...))   필터(     그것($1.페이지, 400),     xpath(//)   ) ) 

C#의 LINQ

C# 3.0에는 LINQ라고 하는 관련 기능 그룹이 있습니다.LINQ는 오브젝트 열거를 조작하기 위한 쿼리 연산자 세트를 정의합니다.

변화하다 s = 열거형.범위(0, 100).어디에(x => x * x > 3).선택한다.(x => x * 2); 

또한 SQL을 연상시키는 대체 이해 구문을 제공합니다.

변화하다 s = 부터 x  열거형.범위(0, 100) 어디에 x * x > 3 선택한다. x * 2; 

LINQ는 일반적인 목록 이해 구현에 대한 기능을 제공합니다.이해의 근본 객체가 구현되는 경우IQueryable인터페이스는 단순히 연쇄화된 이해 방법을 실행하는 것이 아니라 명령어 전체 시퀀스가 추상 구문 트리(AST) 개체로 변환되어 해석과 실행을 위해 IQueryable 개체로 전달됩니다.

이것은 무엇보다도 IQueryable을 가능하게 한다.

  • 양립할 수 없거나 비효율적인 이해를 고쳐 쓰다
  • AST를 실행을 위해 다른 쿼리 언어(예: SQL)로 변환한다.

C++

C++에는 목록 통합을 직접 지원하는 언어 기능은 없지만 연산자 오버로드(예: 오버로드)가 있습니다. ,>>,>>=를 사용하여 "내장" 쿼리 도메인 고유 언어(DSL)에 대한 표현 구문을 제공했습니다.또는 소거 제거 어디어나 STL 알고리즘을 사용하여 리스트 컴포레이션을 구성하여 컨테이너 내의 요소를 선택하고, 그것들을 각각 변환한다.L 알고리즘을 각각 사용할 수 있다.

#실패하다 <blocks> #실패하다 <리스트> #실패하다 <blocks>  사용. 네임스페이스 표준;  템플릿< >학급 C, 학급 P, 학급 T> C 이해하다(C& & 원천, 컨스턴트 P& 술어, 컨스턴트 T& 변용) {   // 수신처 초기화   C d = 앞으로< >C>(원천);    // 요소 필터링   d.지우다(삭제_if(시작한다.(d), 끝.(d), 술어), 끝.(d));    // 변환 적용   각각(시작한다.(d), 끝.(d), 변용);    돌아가다 d; }  인트 주된() {   목록.< >인트> 범위(10);       // range는 10개의 요소로 구성된 목록이며 모두 0입니다.   iota(시작한다.(범위), 끝.(범위), 1);       // 범위에 1, 2, ..., 10이 포함됨    목록.< >인트> 결과 = 이해하다(       범위,       [](인트 x) { 돌아가다 x * x <=> 3; },       [](인트 &x) { x *= 2; });       // 결과에는 4, 6, ..., 20이 포함됩니다. } 

C++에 set builder 표기법과 유사한 목록 이해 구성/구문을 제공하려는 노력이 있습니다.

  • 인부스트.범위 [1] 라이브러리에는 모든 범위에 적용할 수 있고 필터링, 변환 등을 수행할 수 있는 어댑터 [2]의 개념이 있습니다.이 라이브러리를 사용하면 원래의 Haskell 예는 (Boost 사용)과 같습니다.익명 필터링 및 변환 함수의 경우 람다[3](전체 예제):
    카운트_범위(1,10)   필터링되었다( _1*_1 > 3 )   변형된(리트< >인트>( _1*2 )) 
  • [6] 실장에서는 매크로를 사용하여 <<> 연산자를 오버로드합니다.if' 내에서 유효한 식을 평가하여 임의의 변수 이름을 선택할 수 있습니다.하지만 쓰레드 세이프가 아닙니다.사용 예:
목록.< >인트> N; 목록.< >이중으로 하다> S;  위해서 (인트 i = 0; i < > 10; i++)     N.푸시백(i);  S << > 리스트_이해(3.1415 * x, x, N, x * x > 3) 
  • [7] 구현은 클래스 및 연산자 오버로드를 사용하여 헤드/테일 슬라이스를 제공하며 목록 필터링을 위한 연산자(함수 사용)를 제공합니다.사용 예:
부울 심지어.(인트 x) { 돌아가다 x % 2 == 0; } 부울 x2(인트 &x) { x *= 2; 돌아가다 진실의; }  목록.< >인트> l, t; 인트 x, y;  위해서 (인트 i = 0; i < > 10; i++)      l.푸시백(i);  (x, t) = l   x2; (t, y) = t;  t = l < > 9; t = t < > 7   심지어.   x2; 
  • Language for Embedded Query and Traversal(LEESA[8])은 연산자 오버로드를 사용하여 X-Path와 같은 쿼리를 구현하는 C++의 내장 DSL입니다.쿼리는 XSD에서 xml-to-c++ 바인딩을 사용하여 얻은 풍부한 유형의 xml 트리에서 실행됩니다.문자열 인코딩은 전혀 없습니다.xml 태그의 이름조차 클래스이므로 오타가 발생할 수 없습니다.LEESA 식이 데이터 모델에 존재하지 않는 잘못된 경로를 형성하면 C++ 컴파일러는 코드를 거부합니다.
    카탈로그 xml을 검토합니다.
<book> <book> <book> <book>햄릿 </title> <가격> 9.99 </price> <작성자> <이름>윌리엄 셰익스피어 </name> <country> </country> </author> </book> ...</book>...</filters>

LEESA는 다음과 같은 기능을 제공합니다.>>XPath / 구분자용.트리의 중간 노드를 건너뛰는 XPath의 // 구분자는 LEESA에서 전략적 프로그래밍이라고 알려진 것을 사용하여 구현됩니다.다음 예시에서 catalog_, book_, author_ 및 name_은 각각 카탈로그, 책, 작성자 및 이름 클래스의 인스턴스입니다.

// 동등한 X 경로: "카탈로그/책/작성자/이름" 표준::벡터< >이름.> author_names =  평가하다(뿌리, 카탈로그_ >> 예약_ >> 작성자_ >> 이름_);  // 동등한 X 경로: "catalog//name" 표준::벡터< >이름.> author_names =  평가하다(뿌리, 카탈로그_ >> 후예(카탈로그_, 이름_));  // 동등한 X 경로: "catalog//author[country=="England"" 표준::벡터< >이름.> author_names =  평가하다(뿌리, 카탈로그_  >> 후예(카탈로그_, 작성자_)                          >> 선택한다.(작성자_, [](컨스턴트 작가. & a) { 돌아가다 a.나라() == "잉글랜드"; })                          >> 이름_); 

「 」를 참조해 주세요.

주 및 참고 자료

  1. ^ Turner, David (2012). "Some history of functional programming languages" (PDF). International Symposium on Trends in Functional Programming, Springer, Berlin, Heidelberg. pp. 1–20.
  2. ^ DBPL에 대한 쿼리 표기법인 Comprehensions
  3. ^ Kleisli 쿼리 시스템의 기능적 배짱
  4. ^ "2.1 Location Steps". XML Path Language (XPath). W3C. 16 November 1999. Archived from the original on 9 December 2012. Retrieved 24 December 2008.
  5. ^ "XQuery FLWOR Expressions". W3Schools. Archived from the original on 2011-10-08.
  6. ^ "Single-variable List Comprehension in C++ using Preprocessor Macros". Archived from the original on 2011-08-21. Retrieved 2011-01-09.
  7. ^ "C++ list comprehensions". Archived from the original on 2017-07-07. Retrieved 2011-01-09.
  8. ^ "Language for Embedded Query and Traversal (LEESA)".
  • 무료 온라인 컴퓨팅 사전, 편집자 Denis Howe에 이해 목록을 작성하십시오.
  • Wadler, Philip (1990). "Comprehending Monads". Proceedings of the 1990 ACM Conference on LISP and Functional Programming, Nice.

외부 링크

공리

클로쥬르

일반적인 리스프

하스켈

OCaml

파이썬