C #, Visual Basic, C ++ 및 Java와 같은 OOP (object-oriented programming) 언어를 포함한 대부분의 주류 언어는 명령형 (프로 시추 럴) 프로그래밍을 지원하도록 설계되었지만 Haskell / gofer와 같은 언어는 순전히 기능적입니다. 이 두 프로그래밍 방식의 차이점이 무엇인지 자세히 설명 할 수 있습니까?
프로그래밍 방식을 선택하는 것은 사용자 요구 사항에 달려 있지만 기능적 프로그래밍 언어를 배우는 것이 권장되는 이유는 무엇입니까?
답변
정의 :
명령형 언어는 일련의 문장을 사용하여 특정 목표에 도달하는 방법을 결정합니다. 이 문장들은 각각 차례로 실행될 때 프로그램의 상태를 변경한다고합니다.
예 :
Java는 필수 언어입니다. 예를 들어 일련의 숫자를 추가하는 프로그램을 만들 수 있습니다.
int total = 0;
int number1 = 5;
int number2 = 10;
int number3 = 15;
total = number1 + number2 + number3;
각 명령문은 값을 각 변수에 지정하는 것에서 해당 값의 최종 추가에 이르기까지 프로그램의 상태를 변경합니다. 일련의 5 개의 문장을 사용하여 프로그램은 숫자 5, 10 및 15를 더하는 방법을 명시 적으로 알려줍니다.
기능적 언어 :
기능적 프로그래밍 패러다임은 문제 해결에 대한 순수한 기능적 접근을 지원하기 위해 명시 적으로 작성되었습니다. 함수형 프로그래밍은 선언적 프로그래밍의 한 형태입니다.
순수 함수의 장점 :
순수 함수로 함수 변환을 구현하는 주된 이유는 순수 함수를 구성 할 수 있다는 것입니다. 즉, 자체 포함 및 상태 비 저장입니다. 이러한 특성으로 인해 다음과 같은 여러 가지 이점이 있습니다. 가독성 및 유지 관리 성 향상. 각 기능은 주어진 인수에 따라 특정 작업을 수행하도록 설계 되었기 때문입니다. 이 기능은 외부 상태에 의존하지 않습니다.
보다 쉬운 반복 개발. 코드를 리팩토링하기가 쉽기 때문에 디자인 변경이 구현하기가 더 쉬운 경우가 많습니다. 예를 들어, 복잡한 변환을 작성한 다음 변환에서 일부 코드가 여러 번 반복된다는 것을 인식하십시오. 순수한 메소드를 통해 리팩토링하면 부작용에 대해 걱정하지 않고 순수한 메소드를 호출 할 수 있습니다.
더 쉬운 테스트 및 디버깅. 순수 함수는 더 쉽게 테스트 할 수 있으므로 일반적인 값, 유효 엣지 케이스 및 유효하지 않은 엣지 케이스를 사용하여 순수 함수를 호출하는 테스트 코드를 작성할 수 있습니다.
OOP 사용자 또는 명령형 언어의 경우 :
객체 지향 언어는 사물에 대한 고정 된 조작 세트가 있고 코드가 발전함에 따라 주로 새로운 사물을 추가 할 때 좋습니다. 기존 메소드를 구현하는 새 클래스를 추가하면 기존 클래스를 그대로 유지할 수 있습니다.
기능적 언어는 고정 된 사물 집합이 있고 코드가 발전함에 따라 기존 사물에 대한 새로운 작업을 주로 추가 할 때 좋습니다. 기존 데이터 형식으로 계산하는 새 함수를 추가하면 기존 함수가 그대로 유지됩니다.
단점 :
프로그래밍 방식을 선택하는 것은 사용자 요구 사항에 따라 달라 지므로 사용자가 올바른 방식을 선택하지 않을 경우에만 피해가 발생합니다.
진화가 잘못되면 문제가 있습니다.
- 객체 지향 프로그램에 새로운 작업을 추가하려면 새로운 메소드를 추가하기 위해 많은 클래스 정의를 편집해야 할 수도 있습니다
- 기능 프로그램에 새로운 종류의 것을 추가하려면 새로운 기능을 추가하기 위해 많은 기능 정의를 편집해야합니다.
답변
차이점은 다음과 같습니다.
피할 수 없는:
- 스타트
- 신발 사이즈 9 1/2를 켭니다.
- 열쇠 [7]를 보관할 수있는 공간을 주머니에 넣으십시오.
- 열쇠를 주머니에 넣을 방에 열쇠를 넣습니다.
- 차고를 입력하십시오.
- 차고를 엽니 다.
- 차를 입력하십시오.
… 등등 …
- 냉장고에 우유를 넣으십시오.
- 중지.
기능적 하위 범주 인 선언적 :
- 유당 소화에 문제가 없다면 우유는 건강 음료입니다.
- 일반적으로 냉장고에 우유를 저장합니다.
- 냉장고는 물건을 시원하게 보관하는 상자입니다.
- 상점은 품목이 판매되는 장소입니다.
- “판매”는 돈으로 물건을 교환하는 것을 의미합니다.
- 또한 물건으로 돈을 교환하는 것을 “구매”라고합니다.
… 등등 …
- 냉장고에 우유가 있는지 확인하십시오 (필요한 경우-게으른 기능적 언어의 경우).
요약 : 명령형 언어에서는 컴퓨터에서 메모리의 비트, 바이트 및 단어를 변경하는 방법과 순서를 알려줍니다. 기능적인 것에서, 우리는 컴퓨터에게 사물, 행동 등이 무엇인지 알려줍니다. 예를 들어, 0의 계승은 1이고 다른 모든 자연수의 계승은 그 수의 곱과 전임의 계승이라고합니다. 우리는 말하지 않습니다 : n의 계승을 계산하려면 메모리 영역을 예약하고 거기에 1을 저장 한 다음 해당 메모리 영역의 숫자에 숫자 2에서 n을 곱하고 결과를 같은 장소에 저장하십시오. 메모리 영역에는 계승이 포함됩니다.
답변
대부분의 현대 언어는 명령형과 기능면에서 다양하지만 기능적 프로그래밍을 더 잘 이해하려면 java / c #과 같은 기능적 언어가 아닌 명령형 코드와 대조적으로 Haskell과 같은 순수한 기능적 언어의 예를 취하는 것이 가장 좋습니다. 나는 항상 예제로 설명하기가 쉽다고 생각하므로 아래는 하나입니다.
함수형 프로그래밍 : n, n의 계승 계산! 즉, nx (n-1) x (n-2) x … x 2 X 1
-- | Haskell comment goes like
-- | below 2 lines is code to calculate factorial and 3rd is it's execution
factorial 0 = 1
factorial n = n * factorial (n - 1)
factorial 3
-- | for brevity let's call factorial as f; And x => y shows order execution left to right
-- | above executes as := f(3) as 3 x f(2) => f(2) as 2 x f(1) => f(1) as 1 x f(0) => f(0) as 1
-- | 3 x (2 x (1 x (1)) = 6
Haskel을 사용하면 함수 값을 인수 값 수준으로 오버로드 할 수 있습니다. 다음은 명령의 정도를 증가시키는 명령 코드의 예입니다.
//somewhat functional way
function factorial(n) {
if(n < 1) {
return 1;
}
return n * factorial(n-1);
}
factorial(3);
//somewhat more imperative way
function imperativeFactor(n) {
int f = 1
for(int i = 1; i <= n; i++) {
f = f * i
}
return f;
}
이 읽기 는 명령형 코드가 부분, 기계 상태 (i in for loop), 실행 순서, 흐름 제어에 어떻게 초점을 맞추는 지 이해하기에 좋은 참고 자료가 될 수 있습니다.
후자의 예제는 대략적으로 첫 번째 부분은 Haskell이 함수를 값 (0)으로 오버로드하는 것과 대조적으로 언어 자체의 제한으로 볼 수 있으며 첫 번째 부분은 순수한 기능적 언어가 아니라고 말할 수 있습니다. 손으로 기능적 프로그램을 지원한다고 말할 수 있습니다. 어느 정도.
공개 : 위 코드 중 어느 것도 테스트 / 실행되지 않았지만 개념을 전달하기에 충분해야합니다. 또한 나는 그러한 수정에 대한 의견을 부탁드립니다 🙂
답변
함수형 프로그래밍 은 선언적 프로그래밍의 한 형태로 계산 논리를 설명하며 실행 순서는 완전히 강조되지 않습니다.
문제 :이 생물을 말에서 기린으로 바꾸고 싶습니다.
- 목을 길게
- 다리를 길게
- 스팟 적용
- 생물에게 검은 혀를 줘
- 말 꼬리를 제거
각 항목은 순서에 관계없이 동일한 결과를 생성 할 수 있습니다.
명령형 프로그래밍 은 절차 적입니다. 상태와 질서가 중요합니다.
문제점 : 차를 주차하고 싶습니다.
- 차고 문의 초기 상태에 유의하십시오.
- 차도에서 차를 중지
- 차고 문이 닫히면 차고 문을 열고 새로운 상태를 기억하십시오. 그렇지 않으면 계속
- 차를 차고로 끌어 들여
- 차고 문 닫기
원하는 결과를 얻으려면 각 단계를 수행해야합니다. 차 고문이 닫혀있는 동안 차고 안으로 들어가면 차 고문이 파손됩니다.
답변
함수형 프로그래밍은 “함수를 사용한 프로그래밍”으로, 함수에는 참조 투명도를 포함하여 예상되는 수학적 특성이 있습니다. 이러한 속성들로부터, 추가 속성들이 흐르고, 특히 수학적 증거로 이어지는 대체 가능성에 의해 가능하게되는 친숙한 추론 단계들 (즉, 결과에 대한 신뢰를 정당화).
기능적인 프로그램은 단순한 표현 일뿐입니다.
표현식이 더 이상 참조 적으로 투명하지 않은 (따라서 함수와 값으로 작성되지 않고 자체적으로 함수의 일부가 될 수없는) 명령형 프로그램에서 위치를 주목하여 두 스타일 간의 대비를 쉽게 확인할 수 있습니다. 가장 명백한 두 가지 장소는 다음과 같습니다. 돌연변이 (예 : 변수) 기타 부작용 비 국소 적 제어 흐름 (예 : 예외)
함수와 값으로 구성된이 프로그램 표현의 프레임 워크에는 언어, 개념, “기능 패턴”, 조합기 및 다양한 유형 시스템과 평가 알고리즘의 실질적인 패러다임이 구축됩니다.
가장 극단적 인 정의로 C 또는 Java와 같은 거의 모든 언어를 기능적이라고 할 수 있지만 일반적으로 사람들은 구체적으로 관련된 추상화 (예 : 클로저, 불변 값 및 패턴 일치와 같은 구문 보조 도구)가있는 언어를 의미합니다. 함수형 프로그래밍의 사용에 관한 한 펑틴의 사용과 관련이 있으며 부작용없이 코드를 빌드합니다. 증거를 작성하는 데 사용
답변
명령형 프로그래밍 스타일은 2005 년부터 2013 년까지 웹 개발에서 실행되었습니다.
명령형 프로그래밍으로 애플리케이션이 수행해야 할 작업을 단계별로 정확하게 나열한 코드를 작성했습니다.
함수형 프로그래밍 스타일은 함수를 결합하는 영리한 방법을 통해 추상화를 생성합니다.
답변에는 선언적 프로그래밍에 대한 언급이 있으며 선언적 프로그래밍에는 우리가 따라야 할 규칙이 나열되어 있다고 말할 것입니다. 그런 다음 애플리케이션에 초기 상태라고하는 것을 제공하고 이러한 규칙이 애플리케이션의 동작 방식을 정의하도록합니다.
이제 이러한 빠른 설명은 이해가되지 않을 것이므로 유추를 통해 명령형 프로그래밍과 선언적 프로그래밍의 차이점을 살펴 보겠습니다.
우리가 소프트웨어를 개발하지 않고 대신 생계를 위해 파이를 굽는다고 상상해보십시오. 아마도 우리는 나쁜 제빵사이며 맛있는 파이를 굽는 방법을 모릅니다.
그래서 우리의 상사는 우리에게 레시피로 알려진 방향 목록을 제공합니다.
레시피는 파이 만드는 법을 알려줄 것입니다. 하나의 레시피는 다음과 같이 명령형으로 작성됩니다.
- 밀가루 1 컵을 섞는다
- 계란 1 개 추가
- 설탕 1 컵 추가
- 냄비에 혼합물을 부어
- 팬을 오븐에 30 분 350도 동안 넣습니다.
선언적 레시피는 다음을 수행합니다.
밀가루 1 컵, 달걀 1 개, 설탕 1 컵-초기 상태
규칙
- 모든 것이 혼합되면 팬에 넣습니다.
- 모든 것이 섞이지 않으면 그릇에 넣으십시오.
- 팬에 모든 것이 있으면 오븐에 넣으십시오.
따라서 명령 방식은 단계별 접근 방식으로 특징 지워집니다. 1 단계부터 시작하여 2 단계 등으로 이동하십시오.
결국 최종 제품이 생깁니다. 이 파이를 만들면이 재료들을 섞어서 팬과 오븐에 넣고 최종 제품을 얻습니다.
선언적 세계에서는 그 차이가 다릅니다. 선언적 레시피에서는 레시피를 두 개의 개별 파트로 분리하고 변수와 같이 레시피의 초기 상태를 나열하는 하나의 파트로 시작합니다. 여기 변수는 재료의 양과 유형입니다.
우리는 초기 상태 또는 초기 재료를 사용하여 몇 가지 규칙을 적용합니다.
따라서 우리는 초기 상태를 취하여 대황 딸기 파이 등을 먹을 준비가 될 때 까지이 규칙을 반복해서 통과시킵니다.
따라서 선언적 접근 방식에서 이러한 규칙을 올바르게 구성하는 방법을 알아야합니다.
따라서 재료 또는 상태를 검사하고 싶을 때 규칙을 팬에 넣습니다.
초기 상태에서는 아직 재료를 섞지 않았기 때문에 일치하지 않습니다.
따라서 규칙 2는 그들이 섞이지 않으면 그릇에 섞어 말합니다. 예,이 규칙이 적용됩니다.
이제 우리 상태로 혼합 재료 한 그릇이 있습니다.
이제 새로운 상태를 다시 규칙에 적용합니다.
따라서 규칙 1은 재료가 혼합되어 냄비에 놓이면 규칙 1이 적용된다고 말합니다.
이제 우리는 재료가 혼합되어 팬에있는이 새로운 상태를 갖게되었습니다. 규칙 1은 더 이상 관련이 없으며 규칙 2는 적용되지 않습니다.
규칙 3은 재료가 냄비에 있으면 오븐에 넣고 규칙은이 새로운 상태에 적용되는 것입니다.
그리고 우리는 맛있는 핫 애플 파이 또는 다른 것으로 끝납니다.
지금, 당신이 나와 같다면, 왜 우리가 명령형 프로그래밍을하지 않는지 생각할 것입니다. 이것은 말이됩니다.
간단한 흐름은 가능하지만 대부분의 웹 응용 프로그램에는 명령형 프로그래밍 디자인으로는 제대로 캡처 할 수없는보다 복잡한 흐름이 있습니다.
선언적 접근 방식에서는 textInput=“”
단일 변수 와 같은 초기 성분 또는 초기 상태를 가질 수 있습니다 .
텍스트 입력이 빈 문자열로 시작될 수 있습니다.
우리는이 초기 상태를 응용 프로그램에 정의 된 일련의 규칙에 적용합니다.
-
사용자가 텍스트를 입력하면 텍스트 입력을 업데이트하십시오. 글쎄, 지금은 적용되지 않습니다.
-
템플리트가 렌더링되면 위젯을 계산하십시오.
- textInput이 업데이트되면 템플릿을 다시 렌더링하십시오.
글쎄,이 중 어느 것도 적용되지 않으므로 프로그램은 이벤트가 발생할 때까지 기다릴 것입니다.
따라서 어느 시점에서 사용자는 텍스트 입력을 업데이트 한 다음 규칙 번호 1을 적용 할 수 있습니다.
우리는 그것을 업데이트 할 수 있습니다 “abcd”
그래서 우리는 방금 텍스트와 textInput 업데이트를 업데이트했습니다. 규칙 번호 2는 적용되지 않습니다. 규칙 번호 3은 텍스트 입력이 업데이트되었는지를 나타냅니다. 방금 발생한 템플릿을 다시 렌더링 한 다음 템플릿을 다시 렌더링하면 규칙 2로 돌아갑니다. 위젯을 계산하면 위젯을 계산할 수 있습니다.
일반적으로 프로그래머로서 우리는보다 선언적인 프로그래밍 디자인을 위해 노력하고 싶습니다.
명령형이 더 명확하고 명백해 보이지만 선언적 접근 방식은 대규모 응용 프로그램에 매우 적합합니다.
답변
• 명령형 언어 :
-
효율적인 실행
-
복잡한 의미
-
복잡한 구문
-
동시성은 프로그래머가 설계
-
복잡한 테스트, 참조 투명성이 없으며 부작용이 있습니다.
- 상태가
• 기능 언어 :
-
간단한 의미론
-
간단한 구문
-
덜 효율적인 실행
-
프로그램을 자동으로 동시에 만들 수 있습니다
-
간단한 테스트, 참조 투명성, 부작용 없음
- 상태가 없습니다