문제

나는 둘 다에 대한 Wikipedia 기사를 읽었습니다. 절차적 프로그래밍 그리고 함수형 프로그래밍, 하지만 여전히 약간 혼란스럽습니다.누군가 그것을 핵심까지 끓일 수 있습니까?

도움이 되었습니까?

해결책

(이상적으로는) 함수형 언어를 사용하면 수학 함수를 작성할 수 있습니다.걸리는 함수 N 인수를 입력하고 값을 반환합니다.프로그램이 실행되면 이 기능은 필요에 따라 논리적으로 평가됩니다.1

반면에 절차적 언어는 일련의 작업을 수행합니다. 잇달아 일어나는 단계.(순차 논리를 함수 논리로 변환하는 방법이 있습니다. 연속 패스 스타일.)

결과적으로, 순전히 기능적인 프로그램은 항상 다음을 산출합니다. 같은 값 입력의 경우 평가 순서가 잘 정의되어 있지 않습니다.이는 사용자 입력이나 무작위 값과 같은 불확실한 값은 순수 함수형 언어로 모델링하기 어렵다는 것을 의미합니다.


1 이 답변의 다른 모든 내용과 마찬가지로 이는 일반화입니다.순차적으로 호출되는 것이 아니라 결과가 필요할 때 계산을 평가하는 속성을 "게으름"이라고 하며, 모든 함수형 언어가 실제로 보편적으로 게으른 것은 아니며 게으름이 함수형 프로그래밍에만 국한되는 것도 아닙니다.오히려 여기에 제공된 설명은 뚜렷하고 반대되는 범주가 아니라 오히려 유동적인 아이디어인 다양한 프로그래밍 스타일에 대해 생각할 수 있는 "정신적 프레임워크"를 제공합니다.

다른 팁

기본적으로 두 가지 스타일은 음과 양과 같습니다.하나는 조직화되어 있고 다른 하나는 혼란스럽습니다.함수형 프로그래밍이 확실한 선택인 상황도 있고, 절차적 프로그래밍이 더 나은 선택인 상황도 있습니다.이것이 최근 두 프로그래밍 스타일을 모두 포용하는 새 버전으로 출시된 언어가 두 개 이상 있는 이유입니다. ( 펄 6 그리고 D 2 )

절차:

  • 루틴의 출력이 항상 입력과 직접적인 상관 관계를 갖는 것은 아닙니다.
  • 모든 것은 특정한 순서로 이루어집니다.
  • 루틴을 실행하면 부작용이 있을 수 있습니다.
  • 선형 방식으로 솔루션 구현을 강조하는 경향이 있습니다.

펄 6

디 2

int factorial( int n ){

  int result = 1;

  for( ; n > 0 ; n-- ){
    result *= n;
  }

  return result;
}

기능의:

  • 재귀적인 경우가 많습니다.
  • 주어진 입력에 대해 항상 동일한 출력을 반환합니다.
  • 평가 순서는 일반적으로 정의되지 않습니다.
  • 무국적자여야 합니다.즉.어떤 수술도 부작용이 있을 수 없습니다.
  • 병렬 실행에 적합
  • 분할 정복 접근법을 강조하는 경향이 있습니다.
  • Lazy Evaluation 기능이 있을 수 있습니다.

하스켈

(에서 복사됨 위키피디아 );

fac :: Integer -> Integer

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

또는 한 줄로:

fac n = if n > 0 then n * fac (n-1) else 1

펄 6

디 2

pure int factorial( invariant int n ){
  if( n <= 1 ){
    return 1;
  }else{
    return n * factorial( n-1 );
  }
}

참고 사항:

팩토리얼은 실제로 서브루틴을 생성하는 것과 같은 방식으로 Perl 6에서 새로운 연산자를 생성하는 것이 얼마나 쉬운지를 보여주는 일반적인 예입니다.이 기능은 Perl 6에 깊이 뿌리박혀 있어 Rakudo 구현의 대부분의 연산자가 이런 방식으로 정의됩니다.또한 기존 연산자에 자신만의 다중 후보를 추가할 수도 있습니다.

이 예에서는 범위 생성(2..$n) 및 목록 축소 메타 연산자([ OPERATOR ] LIST) 숫자 중위 곱셈 연산자와 결합됩니다.(*)
넣을 수도 있음을 보여줍니다. --> UInt 대신 서명에 returns UInt 그 후에.

( 다음과 같이 범위를 시작하면 벗어날 수 있습니다. 2 곱셈 "연산자"가 반환되므로 1 인수 없이 호출할 때)

나는 이 정의를 다른 곳에서 본 적이 없지만 이것이 여기에 주어진 차이점을 상당히 잘 요약한다고 생각합니다.

기능의 프로그래밍에 중점을 둡니다. 표현

절차적 프로그래밍에 중점을 둡니다. 진술

표현식에는 값이 있습니다.기능적 프로그램은 컴퓨터가 수행해야 하는 일련의 명령을 가치로 표현한 것입니다.

명령문에는 값이 없으며 대신 일부 개념적 기계의 상태를 수정합니다.

순전히 함수형 언어에는 상태를 조작할 방법이 없다는 의미에서 명령문이 없습니다("명령문"이라는 구문 구조가 여전히 있을 수 있지만 상태를 조작하지 않는 한 이러한 의미에서 명령문이라고 부르지 않을 것입니다). ).순전히 절차적 언어에서는 표현이 없으며 모든 것이 기계의 상태를 조작하는 명령이 됩니다.

하스켈은 상태를 조작할 방법이 없기 때문에 순수 함수형 언어의 예가 될 것입니다.기계어 코드는 순전히 절차적 언어의 예입니다. 프로그램의 모든 것은 기계의 레지스터와 메모리 상태를 조작하는 명령문이기 때문입니다.

혼란스러운 부분은 대부분의 프로그래밍 언어에 다음이 포함되어 있다는 것입니다. 둘 다 표현식과 명령문을 사용하여 패러다임을 혼합할 수 있습니다.언어는 진술과 표현의 사용을 얼마나 장려하는지에 따라 더 기능적이거나 더 절차적인 언어로 분류될 수 있습니다.

예를 들어, 함수 호출은 표현식인 반면, COBOL에서 하위 프로그램을 호출하는 것은 명령문(공유 변수의 상태를 조작하고 값을 반환하지 않음)이기 때문에 C는 COBOL보다 더 기능적입니다.Python은 단락 평가(if 문과 반대되는 테스트 && path1 || path2)를 사용하여 조건부 논리를 표현식으로 표현할 수 있기 때문에 C보다 더 기능적입니다.Scheme은 Python보다 더 기능적입니다. 왜냐하면 Scheme의 모든 것이 표현식이기 때문입니다.

절차적 패러다임을 장려하는 언어에서는 함수형 스타일로 작성할 수 있으며 그 반대의 경우도 마찬가지입니다.언어에서 권장하지 않는 패러다임으로 작성하는 것은 더 어렵고/또는 더 어색합니다.

컴퓨터 과학에서 함수형 프로그래밍은 계산을 수학적 함수의 평가로 취급하고 상태 및 변경 가능한 데이터를 피하는 프로그래밍 패러다임입니다.상태 변화를 강조하는 절차적 프로그래밍 스타일과 달리 함수 적용을 강조합니다.

나는 절차적/기능적/객관적 프로그래밍이 문제에 접근하는 방법에 관한 것이라고 믿습니다.

첫 번째 스타일은 모든 것을 단계적으로 계획하고 한 번에 한 단계(절차)를 구현하여 문제를 해결합니다.반면, 함수형 프로그래밍은 문제를 하위 문제로 나눈 다음 각 하위 문제를 해결하고(해당 하위 문제를 해결하기 위한 함수 생성) 결과를 결합하는 분할 정복 접근 방식을 강조합니다. 전체 문제에 대한 답을 만들어 보세요.마지막으로, 객관적인 프로그래밍은 각각 (다소) 독특한 특성을 갖고 다른 개체와 상호 작용하는 많은 개체가 있는 미니 세계를 컴퓨터 내부에 만들어 현실 세계를 모방합니다.이러한 상호작용을 통해 결과가 나타날 것입니다.

각 프로그래밍 스타일에는 고유한 장점과 단점이 있습니다.따라서 "순수 프로그래밍"(예:순전히 절차적(아무도 이 작업을 수행하지 않습니다. 좀 이상합니다. 순전히 기능적이거나 순전히 객관적입니다)은 프로그래밍 스타일의 장점을 보여주기 위해 특별히 고안된 몇 가지 기본적인 문제를 제외하고는 불가능하지는 않더라도 매우 어렵습니다(따라서 순수함을 좋아하는 사람들을 우리는 "위니"라고 부릅니다 :D).

그런 다음 이러한 스타일 중에서 일부 각 스타일에 최적화되도록 설계된 프로그래밍 언어가 있습니다.예를 들어 어셈블리는 절차에 관한 것입니다.좋아요, 대부분의 초기 언어는 C, Pascal과 같은 Asm뿐만 아니라 (그리고 Fortran도) 절차적 언어입니다.그러면 우리는 객관적인 학교에서 유명한 Java를 모두 가지고 있습니다. (실제로 Java와 C#도 "돈 중심"이라는 수업에 속하지만 이는 다른 논의의 주제입니다.)또한 목표는 Smalltalk입니다.기능적 학교에서는 "거의 기능적"(일부는 불순하다고 간주함) Lisp 제품군과 ML 제품군, 그리고 많은 "순수 기능적" Haskell, Erlang 등을 갖게 됩니다.그런데 Perl, Python, Ruby 등의 일반 언어가 많이 있습니다.

Konrad의 의견을 확장하려면 다음을 수행하십시오.

결과적으로, 순전히 기능적인 프로그램은 항상 입력에 대해 동일한 값을 산출하며 평가 순서는 잘 정의되어 있지 않습니다.

이 때문에 기능적 코드는 일반적으로 병렬화하기가 더 쉽습니다.함수에는 (일반적으로) 부작용이 없고 (일반적으로) 인수에 따라 작동하기 때문에 많은 동시성 문제가 사라집니다.

함수형 프로그래밍은 다음을 수행할 수 있어야 할 때도 사용됩니다. 증명하다 귀하의 코드가 정확합니다.이는 절차적 프로그래밍에서는 훨씬 어렵습니다(함수형 프로그래밍에서는 쉽지 않지만 여전히 쉽습니다).

부인 성명:나는 몇 년 동안 함수형 프로그래밍을 사용하지 않았고 최근에야 다시 보기 시작했기 때문에 여기서는 완전히 정확하지 않을 수도 있습니다.:)

여기서 내가 실제로 강조하지 않은 한 가지는 Haskell과 같은 현대 함수형 언어가 명시적 재귀보다 흐름 제어를 위한 일급 함수에 더 가깝다는 것입니다.위에서 했던 것처럼 Haskell에서는 계승을 재귀적으로 정의할 필요가 없습니다.내 생각엔 뭔가

fac n = foldr (*) 1 [1..n]

완벽하게 관용적인 구조이며, 명시적 재귀를 사용하는 것보다 루프를 사용하는 것과 정신적으로 훨씬 더 가깝습니다.

함수형 프로그래밍은 전역 변수를 사용하는 절차적 프로그래밍과 동일합니다. ~ 아니다 사용되고 있습니다.

절차적 언어는 변수를 사용하여 상태를 추적하고 일련의 단계로 실행되는 경향이 있습니다.순수 함수형 언어는 상태를 추적하지 않고 불변 값을 사용하며 일련의 종속성으로 실행되는 경향이 있습니다.많은 경우 호출 스택의 상태는 절차 코드의 상태 변수에 저장되는 정보와 동일한 정보를 보유합니다.

재귀는 함수형 프로그래밍의 전형적인 예입니다.

콘라드는 이렇게 말했습니다.

결과적으로, 순전히 기능적인 프로그램은 항상 입력에 대해 동일한 값을 생성하며 평가 순서는 잘 정의되지 않습니다.이는 사용자 입력 또는 임의 값과 같은 불확실한 값이 순전히 기능적인 언어로 모델링하기 어렵다는 것을 의미합니다.

순전히 함수형 프로그램에서 평가 순서는 추론하기 힘들거나(특히 게으름의 경우) 심지어 중요하지 않을 수도 있지만 잘 정의되지 않았다고 말하면 프로그램이 진행 중인지 알 수 없는 것처럼 들리게 됩니다. 전혀 일하기 위해!

아마도 더 나은 설명은 함수형 프로그램의 제어 흐름이 함수 인수의 값이 필요한 시점에 따라 결정된다는 것입니다.좋은 점은 잘 작성된 프로그램에서는 상태가 명시적이라는 점입니다.각 함수는 입력을 임의로 나열하는 대신 매개변수로 나열합니다. 녹이는 글로벌 상태.그래서 어떤 수준에서는 한 번에 하나의 함수에 대해 평가 순서를 추론하는 것이 더 쉽습니다..각 기능은 우주의 나머지 부분을 무시하고 수행해야 하는 작업에만 집중할 수 있습니다.결합하면 기능은 단독으로 사용할 때와 동일하게[1] 작동하도록 보장됩니다.

...사용자 입력 또는 랜덤 값과 같은 불확실한 값은 순전히 기능적인 언어로 모델링하기가 어렵습니다.

순수 함수형 프로그램의 입력 문제에 대한 해결책은 명령형 언어를 다음과 같이 내장하는 것입니다. DSL 사용하여 충분히 강력한 추상화.명령형(또는 비순수 함수형) 언어에서는 "속임수"를 사용하여 상태를 암시적으로 전달할 수 있고 평가 순서가 명시적이므로(좋든 싫든) 이는 필요하지 않습니다.이러한 "속임수"와 모든 함수에 대한 모든 매개변수의 강제 평가로 인해 명령형 언어에서는 1) 자체 제어 흐름 메커니즘(매크로 없이)을 생성할 수 있는 기능을 상실하고, 2) 코드가 본질적으로 스레드로부터 안전하지 않거나 병렬화가 가능하지 않습니다. 기본적으로, 3) 실행 취소(시간 여행)와 같은 작업을 구현하려면 신중한 작업이 필요합니다(명령적인 프로그래머는 이전 값을 다시 가져오기 위한 방법을 저장해야 합니다!). 반면 순수 함수형 프로그래밍은 이러한 모든 것을 구입합니다. 잊어버렸어요 - "무료".

이것이 열성적인 것처럼 들리지 않기를 바랍니다. 단지 몇 가지 관점을 추가하고 싶었습니다.명령형 프로그래밍, 특히 C# 3.0과 같은 강력한 언어를 사용한 혼합 패러다임 프로그래밍은 작업을 완료하고 수행하는 데 여전히 완전히 효과적인 방법입니다. 은탄환은 없어.

[1] ...메모리 사용량과 관련된 경우는 제외합니다(참조.하스켈에서는 Foldl과 Foldl').

Konrad의 의견을 확장하려면 다음을 수행하십시오.

그리고 평가 순서는 잘 정의되지 않았습니다

일부 기능적 언어에는 지연 평가(Lazy Evaluation)라는 기능이 있습니다.이는 값이 필요할 때까지 함수가 실행되지 않음을 의미합니다.그때까지는 함수 자체가 전달됩니다.

절차적 언어는 1단계 2단계 3단계...2단계에서 2 + 2를 더하라고 하면 바로 수행됩니다.게으른 평가에서는 2 + 2를 더한다고 말하지만 결과가 전혀 사용되지 않으면 덧셈도 수행되지 않습니다.

기회가 있다면 Lisp/Scheme의 사본을 구해서 그 안에서 몇 가지 프로젝트를 수행해 볼 것을 권하고 싶습니다.최근에 유행하게 된 대부분의 아이디어는 수십 년 전에 Lisp에서 표현되었습니다.함수형 프로그래밍, 연속(클로저), 가비지 수집, 심지어 XML까지.

따라서 이는 현재의 모든 아이디어와 기호 계산과 같은 몇 가지 아이디어를 먼저 시작하는 좋은 방법이 될 것입니다.

함수형 프로그래밍이 어떤 것에 좋고, 무엇이 좋지 않은지 알아야 합니다.모든 것에 좋은 것은 아닙니다.일부 문제는 부작용 측면에서 가장 잘 표현되며, 동일한 질문이 질문 시기에 따라 다른 답변을 제공합니다.

@Creighton:

Haskell에는 다음과 같은 라이브러리 함수가 있습니다. 제품:

prouduct list = foldr 1 (*) list

또는 간단하게:

product = foldr 1 (*)

그래서 "관용적" 계승

fac n = foldr 1 (*)  [1..n]

단순히 그럴 것이다

fac n = product [1..n]

기능적 프로그래밍

num = 1 
def function_to_add_one(num):
    num += 1
    return num


function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)

#Final Output: 2

절차적 프로그래밍

num = 1 
def procedure_to_add_one():
    global num
    num += 1
    return num


procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()

#Final Output: 6

function_to_add_one 함수이다

procedure_to_add_one 절차이다

실행하더라도 기능 다섯 번, 돌아올 때마다 2

다음을 실행하면 절차 다섯 번, 다섯 번째 실행이 끝나면 다음을 제공합니다. 6.

절차적 프로그래밍은 일련의 명령문과 조건 구문을 (비함수적) 값인 인수에 대해 매개변수화되는 프로시저라는 별도의 블록으로 나눕니다.

함수형 프로그래밍은 함수가 일급 값이므로 다른 함수에 인수로 전달될 수 있고 함수 호출의 결과로 반환될 수 있다는 점을 제외하면 동일합니다.

이 해석에서 함수형 프로그래밍은 절차적 프로그래밍을 일반화한 것입니다.그러나 소수는 "함수형 프로그래밍"을 부작용이 없는 의미로 해석하는데, 이는 하스켈을 제외한 모든 주요 함수형 언어와는 전혀 다르지만 관련이 없습니다.

차이점을 이해하려면 절차적 프로그래밍과 함수형 프로그래밍 모두의 "대부" 패러다임이 명령형 프로그래밍.

기본적으로 절차 적 프로그래밍은 단지 주요 추상화 방법이 "절차"인 명령 프로그램을 구성하는 방법 일뿐입니다. (또는 일부 프로그래밍 언어의 "기능").객체 지향 프로그래밍조차도 상태가 객체에 캡슐화되어 "현재 상태"를 가진 객체가 되는 명령형 프로그램을 구성하는 또 다른 방법일 뿐이며, 이 객체에는 함수, 메서드 및 기타 항목 집합이 있습니다. 프로그래머는 상태를 조작하거나 업데이트합니다.

이제 함수형 프로그래밍에 관해서는 요점 그 접근 방식은 어떤 가치를 취하고 이러한 가치를 어떻게 전달해야 하는지를 식별하는 것입니다.(따라서 함수를 첫 번째 클래스 값으로 사용하여 다른 함수에 매개변수로 전달하므로 상태와 변경 가능한 데이터가 없습니다.)

추신:모든 프로그래밍 패러다임이 사용된다는 점을 이해하려면 이들 패러다임 간의 차이점을 명확히 해야 합니다.

PSS:결국 프로그래밍 패러다임은 문제 해결을 위한 서로 다른 접근법일 뿐입니다.

PSS: 이것 quora 답변에는 훌륭한 설명이 있습니다.

여기에 있는 답변 중 어느 것도 관용적 기능 프로그래밍을 보여주지 않습니다.재귀 계승 답변은 FP에서 재귀를 표현하는 데 적합하지만 대부분의 코드는 재귀적이지 않으므로 답변이 완전히 대표적이라고 생각하지 않습니다.

문자열 배열이 있고 각 문자열은 "5" 또는 "-200"과 같은 정수를 나타냅니다.내부 테스트 사례(정수 비교 사용)와 비교하여 이 입력 문자열 배열을 확인하려고 합니다.두 솔루션 모두 아래에 나와 있습니다.

절차적

arr_equal(a : [Int], b : [Str]) -> Bool {
    if(a.len != b.len) {
        return false;
    }

    bool ret = true;
    for( int i = 0; i < a.len /* Optimized with && ret*/; i++ ) {
        int a_int = a[i];
        int b_int = parseInt(b[i]);
        ret &= a_int == b_int;  
    }
    return ret;
}

기능의

eq = i, j => i == j # This is usually a built-in
toInt = i => parseInt(i) # Of course, parseInt === toInt here, but this is for visualization

arr_equal(a : [Int], b : [Str]) -> Bool =
    zip(a, b.map(toInt)) # Combines into [Int, Int]
   .map(eq)
   .reduce(true, (i, j) => i && j) # Start with true, and continuously && it with each value

순수 함수형 언어는 일반적으로 연구용 언어이지만(실제 세계에서는 자유로운 부작용을 좋아하므로) 실제 절차적 언어는 필요할 경우 훨씬 간단한 함수형 구문을 사용합니다.

이것은 일반적으로 다음과 같은 외부 라이브러리로 구현됩니다. 로다시, 또는 다음과 같은 최신 언어가 내장되어 있습니다. .함수형 프로그래밍의 무거운 작업은 다음과 같은 함수/개념으로 수행됩니다. map, filter, reduce, currying, partial, 마지막 세 개는 더 자세히 이해하기 위해 찾아볼 수 있습니다.

부록

실제로 사용하려면 함수 호출 오버헤드가 너무 높기 때문에 컴파일러는 일반적으로 함수 버전을 내부적으로 절차 버전으로 변환하는 방법을 연구해야 합니다.표시된 계승과 같은 재귀 사례는 다음과 같은 트릭을 사용합니다. 꼬리 호출 O(n) 메모리 사용량을 제거합니다.부작용이 없다는 사실은 함수형 컴파일러가 다음을 구현할 수 있게 해줍니다. && ret 최적화된 경우에도 .reduce 마지막으로 완료되었습니다.JS에서 Lodash를 사용하면 분명히 최적화가 허용되지 않으므로 성능에 타격을 줍니다(일반적으로 웹 개발에서는 문제가 되지 않습니다).Rust와 같은 언어는 내부적으로 최적화됩니다(그리고 다음과 같은 기능을 갖습니다). try_fold 돕기 위해 && ret 최적화).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top