함수형 프로그래밍은 객체 지향의 슈퍼 세트입니까?


26

기능성 프로그래밍이 많을수록 양파의 레이어가 이전 레이어를 모두 포함하는 것처럼 보이는 추가 추상화 레이어를 추가하는 것처럼 느껴집니다.

이것이 사실인지 모르겠습니다. 수년간 함께해온 OOP 원칙을 벗어나고, 캡슐화, 추상화, 상속, 다형성과 같은 기능적 기능을 설명 할 수 있습니까?

우리 모두가 말할 수 있다고 생각합니다. 예, 튜플을 통해 캡슐화되었거나 튜플이 기술적으로 "기능적 프로그래밍"의 사실로 간주됩니까 아니면 언어의 유틸리티입니까?

Haskell이 "인터페이스"요구 사항을 충족 할 수 있지만 방법이 기능적인 사실인지 다시 확신 할 수 없습니까? 펑터가 수학적 기초를 가지고 있다는 사실은 아마도 함수형을 기대할 수있는 확실한 기초라고 생각합니다.

기능적 사고 방식이 OOP의 4 가지 원칙을 어떻게 충족 시키거나 충족시키지 않는지 자세히 설명하십시오.

편집 : 기능적 패러다임과 객체 지향 패러다임의 차이점을 잘 이해하고 있으며 요즘에는 두 가지 모두를 할 수있는 많은 멀티 패러다임 언어가 있음을 알고 있습니다. 나는 정말로 fp (haskell과 같은 순수 주의자라고 생각)가 나열된 4 가지 중 하나를 수행 할 수있는 방법 또는 왜 그것들을 수행 할 수 없는지에 대한 정의를 찾고 있습니다. 즉, "폐쇄로 캡슐화를 수행 할 수 있습니다" (또는이 믿음이 틀린 경우 이유를 설명하십시오).


7
이 4 가지 원칙은 OOP를 "만들지"않습니다. OOP는 단순히 클래스, 클래스 계층 구조 및 해당 인스턴스를 사용하여 이들을 "해결"합니다. 그러나 함수형 프로그래밍에서 달성 할 수있는 방법이 있다면 대답도 원합니다.
Euphoric September

2
정의에 따라 @Euphoric, 그것은 화장을하지 OOP를.
Konrad Rudolph

2
@KonradRudolph 저는 많은 사람들이 OOP의 독특한 속성으로 이러한 것들과 이점을 주장한다고 알고 있습니다. "다형성"이 "하위 유형 다형성"을 의미한다고 가정하면, 후자 인 두 가지가 OOP에 통합되어있을 수 있습니다. 그러나 아직 OOOP가 아닌 접근 방식을 제외하고 캡슐화 및 추상화에 대한 유용한 정의를 아직 접하지 못했습니다. Haskell에서도 세부 정보를 숨기고 액세스를 제한 할 수 있습니다. 그리고 Haskell은 또한 아형 다형성이 아닌 임시 다형성을 가지고 있습니다. 문제는 "아형"비트가 중요합니까?

1
@KonradRudolph 더 이상 허용되지 않습니다. 어떤 것이 든, 발걸음을 넓히고 그것을 재검토 할 이유를주는 것이 동기가됩니다.

1
추상화는 최소한 원시 머신 코드 이상의 프로그래밍에 관계없이 모든 프로그래밍에 내재되어 있습니다. 캡슐화는 OOP 이전에 사용되어 왔으며 기능 프로그래밍에 내재되어 있습니다. 기능적 언어는 상속 또는 다형성에 대한 명시 적 구문을 포함 할 필요는 없습니다. 나는 그것이 '아니오'에 합산된다고 생각합니다.
sdenham

답변:


44

함수형 프로그래밍은 OOP보다 높은 계층이 아닙니다. 완전히 다른 패러다임입니다. 기능적 스타일 (F #은 정확히이 목적으로 작성 됨)로 OOP를 수행 할 수 있으며 스펙트럼의 다른 쪽 끝에는 객체 방향의 원칙을 명시 적으로 거부하는 Haskell과 같은 것들이 있습니다.

모듈 및 기능을 지원할만큼 고급 언어로 캡슐화 및 추상화를 수행 할 수 있습니다. OO는 캡슐화를위한 특별한 메커니즘을 제공하지만 OO 고유의 것은 아닙니다. OO의 요점은 당신이 언급 한 두 번째 쌍인 상속과 다형성입니다. 이 개념은 공식적으로 Liskov 대체로 알려져 있으며 객체 지향 프로그래밍에 대한 언어 수준의 지원 없이는 얻을 수 없습니다. (예, 경우에 따라 위조하는 것이 가능하지만 OO가 제공하는 많은 이점을 잃게됩니다.)

함수형 프로그래밍은 Liskov 대체에 중점을 두지 않습니다. 추상화 수준을 높이고 "부작용"을 사용하여 변경 가능한 상태 및 루틴의 사용을 최소화하는 데 중점을 둡니다. 이는 기능적 프로그래머가 실제로 무언가를 계산하는 대신 소리를내는 루틴을 만드는 데 사용하는 용어입니다. 무서운. 그러나 다시 말하지만, 이들은 완전히 분리 된 패러다임으로, 프로그래머의 언어와 기술에 따라 함께 사용할 수 있습니다.


1
음, 상속 (필요할 때 예외적으로 드문 경우)은 구성보다 달성 가능하며 유형 수준 상속보다 깨끗합니다. 다형성은 특히 다형성 유형의 존재에서 자연적입니다. 그러나 물론 나는 FP가 OOP 및 그 원칙과 아무 관련이 없다는 것에 동의합니다.
SK-logic

항상 가짜로 할 수 있습니다. 원하는 언어로 객체를 구현할 수 있습니다. 나는 다른 모든 것에 동의한다 :)
Eliot Ball

5
기능성 프로그래머가 "부작용"이라는 용어를 사용하지 않았다고 생각합니다.
sepp2k

4
@ sepp2k : 그는 그들이 용어를 발명했다고 말하지 않았으며, 잔디밭에서 내리기를 거부하는 아이들을 지칭하기 위해 일반적으로 사용하는 것과 거의 동일한 톤을 사용하여 용어를 사용한다고 말하지 않았습니다.
Aaronaught

16
@Aaronaught 내 잔디밭에있는 아이들이 나를 귀찮게하는 것이 아니라, 피의 부작용입니다! 그들이 내 잔디밭 전체에서 돌연변이를 멈 추면 전혀 신경 쓰지 않을 것입니다.
Jimmy Hoffa

10

다음 직관이 OOP와 FP를 비교하는 데 유용하다는 것을 알았습니다.

FP를 OOP의 상위 집합으로 간주하는 대신 OOP와 FP를 다음과 같은 유사한 기본 계산 모델을 보는 두 가지 대안으로 생각하십시오.

  1. 실행되는 일부 작업
  2. 작업에 대한 일부 입력 인수
  3. 작업 정의에 영향을 줄 수있는 일부 고정 데이터 / 파라미터
  4. 일부 결과 값
  5. 아마도 부작용 일 수 있습니다.

OOP에서 이것은

  1. 실행되는 방법
  2. 메소드의 입력 인수
  3. 멤버 변수 형식의 일부 로컬 데이터를 포함하는 메소드가 호출 된 오브젝트
  4. 메소드의 반환 값 (아마도 void)
  5. 이 방법의 부작용.

FP에서 이것은

  1. 실행되는 폐쇄
  2. 클로저의 입력 인수
  3. 클로저의 캡처 변수
  4. 클로저의 반환 값
  5. 클로저의 부작용 (하스켈과 같은 순수한 언어에서는 매우 통제 된 방식으로 발생).

이 해석을 통해 객체는 로컬이 아닌 동일한 변수 (컬렉션의 모든 클로저에 공통 인 객체의 멤버 변수)를 모두 캡처하는 클로저 컬렉션 ​​(메서드)으로 볼 수 있습니다. 이 관점은 객체 지향 언어에서 클로저가 종종 정확히 하나의 방법으로 객체로 모델링된다는 사실에 의해 뒷받침됩니다.

다른 관점은 객체 지향 뷰가 객체 (데이터)를 중심으로하고 기능적 뷰는 함수 / 클로저 (작업)를 중심으로한다는 사실에서 비롯된 것으로 생각합니다.


8

OOP의 정의를 요청한 사람에 따라 다릅니다. 5 명에게 물어 보면 6 개의 정의를 얻게 될 것입니다. 위키 백과는 말합니다 :

객체에 대한 합의 정의 또는 이론을 찾으려고 시도한 결과 그다지 성공적이지 않은 것으로 밝혀졌습니다.

따라서 누군가가 매우 명확한 대답을 할 때마다 소금 한 알로 가져 가십시오.

즉, FP 패러다임으로서 OOP의 상위 집합 이라는 좋은 주장이 있습니다 . 특히 객체 지향 프로그래밍이라는 용어에 대한 Alan Kay의 정의는 이 개념과 모순되지 않습니다 (그러나 Kristen Nygaard는 ). Kay가 정말로 염려 한 것은 모든 것이 객체이며 로직은 객체간에 메시지를 전달하여 구현됩니다.

질문에 더 흥미롭게도 클래스와 객체는 함수와 함수에 의해 반환 된 클로저 (한 번에 클래스와 생성자 역할을 함)로 생각할 수 있습니다. 이는 프로토 타입 기반 프로그래밍과 매우 유사하며 실제로 JavaScript를 통해 정확하게 수행 할 수 있습니다.

var cls = function (x) {
    this.y = x;
    this.fun = function () { alert(this.y); };
    return this;
};

var inst = new cls(42);
inst.fun();

(물론 JavaScript는 순수하게 기능적인 프로그래밍에서는 잘못된 값을 변경할 수 있지만 엄격한 OOP 정의에는 필요하지 않습니다.)

더 중요한 질문은 다음과 같습니다. 이것은 OOP 의 의미있는 분류입니까? 함수형 프로그래밍의 하위 집합으로 생각하면 도움이됩니까? 나는 대부분의 경우 그렇지 않다고 생각합니다.


1
패러다임을 바꿀 때 어디에 선을 그려야하는지 생각하는 것이 의미가 있다고 생각합니다. fp에서 subtypal polymorphism을 달성 할 수있는 방법이 없다고 말하면 fp를 사용하여 잘 맞는 것을 모델링하려고 시도하지 않아도됩니다. 그러나 가능하다면 fp 공간에서 심하게 작업하지만 몇 가지 틈새 공간에서 아형 다형성을 원할 때 좋은 방법을 달성하는 데 시간이 걸릴 수 있습니다 (좋은 방법은 불가능할 수도 있음). 그러나 대부분의 시스템이 시스템에 적합하면 OOP를 사용하는 것이 더 좋습니다.
Jimmy Hoffa

6

OO와 같은 FP는 잘 정의 된 용어가 아닙니다. 상이하고 상충되는 정의가 다른 학교가 있습니다. 그들이 공통으로 가지고있는 것을 취하면

  • 함수형 프로그래밍은 일급 함수를 사용한 프로그래밍

  • OO 프로그래밍은 동적으로 해결 된 오버로드의 제한된 형식과 결합 된 포함 다형성을 사용 하여 프로그래밍 합니다. (참고 : OO 서클에서 다형성 은 일반적으로 포함 다형성 을 의미하는 것으로 간주되는 반면, FP 학교는 일반적으로 파라 메트릭 다형성을 의미 합니다.)

다른 모든 것은 다른 곳에 존재하거나 어떤 경우에는 존재하지 않습니다.

FP와 OO는 두 가지 추상화 작성 도구입니다. 그들은 각각 자신의 강점과 약점을 가지고 있지만 (예를 들어, 표현 문제에서 다른 선호되는 확장 방향을 가짐), 다른 것보다 본질적으로 더 강력한 것은 없습니다. FP 커널을 통해 OO 시스템을 구축 할 수 있습니다 (CLOS는 그러한 시스템 중 하나임). OO 프레임 워크를 사용하여 퍼스트 클래스 함수를 얻을 수 있습니다 (예 : 람다 함수가 C ++ 11에 정의 된 방식 참조).


나는 당신이 '일차 함수'보다는 '일등 함수'를 의미한다고 생각합니다.
dan_waterworth 2009 년

Errr ... C ++ 11 람다는 일류 함수가 아닙니다. 각 람다는 고유 함수 포인터 유형 (모두 실제 목적을 위해 익명 구조체)을 가지고 있으며, 기본 함수 포인터 유형과 호환되지 않습니다. 그리고 std::function함수 포인터와 람다를 모두 할당 할 수있는 것은 객체 지향이 아니라 일반적으로 결정적입니다. 객체 지향의 제한된 다형성 브랜드 (서브 타입 다형성)가 파라 메트릭 다형성 (완전히 시스템 F- 오메가는 물론 Hindley-Milner)보다 강력하지 않기 때문에 이는 놀라운 일이 아닙니다.
pyon

순수 기능 언어에 대한 경험이 많지 않지만 클로저 내에서 하나의 정적 메소드 클래스를 정의하고 다른 컨텍스트로 전달할 수 있다면 적어도 절반 이상이라고 말하고 싶습니다. 기능적 스타일 옵션이 있습니다. 대부분의 언어에서 엄격한 매개 변수를 해결하는 방법에는 여러 가지가 있습니다.
Erik Reppen

2

아니; OOP는 절차 적 프로그래밍의 상위 집합으로 볼 수 있으며 인스턴스 필드에 표시된 상태를 가지고 있기 때문에 기능적 패러다임과 근본적으로 다릅니다. 기능적 패러다임에서 변수는 원하는 결과를 얻기 위해 상수 데이터에 적용되는 함수입니다.

실제로 함수형 프로그래밍을 OOP의 하위 집합으로 간주 할 수 있습니다. 모든 클래스를 불변으로 만들면 일종의 함수형 프로그래밍이 있다고 생각할 수 있습니다.


3
불변 클래스는 고차 함수,리스트 이해 또는 클로저를 만들지 않습니다. Fp는 부분 집합이 아닙니다.
Jimmy Hoffa

1
@Jimmy Hoffa : 비슷한 유형의 객체를 하나 이상 받거나 비슷한 유형의 객체 (메소드가 있고 필드가없는 유형)를 반환하는 단일 메서드가있는 클래스를 만들어서 높은 수준의 함수를 쉽게 시뮬레이션 할 수 있습니다. . 리스트 이해력은 패러다임이 아닌 프로그래밍 언어와 관련된 것이 아닙니다 (Smalltalk가이를 지원하고 OOP 임). 클로저는 C #에 있으며 Java에도 삽입됩니다.
m3th0dman

예 C #에는 클로저가 있지만 다중 패러다임이기 때문에 클로저가 다른 fp 조각과 함께 C #에 추가되었지만 (영원히 감사합니다) 죄송합니다 언어로 존재하더라도 oop하지 않습니다. 그러나 고차 함수에 대한 좋은 점은 클래스에서 메소드를 캡슐화하면 동일한 동작을 허용합니다.
Jimmy Hoffa

2
예, 그러나 클로저를 사용하여 상태를 변경하는 경우 여전히 기능적 패러다임으로 프로그래밍 하시겠습니까? 요점은-기능적 패러다임은 고차 함수, 재귀 또는 클로저가 아닌 상태 부족에 관한 것입니다.
m3th0dman

fp의 정의에 대한 흥미로운 생각. 나는 이것에 대해 더 많은 생각을 할 것입니다. 관찰을 공유해 주셔서 감사합니다.
Jimmy Hoffa

2

대답:

Wikipedia에는 ​​함수 예제 에 대한 훌륭한 기사 가 있습니다. @Konrad Rudolph는 이미 OOP 기사에 대한 링크를 제공했습니다 .

한 패러다임이 다른 패러다임의 수퍼 세트라고 생각하지 않습니다. 그것들은 프로그래밍에 대한 다른 관점이며 일부 문제는 한 관점과 다른 관점에서 더 잘 해결됩니다.

귀하의 질문은 FP 및 OOP의 모든 구현 으로 인해 더욱 복잡합니다 . 각 언어에는 질문에 대한 정답과 관련된 고유 한 특징이 있습니다.

점점 접하는 램 블링 :

나는 스칼라와 같은 언어가 당신에게 두 세계의 최고를 제공하려고한다는 생각을 좋아합니다. 나는 그것이 당신에게도 두 세계의 합병증을 줄 것이라고 걱정합니다.

Java는 OO 언어이지만 버전 7에는 일종의 클로저를 모방하는 데 사용할 수있는 "자원을 사용하여 시도"기능이 추가되었습니다. 여기서는 다른 함수 중간에 로컬 변수 "a"를 업데이트하여 해당 함수에 표시하지 않습니다. 이 경우 다른 함수의 첫 번째 절반은 ClosureTry () 생성자이고 두 번째 절반은 close () 메서드입니다.

public class ClosureTry implements AutoCloseable {

    public static void main(String[] args) {
        int a = 1;
        try(ClosureTry ct = new ClosureTry()) {
            System.out.println("Middle Stuff...");
            a = 2;
        }
        System.out.println("a: " + a);
    }

    public ClosureTry() {
        System.out.println("Start Stuff Goes Here...");
    }

    /** Interface throws exception, but we don't have to. */
    public void close() {
        System.out.println("End Stuff Goes Here...");
    }
}

산출:

Start Stuff Goes Here...
Middle Stuff...
End Stuff Goes Here...
a: 2

이것은 스트림을 열고, 스트림에 쓰고, 확실하게 닫거나, 두 함수를 서로 호출하는 것을 잊지 않는 방식으로 두 함수를 페어링하려는 의도 된 목적에 유용 할 수 있습니다. . 물론 다른 프로그래머가 무언가를 깨뜨리지 않고 try 블록을 제거 할 수있는 것은 매우 새롭고 특이한 일이므로 현재 일종의 반 패턴이지만 흥미로울 수 있습니다.

가장 필수적인 언어로 모든 루프를 재귀로 표현할 수 있습니다. 객체와 변수는 변경할 수 없습니다. 부작용을 최소화하기 위해 Procecures를 작성할 수 있습니다 (컴퓨터에서 진정한 기능을 수행 할 수는 없다고 주장하지만, 실행하는 데 걸리는 시간과 프로세서 / 디스크 / 시스템 리소스는 피할 수없는 부작용입니다). 일부 기능 언어는 모든 객체 지향 작업이 아니라도 많은 기능을 수행 할 수 있습니다. 일부 언어에는 가변 패턴과 같은 특정 패턴을 방지하는 제한 사항 (예 : 변수 업데이트 허용 안 함)이 있지만 상호 배타적 일 필요는 없습니다.

나에게있어 객체 ​​지향 프로그래밍의 가장 유용한 부분은 데이터 숨기기 (캡슐화), 비슷한 개체를 동일하게 다형성 (다형성)하고 해당 데이터에서 함께 작동하는 데이터와 메서드 (객체 / 클래스)를 수집하는 것입니다. 상속은 OOP의 주력 일지 모르지만 나에게는 가장 중요하고 가장 적게 사용되는 부분입니다.

함수형 프로그래밍에서 가장 유용한 부분은 불변성 (변수 대신 토큰 / 값), 함수 (부작용 없음) 및 클로저입니다.

나는 그것이 객체 지향적이라고 생각하지 않지만, 컴퓨터 과학에서 가장 유용한 것 중 하나는 인터페이스를 선언하는 능력이며, 다양한 기능과 데이터가 그 인터페이스를 구현한다는 것입니다. 또한 몇 가지 변경 가능한 데이터 조각을 사용하고 싶습니다. 따라서 모든 프로그램 디자인에서 변경 가능성과 부작용을 제한하려고 시도하더라도 독점적으로 기능적인 언어로는 완전히 편안하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.