기능적, 선언적, 명령형 프로그래밍이라는 용어는 무엇을 의미합니까?
기능적, 선언적, 명령형 프로그래밍이라는 용어는 무엇을 의미합니까?
답변:
이 글을 쓰는 시점에서이 페이지에서 가장 많이 투표 된 답변은 Wikipedia를 인용하는 답변을 포함하여 선언적 대 명령 적 정의에 대해 부정확하고 혼동됩니다. 일부 답변은 다른 방식으로 용어를 혼동하고 있습니다.
수식이 셀을 변경하는 것과 상관없이 스프레드 시트 프로그래밍이 선언적인 이유에 대한 설명 도 참조하십시오 .
또한 여러 답변은 함수형 프로그래밍이 선언의 하위 집합이어야한다고 주장합니다. 그 시점에서 우리는 "기능"과 "절차"를 구별 할 수 있는지에 달려 있습니다. 명령형 대 선언 형을 먼저 처리합니다.
선언적 표현의 정의
만 가능하게 차별화 할 수 속성 선언 에서 표현 필수적 표현은 하위 표현의 참조 투명성 (RT)입니다. 다른 모든 속성은 두 유형의 표현식간에 공유되거나 RT에서 파생됩니다.
100 % 선언적 언어 (즉, 가능한 모든 표현이 RT 인 언어)는 다른 RT 요구 사항 중에서 HTML과 Haskell의 대부분과 같은 저장된 값의 변형을 허용하지 않습니다.
RT 표현의 정의
RT는 종종 "부작용이 없다"고합니다. 효과 라는 용어 는 정확한 정의가 없으므로 어떤 사람들은 "부작용 없음"이 RT와 동일하다는 데 동의하지 않습니다. RT는 정확한 정의를 가지고 있습니다.
모든 하위 표현식은 개념적으로 함수 호출이므로 RT는 함수의 구현 (예 : 호출 된 함수 내부의 표현식)이 함수 외부 의 변경 가능한 상태에 액세스하지 않아야 합니다 ( 변경 가능한 로컬 상태에 액세스하는 것은 허용됨). 간단히 말해서 함수 (구현)는 순수 해야합니다 .
순수한 기능의 정의
순수한 기능은 종종 "부작용이 없다"고 말합니다. 효과 라는 용어 는 정확한 정의가 없으므로 일부 사람들은 동의하지 않습니다.
순수한 함수에는 다음과 같은 속성이 있습니다.
RT는 표현식 (함수 호출 포함)에 적용되고 순도는 함수 (구현)에 적용됩니다.
RT 표현식을 만드는 불순한 함수의 모호한 예는 동시성이지만 인터럽트 추상화 계층에서 순도가 깨지기 때문입니다. 당신은 정말로 이것을 알 필요가 없습니다. RT 표현식을 작성하려면 순수한 함수를 호출하십시오.
RT의 파생 속성
선언적 프로그래밍에 인용 된 다른 속성, 예를 들어 Wikipedia에서 사용 된 1999 년 의 인용 은 RT에서 파생되거나 명령형 프로그래밍과 공유됩니다. 따라서 내 정확한 정의가 올바른지 증명합니다.
외부 값의 불변성은 RT 요구 사항의 일부입니다.
선언적 언어에는 루프 제어 구조가 없습니다 (예 : for
및 while
). 불변성으로 인해 루프 조건이 변경되지 않기 때문 입니다.
선언적 언어는 불변성으로 인해 평가 순서의 다른 선택이 결과를 변경하지 않기 때문에 중첩 함수 순서 (일명 논리적 종속성) 이외의 제어 흐름을 표현 하지 않습니다 (아래 참조).
선언적 언어는 논리적 "단계"(즉, 중첩 된 RT 함수 호출 순서)를 표현하지만 각 함수 호출이 더 높은 수준의 의미 론적 (즉, "할 일")인지 여부는 선언적 프로그래밍의 요구 사항이 아닙니다. 명령형과 구별되는 점은 불변성 (즉, 일반적으로 RT)으로 인해 이러한 "단계"는 변경 가능한 상태에 의존 할 수없고 표현 된 논리의 관계 순서 (즉, 함수 호출의 중첩 순서, 일명 하위 표현식)에만 의존 할 수 없다는 것입니다. ).
예를 들어 단락 <p>
의 하위 표현식 (예 : 태그)이 평가 될 때까지 HTML 단락 을 표시 할 수 없습니다. 태그 계층 (논리적으로 중첩 된 함수 호출 인 하위 표현식의 중첩)의 논리적 관계로 인해 변경 가능한 상태는없고 순서 종속성 만 있습니다.
따라서 선언적 표현 은 변이 가능한 상태 관계가 아닌 구성 부분 (즉, 하위 표현 함수 인수) 의 논리적 관계 만 표현한다는 불변성의 파생 속성 (보다 일반적으로 RT)이 있습니다.
평가 순서
하위 표현식의 평가 순서를 선택하면 함수 호출이 RT가 아닌 경우 (즉, 함수가 순수하지 않은 경우), 예를 들어 함수 외부의 일부 변경 가능한 상태가 함수 내에서 액세스되는 경우에만 결과가 달라질 수 있습니다.
예를 들어, 일부 중첩 된 표현, 예를 들어 주어진 f( g(a, b), h(c, d) )
기능이있는 경우, 함수 인수의 열망과 게으른 평가는 동일한 결과를 줄 것이다 f
, g
그리고 h
순수를.
반면, 기능하는 경우 f
, g
그리고 h
순수하지 않은, 다음 평가 순서의 선택은 다른 결과를 제공 할 수 있습니다.
식 연산자는 단항 접두사, 단항 접두사 또는 이진 접두사 표기법으로 가장하는 함수 호출이기 때문에 중첩 식은 개념적으로 중첩 된 함수입니다.
모든 식별자는, 예를 들어, 경우에 접선 방향으로는, a
, b
, c
, d
,이다 불변의 모든 곳에서, 프로그램의 외부 상태 (즉, I / O) 액세스 할 수 없습니다, 그리고 더 추상화 계층 파손이없는 다음 기능은 항상 순수하다.
그건 그렇고, Haskell은 다른 문법을 가지고 f (g a b) (h c d)
있습니다.
평가 순서 세부 사항
함수는 입력에서 출력으로의 상태 전이 (변경 가능한 저장 값이 아님)입니다. 순수 함수 호출의 RT 구성의 경우 , 이러한 상태 전이의 실행 순서는 독립적입니다. 각 함수 호출의 상태 전이는 부작용이없고 RT 함수가 캐시 된 값으로 대체 될 수 있다는 원칙으로 인해 다른 함수와 독립적입니다 . 하기 위해 인기있는 오해를 수정 , 순수한 모나드 조성은 항상 선언 및 RT 하스켈의 사실에도 불구하고, IO
모나드는 틀림없이 불순한 때문에 필수적 WRT World
프로그램의 외부 상태 (그러나 아래의 경고의 의미에서, 부작용 격리되어 있습니다).
평가가 어렵다는 것은 함수가 호출되기 전에 함수 인수가 평가됨을 의미하며, 게으른 평가는 인수가 함수 내에서 액세스 될 때까지 평가되지 않음을 의미합니다 .
정의 : 함수 매개 변수 는 함수 정의 사이트 에서 선언 되고 함수 인수 는 함수 호출 사이트 에서 제공 됩니다. parameter 와 argument 의 차이점을 알아야합니다 .
개념적으로, 모든 표현은 예 (의 조성) 함수 호출, 상수 단항 연산자는 하나 개의 입력과 함수 입력없이 함수이다되는 이진 중위 연산자는 두 입력이 함수는, 생성자 함수, 심지어 제어 명령이다 (예이다 if
, for
, while
) 기능으로 모델링 할 수 있습니다. 이 있도록 인수 평가 기능 (중첩 된 함수 호출 순서하지 혼동 할)은 예를 들면, 구문에 의해 선언되지 f( g() )
열심히 평가할 수 g
다음 f
에 g
'의 결과 나에 대한 평가 할 수 f
만 유유히 평가 g
의 결과 내에서 필요할 때 f
.
주의 사항, 튜링 완전 언어 없음 (즉, 무한한 재귀를 허용하는)은 완벽하게 선언적입니다. 그러나 평가 순서의 선택으로 인한 이러한 부작용은 메모리 소비, 실행 시간, 대기 시간, 비 종료 및 외부 히스테리시스로 제한 되므로 외부 동기화가 가능합니다.
기능적 프로그래밍
선언적 프로그래밍에는 루프를 사용할 수 없으므로 반복하는 유일한 방법은 함수 재귀입니다. 이런 의미에서 기능적 프로그래밍은 선언적 프로그래밍과 관련이 있습니다.
그러나 함수형 프로그래밍은 선언적 프로그래밍에만 국한되지 않습니다 . 기능적 구성은 특히 표현 문제 와 관련하여 하위 유형과 대조 될 수 있는데, 하위 유형이나 기능적 분해를 추가하여 확장을 수행 할 수 있습니다 . 확장은 두 가지 방법론 의 혼합 일 수 있습니다 .
함수형 프로그래밍은 일반적으로 함수를 일류 객체로 만듭니다. 즉, 함수 유형은 다른 유형이있는 곳이면 어디든지 문법에 나타날 수 있습니다. 결론은 함수가 함수를 입력하고 작동 할 수 있으므로 함수 구성을 강조함으로써 결정 분리, 즉 결정 론적 계산의 하위 계산 사이의 종속성을 분리함으로써 관심의 분리를 제공한다는 것입니다.
예를 들어, 컬렉션의 각 요소에 적용될 수있는 무한한 수의 특수화 된 액션 각각에 대해 별도의 함수를 작성하는 대신 (그리고 함수가 선언적이어야하는 경우 루프 대신 재귀를 사용하는 대신) 함수형 프로그래밍은 재사용 가능한 반복을 사용합니다. 기능, 예를 들면 map
, fold
, filter
. 이 반복 함수는 일류 특수 액션 함수를 입력합니다. 이러한 반복 함수는 콜렉션을 반복하고 각 요소에 대해 입력 된 특수 조치 함수를 호출합니다. 이 조치 함수는 더 이상 콜렉션을 반복하기 위해 반복문을 포함 할 필요가 없기 때문에 더 간결합니다.
그러나 함수가 순수하지 않으면 실제로 절차입니다. 불순한 함수를 사용하는 함수형 프로그래밍은 실제로 절차 적 프로그래밍이라고 주장 할 수 있습니다. 따라서 선언적 표현이 RT라는 데 동의하면 절차 적 프로그래밍은 선언적 프로그래밍이 아니라고 할 수 있습니다. 따라서 함수형 프로그래밍은 항상 RT이며 선언적 프로그래밍의 하위 집합이어야한다고 주장 할 수 있습니다.
병행
일급 기능을 갖춘이 기능 구성 은 독립 기능을 분리 하여 병렬 처리 의 깊이를 표현할 수 있습니다 .
브렌트의 원리 : 작업 w 및 깊이 d를 사용한 계산은 시간 O (max (w / p, d))의 p- 프로세서 PRAM에서 구현 될 수 있습니다.
동시성과 병렬 처리 모두 선언적 프로그래밍 , 즉 불변성과 RT가 필요합니다.
그렇다면 Parallelism == 동시성이라는이 위험한 가정은 어디에서 왔습니까? 부작용이있는 언어의 자연스러운 결과입니다. 언어가 모든 곳에서 부작용이있는 경우 한 번에 여러 작업을 수행하려고 할 때마다 각 작업의 효과가 인터리빙되어 결정되지 않은 결과가 나타납니다 . 따라서 부작용이있는 언어에서 병렬 처리를 얻는 유일한 방법은 동시성입니다. 따라서 우리가 종종 두 가지가 얽힌 것을 본다는 것은 놀라운 일이 아닙니다.
평가 순서는 또한 기능 구성의 종료 및 성능 부작용에 영향을 미칩니다.
Eager (CBV)와 Lazy (CBN)는 평가 순서가 역전되어 있기 때문에 범주 형 결투 [ 10 ]입니다. 즉, 외부 또는 내부 함수가 각각 먼저 평가되는지 여부입니다. 거꾸로 된 나무를 상상 해보면 함수 트리 분기 팁에서 분기 계층 구조까지 최상위 계층 함수 트렁크까지 간절히 평가합니다. 반면, 게으른 트렁크에서 분기 팁까지 평가합니다. 열망에는 결속 제품 ( "and", a / k / 범주 적 "제품")이없고 게으름 병에는 결속 coproducts ( "또는", a / k / 범주 "합계")가 없습니다 [ 11 ].
공연
심한
비 종료와 마찬가지로, 열성적인 기능적 구성으로 열성적이다. 즉, 구성 적 제어 구조는 게으르지 않은 불필요한 작업을한다. 예를 들어 , 첫 번째 true 요소에서 끝나는 접기로 구성된 경우 전체 목록을 열성적으로 불필요하게 맵핑합니다.
이러한 불필요한 작업은 순수한 기능을 갖는 열망과 지연의 순차 시간 복잡성에서 "최대"의 추가 로그 요소의 원인 이다. 해결책은 열악한 부정확 함이 내부 함수에서 시작되기 때문에 지연 생성자 (예 : 선택적 지연 제품에 대한 열망)가있는 펑터 (예 : 목록)를 사용하는 것입니다. 이는 제품이 건설적인 유형, 즉 초기 고정 점에 초기 대수를 갖는 유도 형이기 때문입니다 [ 11 ]
게으른
비 종료와 마찬가지로, 게으른 기능적 구성으로 게으른 게으른 게으른 것입니다. 즉, 일치 성 최종성이 필요 이상으로 발생할 수 있으며, 불필요한 작업과 열등한 경우가 아닌 지체의 결정을 초래합니다 [ 10 ] [ 11 ] . 최종성의 예로는 상태, 타이밍, 비 종료 및 런타임 예외가 있습니다. 이것들은 필수적인 부작용이지만 순수한 선언적 언어 (예 : Haskell)에서도 공간 할당에 암시적인 IO 모나드 (주 : 모든 모나드가 반드시 필요한 것은 아닙니다!)의 상태가 있으며 타이밍은 명령적인 상태와 관련된 상태입니다. 현실 세계. 게으른 경우 게으름 이 외부 기능에서 발생 하기 때문에 선택적인 열악한 보조 제품과 함께 게으른 사용하면 게으름이 내부 보조 제품으로 누출 됩니다.(비 종료 섹션의 예를 참조하십시오. 여기서 ==는 외부 이진 연산자 함수입니다). 이는 공동 생산물이 최종성, 즉 최종 객체에 최종 대수를 갖는 일치 형 유형에 의해 제한되기 때문이다 [ 11 ].
Lazy는 선언 된 함수 계층과 런타임 평가 순서 사이 의 불일치로 인해 대기 시간 및 공간에 대한 함수의 디자인 및 디버깅에 결정 성을 유발합니다. 디버깅은 대부분의 프로그래머의 기능을 능가 할 수 있습니다. 열성적으로 평가 된 게으른 순수 함수는 런타임에 이전에는 볼 수 없었던 종료되지 않을 수 있습니다. 반대로, 지연으로 평가 된 열악한 순수 함수는 런타임에 이전에 볼 수 없었던 공간 및 지연 시간 결정을 유발할 수 있습니다.
비 종료
컴파일 타임에 Halting 문제와 Turing 완전한 언어로의 상호 재귀로 인해 함수는 일반적으로 종료되지 않을 수 있습니다.
심한
Head
"and" 의 결합에 대해 간결하지만 게으르지 않은 경우, 왼쪽이 끝나지 않고 오른쪽이 끝나기 때문에 각각 또는 그렇지 않은 Tail
경우 각각 또는 그렇지 않습니다.Head
Tail
List( Head(), Tail() ).tail == Tail()
List( Head(), Tail() ).head == Head()
반면에 게으른 양쪽은 종료됩니다. 따라서 열성적인 제품은 너무 열성적이며, 필요하지 않은 경우 종료되지 않은 (런타임 예외 포함) 제품에 너무 열심입니다.
게으른
의 분리를위한, 게으른하지만 열망 있지 않은 상태 1
"또는" 2
경우, f
종료하지 않는, 다음 List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail
사실이 아니다 왼쪽 종료하고, 오른쪽은하지 않기 때문에.
반면 열망이 없으면 어느 쪽도 종료되지 않으므로 평등 테스트에 도달하지 않습니다. 따라서 게으른 코디네이션에서는 너무 게으르고, 이러한 경우에는 열망하는 것보다 더 많은 작업을 수행 한 후 종료되지 않습니다 (런타임 예외 포함).
[ 10 ] 선언적 연속성 및 범주 적 이중성, Filinski, 섹션 2.5.4 SB에서 CBV와 CBN의 비교, 3.6.1 CBV와 CBN.
[ 11 ] 선언적 연속성 및 범주 적 이중성, Filinski, 섹션 2.2.1 제품 및 보조 제품, 2.2.2 터미널 및 초기 개체, 게으른 제품이있는 2.5.2 CBV 및 열성적인 보조 제품이있는 2.5.3 CBN
이것에 대한 모호하지 않고 객관적인 정의는 실제로 없습니다. 내가 그들을 정의 하는 방법은 다음과 같습니다 .
명령 -컴퓨터가 수행하는 것보다 컴퓨터가 수행 해야하는 단계 (예 : C, C ++, Java) 에 중점을 둡니다 .
선언적 -컴퓨터가 어떻게해야하는지보다는 컴퓨터가해야하는 것에 중점을 둡니다 (예 : SQL).
기능 -재귀에 중점을 둔 선언적 언어의 하위 집합
명령형 과 선언 형 은 서로 반대되는 두 가지 프로그래밍 스타일을 설명합니다. 명령형은 전통적인 "단계별 레시피"접근 방식이지만 선언적은 더 "이것은 내가 원하는 것입니다. 이제는 어떻게해야합니까?"
이 두 가지 접근 방식은 동일한 언어 및 동일한 프로그램을 사용하더라도 프로그래밍 과정에서 발생합니다. 일반적으로 선언적 접근 방식은 프로그래머가 너무 많은 세부 사항을 지정하지 않아도되고 버그가 발생할 가능성이 적기 때문에 선호되는 것으로 간주됩니다 (원하는 결과를 설명하면 잘 테스트 된 자동 프로세스가 그 뒤로 거꾸로 작동 할 수 있음) 단계를 정의하면 각 단계를 수동으로 지정하는 것보다 더 신뢰할 수 있기를 바랍니다.
반면에 명령형 접근 방식은보다 낮은 수준의 제어를 제공합니다. 이는 프로그래밍에 대한 "마이크로 매니저 접근 방식"입니다. 프로그래머가 문제에 대한 지식을 활용하여보다 효율적인 답변을 제공 할 수 있습니다. 따라서 프로그램의 일부가보다 선언적인 스타일로 작성되는 것은 드문 일이 아니라 속도에 중요한 부분이 더 중요합니다.
상상할 수 있듯이 프로그램을 작성하는 데 사용하는 언어는 선언적 방식에 영향을 미칩니다. 결과에 대한 설명을 제공하여 수행 할 작업을 수행하기위한 내장 된 "스마트"기능이 훨씬 더 선언적입니다. 프로그래머가 먼저 선언적 계층을 구축하기 전에 명령형 코드로 이러한 종류의 지능을 추가 해야하는 것보다 접근합니다. 예를 들어 프롤로그와 같은 언어는 답변을 검색하는 프로세스가 내장되어 있기 때문에 매우 선언적인 것으로 간주됩니다.
지금까지 함수 프로그래밍에 대해서는 언급하지 않았습니다 . 그 의미는 다른 두 단어와 즉시 관련이없는 용어이기 때문입니다. 가장 단순하고 기능적인 프로그래밍은 함수를 사용한다는 것을 의미합니다. 특히 함수를 "퍼스트 클래스 값"으로 지원하는 언어를 사용합니다. 즉, 함수를 작성할 수있을뿐만 아니라 함수를 작성하는 함수 (...를 작성하는 함수)를 작성하고 함수를 전달할 수 있습니다. 기능. 간단히 말해서, 함수는 문자열과 숫자와 같이 유연하고 일반적입니다.
따라서 기능적, 명령 적, 선언적 표현이 함께 언급되는 것이 이상하게 보일 수도 있습니다. 그 이유는 기능 프로그래밍의 개념을 "극단적으로"취한 결과입니다. 가장 순수한 의미의 함수는 수학에서 나온 것입니다. 일종의 "블랙 박스"는 입력을 받고 항상 같은 출력을 제공합니다. 이런 종류의 행동에는 변화하는 변수를 저장할 필요가 없습니다. 따라서 매우 순수하고 수학적으로 영향을받는 함수형 프로그래밍 아이디어를 구현하는 것이 목표 인 프로그래밍 언어를 설계하는 경우, 변경 될 수있는 값 (특정, 제한된 기술적 의미)에 대한 아이디어를 거부하게됩니다.
그리고 만약 그렇게한다면 – 변수가 어떻게 변할 수 있는지를 제한한다면 – 거의 우연히 프로그래머는 강제적으로 프로그램을 작성해야합니다. 왜냐하면 명령형 프로그래밍의 많은 부분이 변수가 어떻게 변하는 지 설명하고 있기 때문에 더 이상 그렇게! 따라서 함수형 프로그래밍, 특히 함수형 언어로 프로그래밍하는 경우보다 선언적인 코드를 제공하는 경향이 있습니다.
요약하면 다음과 같습니다.
명령형과 선언 형은 서로 반대되는 두 가지 프로그래밍 스타일입니다 (같은 스타일을 권장하는 프로그래밍 언어에 사용됩니다)
함수형 프로그래밍은 함수가 매우 중요 해지고 결과적으로 값을 변경하는 것이 덜 중요 해지는 프로그래밍 스타일입니다. 값의 변경을 지정하는 제한된 능력은보다 선언적인 스타일을 강요합니다.
따라서 "기능 프로그래밍"은 종종 "선언적"으로 설명됩니다.
간단히 말해서 :
필수 언어는 순서에서 컴퓨터가 실행이 (다음, 그렇게이 작업을 수행 할) 것을 일련의 명령을을 지정한다.
선언적 언어는 출력되는 입력 (예. 당신이있는 경우, 결과는 B이다) 결과를해야하는지에 대한 일련의 규칙을 선언합니다. 엔진은 이러한 규칙을 입력에 적용하고 출력을 제공합니다.
기능적 언어 입력이 출력으로 변환하는 방법을 정의하는 수학 / 논리 함수의 세트를 선언한다. 예. f (y) = y * y. 선언적 언어의 한 유형입니다.
명령 : 목표 달성 방법
Take the next customer from a list.
If the customer lives in Spain, show their details.
If there are more customers in the list, go to the beginning
선언 : 무엇을 우리가 달성하고자하는
Show customer details of every customer living in Spain
명령형 프로그래밍 이란 프로그램이 컴퓨터에서 수행되는 작업이 수행되는 방식을 설명하는 명령으로 구성되는 모든 스타일의 프로그래밍을 의미합니다 .
선언적 프로그래밍 (Declarative Programming) 이란 프로그램이 문제 또는 솔루션에 대한 설명이지만 작업 수행 방식을 명시 적으로 명시하지 않은 모든 스타일의 프로그래밍을 의미합니다 .
함수형 프로그래밍 은 함수의 함수와 함수를 평가하여 프로그래밍하는 것입니다 ... (엄격하게 정의 된) 함수형 프로그래밍은 부작용이없는 수학 함수를 정의하여 프로그래밍하는 것을 의미하므로 선언적 프로그래밍의 한 형태이지만 선언적 프로그래밍의 유일한 종류는 아닙니다 .
논리 프로그래밍 (예 : Prolog)은 선언적 프로그래밍의 또 다른 형식입니다. 논리 문이 참인지 (또는 만족시킬 수 있는지)를 결정하여 계산을 포함합니다. 프로그램은 일반적으로 일련의 사실과 규칙, 즉 일련의 지침이 아닌 설명입니다.
용어 재 작성 (예 : CASL)은 선언적 프로그래밍의 또 다른 형태입니다. 그것은 대수 용어의 상징적 변형을 포함합니다. 논리 프로그래밍 및 기능 프로그래밍과는 완전히 다릅니다.
사전 답변을 작성 했으므로 아래 인용 된 선언적 속성에 대한 새로운 정의 를 공식화했습니다 . 또한 명령형 프로그래밍을 이중 속성으로 정의했습니다.
이 정의는 간결하고 일반적이기 때문에 이전 답변에서 제공 한 것보다 우수합니다. 그러나 프로그래밍과 삶에 일반적으로 적용되는 불완전 성 이론의 함의는 인간이 자신의 마음을 감싸기 어렵 기 때문에 이해하기가 더 어려울 수 있습니다.
인용 된 정의에 대한 설명은 선언적 프로그래밍에서 순수 기능 프로그래밍 이 수행하는 역할을 설명합니다 .
모든 이국적인 유형의 프로그래밍은 선언적 대 명령형의 다음 분류법에 적합합니다.
선언적 대 명령형
선언적 속성은 기이하고 모호하며 일반적으로 모호하지 않은 기술적으로 정확한 정의로 포착하기가 어렵습니다. 의도하지 않은 부작용을 일으키지 않고 프로그램의 의미 (일명 의미론)를 선언 할 수 있다는 순진한 개념이기 때문입니다. 의미의 표현과 의도하지 않은 효과의 회피 사이에는 본질적인 긴장이 있으며,이 긴장은 실제로 프로그래밍과 우주 의 불완전 성 이론 에서 비롯됩니다 .
그것은 기술적으로 부정확 한 지나친 단순화, 등과 같은 선언적 정의 종종 모호 " 무엇을 " 로하고 필수적 " 수행하는 방법 " . 모호한 경우는 프로그램을 출력하는 프로그램 (컴파일러 )의 " 무엇 "이 " 어떻게 "입니다.
분명히 완전한 튜링 언어를하게 억제 할 재귀는 또한 유사하다 semantics-에서뿐만 아니라 평가 (일명 운영 의미)의 구문 구조이다. 이것은 논리적으로 고델의 정리와 유사한 예입니다.“ 모든 공리 체계도 일관성이 없습니다 .” 그 말의 모순 된 이상한 점을 깊이 생각해보십시오! 따라서 그것은 우리가 증명할 수, 또한 의미의 표현이 증명 바인딩이없는 방법을 보여줍니다 예입니다 (2) 그 프로그램 (및 유사의 의미) 앞뒤가 맞지 정리 일명 정지.
불완전 성 정리는 열역학 제 2 법칙에 언급 된 바와 같이“ 엔트로피 (일명 독립 가능성의 수) 는 영원히 최대로 추세하고있다 . 프로그램의 코딩과 디자인은 실제 세계의 요구를 해결하려고 시도하기 때문에 결코 끝나지 않습니다. 실제 세계의 의미는 항상 더 많은 가능성으로 변하고 있습니다. 인간은 결코 새로운 것을 발견하는 것을 멈추지 않습니다 (프로그램의 오류를 포함하여 ;-).
가장자리가없는이 이상한 우주 (우주에서 "외부"가 없다고 생각하는) 내에서 앞서 언급 한 원하는 개념을 정확하고 기술적으로 포착하려면 간결하지만 기만적으로 단순하지 않은 정의가 필요합니다. 깊이.
정의:
선언적 속성은 각 특정 모듈 식 의미론을 표현할 수있는 하나의 가능한 문장 세트 만 존재할 수 있습니다.
명령형 속성 3 은 의미 상 구성이 일치하지 않고 /거나 문장 세트의 변형으로 표현 될 수있는 이중입니다.
이러한 선언적 정의는 시맨틱 범위에서 뚜렷하게 지역적 이며, 이는 모듈 형 시맨틱이 글로벌 범위 에서 인스턴스화되고 어떻게 사용되는지에 관계없이 일관된 의미를 유지해야 함을 의미합니다 . 따라서 각 선언적 모듈 의미론은 가능한 모든 다른 것들과 본질적으로 직교해야하며 일관성을 증명하기위한 불가능한 (불완전 성 이론으로 인해) 글로벌 알고리즘이나 모델이 아니라 로버트 하퍼 (Robert Harper) 교수의“ 항상 더 좋은 것은 아니다 ” 표준 ML의 디자이너 중 하나 인 Carnegie Mellon University의 컴퓨터 과학 전공.
이러한 모듈 식 선언적 의미의 예는 카테고리 이론 펑은 예 포함 다음 의미의 운영 수준의 순수 함수형 프로그래밍에, 공칭 입력, 네임 스페이스, 이름 필드 및 WRT를.
Applicative
따라서 잘 디자인 된 선언적 언어는 표현할 수있는 것에서 약간의 일반성이 없어지지 만 본질적인 일관성으로 표현 될 수있는 것에서 이득을 얻음에도 불구하고 의미를보다 명확하게 표현할 수 있습니다.
앞에서 언급 한 정의의 예는 스프레드 시트 프로그램의 셀에있는 수식 세트입니다. 다른 열 및 행 셀로 이동할 때 동일한 의미를 갖지 않을 것으로 예상됩니다. 즉, 셀 식별자가 변경되었습니다. 셀 식별자는 의도 된 의미의 일부이며 불필요한 것은 아닙니다. 따라서 각 스프레드 시트 결과는 일련의 수식에서 셀 식별자에 고유합니다. 이 경우 일관된 모듈 의미는 셀 수식을 셀 수식에 대한 순수한 함수 의 입력 및 출력으로 사용하는 것입니다 (아래 참조).
하이퍼 텍스트 마크 업 언어는 일명, HTML 정적 웹 페이지 -의 언어는 매우 (그러나 완벽의 예 3 (적어도 HTML 5 전) 동적 거동을 표현 할 능력이 없다고) 선언적 언어입니다. HTML은 아마도 배우기 가장 쉬운 언어 일 것입니다. 동적 동작의 경우 JavaScript와 같은 명령적인 스크립팅 언어는 일반적으로 HTML과 결합되었습니다. JavaScript가없는 HTML은 각 명목 유형 (즉, 태그)이 구문 규칙 내에서 구성에서 일관된 의미를 유지하기 때문에 선언적 정의에 적합합니다.
선언적에 대한 경쟁적 정의 는 의미 론적 문장 의 교환 적이고 dem 등한 속성입니다. 즉, 의미를 변경하지 않고 명령문을 재정렬하고 복제 할 수 있습니다. 예를 들어, 이름이 지정된 필드에 값을 할당하는 명령문은 프로그램의 의미를 암시 적 순서로 모듈화 한 경우 프로그램의 의미를 변경하지 않고 순서를 다시 정하고 복제 할 수 있습니다. 이름은 때때로 순서를 의미합니다. 예를 들어 셀 식별자에는 열과 행 위치가 포함됩니다. 스프레드 시트에서 합계를 이동하면 그 의미가 변경됩니다. 그렇지 않으면, 이러한 속성에는 암시 적으로 전역이 필요합니다의미론의 일관성. 순서와 복제가 의미론에 내재되어 있기 때문에 무작위로 정렬되거나 복제 될 때 일관성있게 유지되도록 명령문의 의미론을 설계하는 것은 일반적으로 불가능합니다. 예를 들어,“Foo 존재”(또는 구성) 및“Foo 존재하지 않습니다”(및 파기)라는 문구가 있습니다. 의도 된 의미론의 고유 한 불일치가 있다고 생각되면, 선언적 특성에 대해 충분히 일반적인 것으로이 정의를 받아들입니다. 본질적으로이 정의는 의미론에 직교하는 일관성, 즉 의미론의 우주가 동적으로 제한되지 않고 글로벌 일관성 패러다임 에서 포착 될 수 없다는 사실을 무시하려고 시도하기 때문에 일반화 된 정의로 공허합니다 .
제 (구조의 평가 순서)에 교환 적 및 멱등 특성을 요구하는 낮은 수준의 선언적으로 연산 의미론 변환 연산을 의미 국소 모듈 의미, 즉 순수한 (대신 필수적 루프 재귀 포함) 함수형 프로그래밍. 그런 다음 구현 세부 사항의 작동 순서 는 상위 레벨 시맨틱의 일관성에 영향을 미치지 않습니다 (즉, 전체적으로 확산 됩니다). 예를 들어, 스프레드 시트 수식의 평가 순서 (및 이론적으로는 중복)는 모든 출력이 계산 될 때까지 (즉, 순수한 함수와 유사한) 출력이 입력으로 복사되지 않기 때문에 중요하지 않습니다.
C, Java, C ++, C #, PHP 및 JavaScript는 특별히 선언적이지 않습니다. Copute의 구문과 Python의 구문은 의도 된 결과 , 즉 불필요한 구문을 제거하는 일관된 구문 의미론 과보다 선언적으로 결합되어 있으므로 코드를 잊어 버린 후 쉽게 이해할 수 있습니다. Copute와 Haskell은 운영 의미론을 결정 하고 순수한 기능적 패러다임을 허용하기 때문에“ 반복하지 마십시오 ”(DRY)를 권장 합니다.
2 언어 Coq와 같이 프로그램의 의미론을 입증 할 수있는 경우에도, 이는 타이핑 으로 표현 된 의미론으로 제한되며, 타이핑은 프로그램의 모든 의미론을 캡처 할 수 없습니다. 튜링이 완료되지 않은 경우, 예를 들어 HTML + CSS를 사용하면 정의되지 않은 의미를 갖는 일치하지 않는 조합을 표현할 수 있습니다.
3 많은 설명은 명령형 프로그래밍 만이 구문 적으로 명령 된 문장을 가지고 있다고 잘못 주장하고있다. 나는 명령형 프로그래밍과 기능적 프로그래밍 사이의 혼란을 분명히했다 . 예를 들어, HTML 문의 순서는 의미의 일관성을 감소시키지 않습니다.
편집 : Robert Harper의 블로그에 다음 의견 을 게시했습니다 .
함수형 프로그래밍에서 변수의 변동 범위는 유형입니다.
명령형 프로그래밍과 기능을 구별하는 방법에 따라 명령형 프로그램에서 '지정 가능'은 가변성에 한계를 두는 유형을 가질 수도 있습니다.
내가 함수형 프로그래밍에 대해 현재 인정하고있는 머들 링되지 않은 유일한 정의는 a) 일류 객체 및 유형으로서의 함수, b) 루프에 대한 재귀에 대한 선호 및 / 또는 c) 순수한 함수, 즉 원하는 의미에 영향을 미치지 않는 함수 ( 메모리 할당과 같은 연산 의미론의 영향으로 인해 범용 목적 상 의미론에는 완벽하게 순수한 기능적 프로그래밍이 존재하지 않습니다 ).
순수 함수의 dem 등원 속성은 변수에 대한 함수 호출이 값으로 대체 될 수 있음을 의미하며 이는 일반적으로 명령 절차의 인수에는 해당되지 않습니다. 순수한 함수는 입력과 결과 유형 사이의 구성되지 않은 상태 전환에 대한 선언적인 것으로 보입니다.
그러나 순수한 함수의 구성은 그러한 일관성을 유지하지 못합니다. 하스켈의 IOMonad와 같은 순수한 함수형 프로그래밍 언어로 부작용 (글로벌 상태) 명령 프로세스를 모델링하는 것이 가능하기 때문에 이러한 기능을 방지하는 것은 완전히 불가능합니다. 모든 튜링은 완벽한 기능성 프로그래밍 언어입니다.
최근 블로그 에서 비슷한 의견에 대한 합의로 보이는 2012 년에 썼 듯이 선언적 프로그래밍은 의도 된 의미가 결코 불투명하지 않다는 개념을 포착하려는 시도입니다. 불투명 한 의미론의 예는 순서에 대한 의존성, 운영 의미 론적 계층에서 상위 수준 의미론의 소거에 대한 의존성 (예 : 캐스트는 변환이 아니며 통일 된 제네릭은 상위 수준 의미론을 제한 함 ), 확인할 수없는 변수 값에 대한 의존성 (증명 됨) 프로그래밍 언어로 수정하십시오.
따라서 나는 튜링이 아닌 완전한 언어 만이 선언적 일 수 있다고 결론지었습니다.
따라서 선언적 언어의 분명하고 명확한 특성 중 하나는 그 산출물이 열거 가능한 일련의 생성 규칙을 따르는 것으로 입증 될 수 있다는 것입니다. 예를 들어, 스크립트되지 않은 (즉, Turing이 완료되지 않은) 특정 HTML 프로그램 (통역사 분기 방식의 차이를 무시 함)의 경우 출력 변수를 열거 할 수 있습니다. 간결하게 HTML 프로그램은 그 가변성의 순수한 기능입니다. 스프레드 시트 프로그램 Ditto는 입력 변수의 순수한 기능입니다.
따라서 선언적 언어는 무한 재귀 의 대립이라고 할 수 있습니다. 즉, 고델의 두 번째 불완전 성 정리 자체 참조 이론에 따르면 증명할 수 없습니다.
Lesie Lamport 는 유클리드가 프로그래밍 언어 맥락에서 수학 증명에 적용되는 고델 의 불완전 성 이론을 유형과 논리 (Curry-Howard 대응 등)와 일치시켜 어떻게 처리했는지에 대한 동화를 썼습니다 .
명령형 프로그래밍 : "기계"에게 무언가를 수행하는 방법을 알려 주면 결과적으로 원하는 일이 발생합니다.
선언적 프로그래밍 : "머신"에게 무슨 일이 일어나고 싶은지 알려주고 컴퓨터가 어떻게해야하는지 파악하게합니다.
function makeWidget(options) {
const element = document.createElement('div');
element.style.backgroundColor = options.bgColor;
element.style.width = options.width;
element.style.height = options.height;
element.textContent = options.txt;
return element;
}
function makeWidget(type, txt) {
return new Element(type, txt);
}
참고 : 차이점은 간결하거나 복잡하거나 추상화 된 것이 아닙니다. 언급 한 바와 같이, 그 차이는 어떻게 대 무엇을 .
명령 적 / 선언적 / 기능성 측면은 일반적인 언어를 분류하는 과거 좋았지 만, 요즘은 모두 "큰 언어"의 일부 옵션 (일반적으로이 (자바, 파이썬, 자바 스크립트 등) 프레임 워크 "다른 초점"로 표현을) 주요한 것 (일반적인 명령)보다, 병렬 프로세스, 선언적 함수, 람다 등을 표현하는 것
따라서이 질문의 좋은 변형은 "현재 프레임 워크를 분류하는 데 어떤 측면이 좋은가?"입니다. ... 중요한 것은 "프로그래밍 스타일"이라는 레이블을 붙일 수있는 것입니다 ...
설명하기 좋은 예입니다. Wikipedia 에서 jQuery에 대해 읽을 수있는 것처럼
선택기 엔진 (...)으로 활성화 된 jQuery 핵심 기능 (DOM 요소 선택, 순회 및 조작)은 알고리즘과 DOM 데이터 구조를 융합하여 새로운 "프로그래밍 스타일"을 만들었습니다.
따라서 jQuery는 객체 지향 일뿐만 아니라 " 알고리즘과 데이터 구조 융합 " 인 "새로운 프로그래밍 스타일" 에 중점을 둔 가장 좋은 예입니다 . jQuery는 스프레드 시트처럼 다소 반응 적이지만 "셀 지향적"이 아니라 " DOM- 노드 지향적 "입니다 ... 이 맥락에서 주요 스타일 을 비교합니다 .
융합 없음 : 모든 "큰 언어", 모든 기능적 / 선언적 / 제 국적 표현에서 일반적으로 일부 객체 지향을 제외하고 는 엄격한 대수적 구조 관점 에서 의 융합 인 데이터와 알고리즘의 "융합 없음"입니다 .
일부 융합 : 모든 고전적인 융합 전략은 오늘날 패러다임으로 사용하는 프레임 워크를 가지고 있습니다 ... dataflow , 이벤트 중심 프로그래밍 (또는 awk 및 XSLT 와 같은 오래된 도메인 특정 언어 ) ... 현대 스프레드 시트를 사용한 프로그래밍과 마찬가지로 반응 형 프로그래밍 스타일의 예 .
큰 융합 : "jQuery 스타일"... jQuery는 " 퓨징 알고리즘 및 DOM 데이터 구조 "에 중점을 둔 도메인 별 언어 입니다.
추신 : XQuery, SQL (PL을 명령 식 옵션으로 사용)과 같은 다른 "쿼리 언어"도 데이터 알고리즘 융합 예이지만 다른 시스템 모듈과의 융합이없는 섬입니다 ...- 변수를 사용할 때 Springfind()
및 사양 절은, 또 다른 좋은 퓨전 예이다.
선언적 프로그래밍은 입력과 출력 사이에 시간을 초월한 논리를 의사 코드로 표현하여 프로그래밍하는 것입니다. 다음 예제는 선언적입니다.
def factorial(n):
if n < 2:
return 1
else:
return factorial(n-1)
output = factorial(argvec[0])
여기서는 '인수'라는 관계를 정의하고 출력과 입력 간의 관계를 해당 관계로 정의했습니다. 여기서 분명히 알 수 있듯이, 구조화 된 언어에 대해서는 선언적 프로그래밍이 어느 정도 확장 될 수 있습니다. 선언적 프로그래밍의 중심 아이디어는 변경할 수없는 데이터입니다. 변수에 할당하면 한 번만 수행 한 다음 다시는 수행 할 수 없습니다. 더 엄격하게 정의 된 다른 정의에는 부작용이 전혀 없을 수 있으므로 이러한 언어를 '순전히 선언적'이라고합니다.
명령형 스타일의 동일한 결과는 다음과 같습니다.
a = 1
b = argvec[0]
while(b < 2):
a * b--
output = a
이 예제에서 우리는 입력과 출력 사이에 영원한 정적 논리 관계를 표현하지 않았으며, 메모리 주소 중 하나가 원하는 결과를 유지할 때까지 수동으로 메모리 주소를 변경했습니다. 모든 언어가 선언적 의미론을 어느 정도까지 확장 할 수 있지만, 반드시 명령형을 허용하지는 않지만, 일부 '순전히'선언적 언어는 부작용과 돌연변이를 모두 허용합니다.
선언적 언어는 종종 '해야 할 일'과 달리 '해야 할 일'을 지정한다고 말합니다. 오해, 선언적 프로그램은 여전히 입력에서 출력으로 이동하는 방법을 지정하지만 다른 방법으로는 지정한 관계는 효과적으로 계산할 수 있어야합니다 (중요한 용어, 모르는 경우 찾아보십시오). 또 다른 접근법은 비 결정적 프로그래밍입니다. 실제로 구현이 시행 착오에 이르는 모든 경로를 다 사용하기 전에 결과가 많이 충족되는 조건을 지정합니다.
순전히 선언적인 언어에는 Haskell 및 Pure Prolog가 포함됩니다. Pure Prolog, Haskell, OCaml, Scheme / Lisp, Python, Javascript, C--, Perl, PHP, C ++, Pascall, C, Fortran, Assembly는 슬라이딩 스케일입니다.
factorial
이 값을 변경하지 않는지 확인하십시오 .
분류 체계가 잘못되었다고 생각합니다. 명령형과 선언 형의 두 가지 반대 유형이 있습니다. 기능은 선언의 하위 유형일뿐입니다. BTW, 위키 백과는 같은 사실을 말합니다.
간단히 말해서, 프로그래밍 스타일이 많을수록 그 스타일이 선언적이라고 여겨지는 방법에 대한 세부 사항을 추상화하는 방법 (할 일)이 강조됩니다. 명령의 경우에는 반대입니다. 함수형 프로그래밍은 선언적 스타일과 관련이 있습니다.