함수형 프로그램이 컴파일 성공과 정확성간에 상관 관계가있는 이유는 무엇입니까?


12

LINQ를 처음 사용하기 시작한 이래로 4 년 동안 함수형 프로그래밍을 지향하고 있습니다. 최근에, 나는 순수한 기능적 C # 코드를 작성했고, 기능성 프로그램에 대해 읽은 것을 직접 보았습니다.

나는 이것이 왜 그런지 손가락을 쓰려고했지만 성공하지 못했습니다.

OO 원칙을 적용 할 때 기능 프로그램에없는 "추상 계층"이 있으며이 추상화 계층을 통해 구현 간 잘못된 개체 간 계약을 수정할 수 있습니다.

누구든지 이것에 대해 생각하고 함수형 프로그래밍에서 컴파일 성공과 프로그램 정확성 간의 상관 관계에 대한 근본적인 추상적 이유를 생각해 냈습니까?


9
Lisp는 기능적 언어이지만, 컴파일 시간을 확인할 수는 없습니다. 몇 가지 다른 기능적 언어에도 동일합니다. 당신이 말하는 언어의보다 정확한 특성은 다음과 같습니다 : 강력한 형식의 시스템 (최소 Hindley-Milner)을 가진 언어.

1
@delnan 나는 함수형 프로그래밍 코드를 작성하는데 사용될 수 있지만 Lisp는 함수형 프로그래밍 언어라고 말하지 않을 것이다. Lisp 방언 인 Clojure는 함수형 프로그래밍 언어입니다
sakisk

2
@delnan에 동의합니다. 이 문장은 정적 타입의 함수형 프로그래밍 언어, 특히 Hindley-Milner 시스템을 사용하는 Haskell과 관련이 있습니다. 주요 아이디어는 유형을 올바르게 얻으면 프로그램이 정확하다는 자신감이 높아진다는 것입니다.
사키 스크

1
함수형 코드는 일반적인 주류 OOP 코드만큼 추상화 및 간접적 인 수를 가질 수 있습니다. 악마는 세부 사항에 있습니다-부작용이 적고 null이 없으면 추적 할 수있는 상태가 적고 실수를 일으킬 가능성이 적습니다. 주류 명령형 언어로 동일한 원칙을 적용 할 수 있습니다. 더 많은 작업이 필요하고 더 장황한 경우가 많습니다 (예 : final모든 것을 때려야 함).
Doval

1
하지 프로그램의 전체 대답하지만, 타이핑 입니다 프로그램의 형식 검증의 원유 형태. 일반적으로 객체 지향 프로그램은 대체 를 고려해야하기 때문에 복잡하거나 매우 간단한 유형의 시스템을 갖 습니다. 대부분의 경우 편의상 소리가 나지 않습니다. OTOH ML 유사 시스템은 CH를 최대한으로 사용할 수 있으므로 증명을 유형으로 인코딩하고 컴파일러를 증명 검사기로 사용할 수 있습니다.
Maciej Piechotka

답변:


12

나는이 대답을 많은 것을 증명하는 사람으로 쓸 수 있으므로 정확성은 작동하는 것이 아니라 작동하고 입증하기 쉬운 것입니다.

많은 의미에서 함수형 프로그래밍은 명령형 프로그래밍보다 더 제한적입니다. 결국, C에서 변수를 절대로 돌연변이시키는 것을 막을 수있는 것은 없습니다! 실제로 FP 언어의 대부분의 기능은 몇 가지 핵심 기능 측면에서 간단하게 이야기 할 수 있습니다. 그것은 모두 람다, 함수 응용 프로그램 및 패턴 일치로 요약됩니다!

그러나 파이퍼를 미리 지불 했으므로 처리해야 할 일이 훨씬 적고 상황이 어떻게 잘못 될 수 있는지에 대한 옵션이 훨씬 적습니다. 1984 팬이라면 자유는 참으로 노예입니다! 프로그램에 101 가지의 깔끔한 트릭을 사용함으로써 이러한 101 가지 상황이 발생할 수있는 것처럼 사물을 추론해야합니다! 그것이 밝혀지면 정말하기가 어렵습니다 :)

칼 대신 안전 가위로 시작하면 달리기는 덜 위험합니다.

이제 우리는 당신의 질문을 살펴 봅니다 :이 모든 것이 어떻게 "컴파일하고 작동합니다!" 현상. 나는 이것이 코드를 증명하기 쉬운 이유와 같은 이유라고 생각합니다! 결국, 소프트웨어를 작성할 때 그것이 올바른지에 대한 비공식 증거를 구성하고 있습니다. 이 때문에 당신의 자연적인 손떨림 증거와 컴파일러 자체의 정확성에 대한 개념 (typechecking)은 상당히 많습니다.

기능과 기능 간의 복잡한 상호 작용을 추가하면 유형 시스템에서 확인하지 않는 기능이 증가합니다. 그러나 비공식 증거를 작성하는 능력은 향상되지 않습니다! 즉, 초기 검사를 통해 미끄러질 수있는 것이 많으며 나중에 잡아야합니다.


1
나는 당신의 대답을 좋아하지만 나는 그것이 OP의 질문에 대답 표시되지 않습니다
sakisk

1
@faif 내 답변을 확장했습니다. TLDR : 모두는 수학자입니다.
Daniel Gratzer

"프로그램에 101 가지의 깔끔한 트릭을 사용함으로써, 우리는 이러한 101 가지 일이 일어날 수있는 것처럼 사물을 추론해야합니다!" 당신의 머리에 많은 정보.
Giorgio

12

함수형 프로그래밍에서 컴파일 성공과 프로그램 정확성 간의 상관 관계에 대한 근본적인 추상 이유는 무엇입니까?

가변 상태.

컴파일러는 정적으로 검사합니다. 그것들은 당신의 프로그램이 잘 구성되어 있는지 확인하고 타입 시스템은 올바른 종류의 장소에서 올바른 종류의 값이 허용되도록하는 메커니즘을 제공합니다. 타입 시스템은 또한 올바른 종류의 장소에서 올바른 종류의 의미가 허용되도록 노력합니다.

프로그램이 상태를 도입하자마자 후자의 제약이 덜 유용 해집니다. 올바른 지점에서 올바른 값에 대해 걱정할 필요가있을뿐만 아니라 프로그램의 임의의 지점에서 변경되는 값을 고려해야합니다. 해당 상태와 함께 변경되는 코드의 의미를 고려해야합니다.

함수형 프로그래밍을 잘하고 있다면 변경 가능한 상태가 없거나 아주 적습니다.

컴파일러가 더 많은 버그를 잡을 수 있기 때문에 상태가없는 프로그램이 컴파일 후 더 자주 작동하는 경우 또는 해당 스타일의 프로그래밍으로 버그가 덜 발생하기 때문에 컴파일 후 상태가없는 프로그램이 더 자주 발생하는 경우에는 원인에 대해 약간의 논쟁이 있습니다.

내 경험에 두 가지가 혼합되어있을 것입니다.


2
"내 경험에서 두 가지가 혼합 된 것 같습니다.": 나는 같은 경험을 가지고 있습니다. 정적 타이핑은 명령형 언어 (예 : 파스칼)를 사용할 때 컴파일 타임에 오류를 포착합니다. FP에서 변경 가능성을 피하고 더 선언적인 프로그래밍 스타일을 사용하면 코드를 쉽게 추론 할 수 있습니다. 언어가 둘 다 제공하는 경우 두 가지 장점이 있습니다.
Giorgio

7

간단히 말해서, 제한 사항은 사물을 결합하는 올바른 방법이 적다는 것을 의미하며, 일류 함수는 루프 구조와 같은 요소를 더 쉽게 추출 할 수있게합니다. 이 답변 에서 루프를 가져옵니다. 예를 들면 다음과 같습니다.

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        iterator.remove();
    }
}

이것은 Java에서 반복하는 동안 컬렉션에서 요소를 제거하는 안전한 방법 중 하나입니다. 매우 가깝게 보이지만 잘못된 방법이 많이 있습니다. 이 방법을 모르는 사람들은 때로는 사본을 반복하는 것처럼 문제를 피하기 위해 복잡한 방법을 사용합니다.

이 제네릭을 만드는 것은 끔찍한 일이 아니기 때문에의 컬렉션 이상에서 작동 Strings하지만 일급 함수가 없으면 술어 ( if) 안의 조건을 바꿀 수 없으므로이 코드는 복사되어 붙여 넣는 경향이 있습니다 약간 수정되었습니다.

당신에게주는 일류의 기능을 결합 능력 그렇게하지 않으면 매우 성가신하게 불변성의 제한 매개 변수로의 술어를 통과를, 그리고 당신은 같은 간단한 빌딩 블록 마련 filter이 스칼라 코드와 같이, 그것은 같은 일을합니다 :

list filter (!_.isEmpty)

스칼라의 경우 컴파일 타임에 타입 시스템이 당신을 위해 무엇을 검사하는지 생각해보십시오. 그러나이 검사는 처음으로 그것을 실행할 때 동적 타입 시스템에 의해 수행됩니다.

  • listfilter메소드 를 지원하는 일종의 유형 , 즉 컬렉션 이어야합니다 .
  • 의 요소 에는 부울을 리턴 list하는 isEmpty메소드가 있어야합니다 .
  • 출력은 동일한 유형의 요소를 가진 (잠재적으로) 더 작은 모음입니다.

일단 그러한 것들이 확인되면 프로그래머가 망치는 다른 방법은 무엇입니까? 실수로를 잊어 버렸기 때문에 !테스트 사례가 매우 명백하게 실패했습니다. 그것은 유일하게 할 수있는 유일한 실수이며, 역 조건을 테스트 한 코드에서 직접 번역했기 때문에 실수했습니다.

이 패턴은 반복해서 반복됩니다. 일급 함수를 사용하면 정확한 의미를 가진 재사용 가능한 작은 유틸리티로 사물을 리팩토링 할 수 있으며, 불변성과 같은 제한 사항으로 인해 그렇게 할 수 있습니다. 유틸리티의 매개 변수를 검사하면 유형을 확인하는 데 필요한 공간이 거의 없습니다.

물론 이것은 filter이미 단순화 된 기능이 이미 존재 한다는 것을 알고 그것을 찾을 수 있거나 자신을 만들면 얻을 수있는 이점을 인식 한다는 것을 프로그래머에게 달려 있습니다. 꼬리 재귀 만 사용하여 어디에서나 직접 구현해보십시오. 명령 버전과 같은 복잡한 보트로 돌아 왔습니다. 당신은 그냥 있기 때문에 매우 간단하게 쓰기, 간단한 버전은 분명 의미하지 않는다.


"그러한 것들을 확인한 후 프로그래머가 조일 수있는 다른 방법은 무엇입니까?": 이것은 (1) 정적 타이핑 + (2) 기능적 스타일로 인해 문제를 해결하는 방법이 적다는 내 경험을 확인시켜줍니다. 결과적으로 나는 올바른 프로그램을 더 빨리 얻는 경향이 있으며 FP를 사용할 때 더 적은 단위 테스트를 작성해야합니다.
Giorgio

2

함수형 프로그래밍 컴파일과 런타임 정확성 사이에는 중요한 상관 관계가 없다고 생각합니다. 캐스팅하지 않으면 적어도 올바른 유형을 가질 수 있기 때문에 정적으로 유형이 지정된 컴파일과 런타임 정확성간에 약간의 상관 관계가있을 수 있습니다.

설명과 같이 성공적인 컴파일과 런타임 유형의 정확성을 서로 연관시킬 수있는 프로그래밍 언어 측면은 정적 타이핑이며, 심지어 런타임에만 주장 할 수있는 캐스트로 유형 검사기를 약화하지 않는 경우에만 Java 또는 .Net과 같은 강력한 유형의 값 또는 위치) (타입 정보가 손실되거나 타이핑이 약한 환경 (예 : C 및 C ++))

그러나 기능적 프로그래밍 그 자체는 공유 데이터 및 변경 가능한 상태를 피하는 것과 같은 다른 방법으로 도움이 될 수 있습니다.

두 측면이 모두 정확성과 유의 한 상관 관계를 가질 수 있지만 컴파일 및 런타임 오류가 없으면 프로그램에서 수행해야 할 작업이 빠르게 수행되는 것처럼 광범위한 의미의 정확성에 대해 엄격하게 말하지 않습니다. 잘못된 입력 또는 제어 할 수없는 런타임 오류 이를 위해서는 비즈니스 규칙, 요구 사항, 유스 케이스, 어설 션, 단위 테스트, 통합 테스트 등이 필요합니다. 결국 내 생각에는 기능 프로그래밍, 정적 타이핑 또는 둘 다보다 훨씬 더 자신감이 있습니다.


이. 성공적인 컴파일로 프로그램의 정확성을 판단 할 수 없습니다. 컴파일러가 프로그램 사양에 기여한 모든 사람의 종종 상충되고 부정확 한 요구 사항을 이해할 수 있다면 성공적인 컴파일이 올바른 것으로 간주 될 수 있습니다. 그러나 그 신화적인 컴파일러에는 프로그래머가 필요하지 않습니다! 기능적 프로그램과 명령형 프로그램에 대한 컴파일과 정확성 사이의 전반적인 상관 관계 가 약간 더 높을 수 있지만 , 전체 정확성 판단의 일부는 기본적으로 관련이 없다고 생각합니다.
Jordan Rieger

2

관리자에 대한 설명 :

기능적 프로그램은 모든 것이 연결되는 하나의 큰 기계, 튜브, 케이블과 같습니다. [차]

절차 적 프로그램은 작은 기계가 들어있는 방이있는 건물과 같은 방식으로 일부 제품을 보관함에 저장하고 다른 곳에서 부분 제품을 가져 오는 것과 같습니다. [공장]

따라서 기능성 기계가 이미 서로 맞으면 무언가를 생산해야합니다. 절차 적 복합체가 실행되면 특정 효과를 감독하고 혼돈을 일으켜 기능을 보장하지 못할 수 있습니다. 모든 것이 올바르게 통합되어 있는지에 대한 점검 목록이 있더라도 상태가 너무 많아서 상황에 따라 (일부 제품이 놓여 있거나 버킷이 넘치거나 누락 됨) 보장하기가 어렵습니다.


그러나 심각하게 절차 코드는 기능 코드만큼 원하는 결과의 의미를 지정하지 않습니다. 절차 적 프로그래머는 상황 코드와 데이터로 더 쉽게 벗어날 수 있으며 한 가지 방법 (일부는 불완전한 방법)을 수행하는 여러 가지 방법을 도입 할 수 있습니다. 일반적으로 외부 데이터가 생성됩니다. 문제가 복잡해지면 기능 프로그래머가 더 오래 걸릴 수 있습니까?

강력한 유형의 기능 언어는 여전히 더 나은 데이터 및 흐름 분석을 수행 할 수 있습니다. 절차 적 언어를 사용하면 프로그램의 목표는 종종 공식 정확성 분석으로 프로그램 외부에서 정의되어야합니다.


1
더 나은 신학 : 기능적 프로그래밍은 고객이없는 헬프 데스크와 같습니다. 목적이나 효율성에 의문을 제기하지 않는 한 모든 것이 훌륭합니다.
Brendan

@Brendan 자동차 및 공장은 그런 나쁜 비유를 형성하지 않습니다. 기능적 언어의 (소규모) 프로그램이 "공장"보다 작동하기 쉽고 오류가 적은 이유를 설명하려고 시도합니다. 그러나 OOP를 구하기 위해 공장은 여러 가지 물건을 생산할 수 있으며 더 큰 제품을 생산할 수 있다고 말합니다. 당신의 비교는 적당합니다; 얼마나 자주 FP가 병렬화하고 최적화 할 수 있지만 실제로는 말장난이 없는지 느린 결과를냅니다. 나는 아직도 FP를 붙잡고있다.
Joop Eggen

규모에 따른 기능적 프로그래밍은 en.wikipedia.org/wiki/Spherical_cow에 매우 효과적입니다 .
Den

@Den 본인은 대규모 FP 프로젝트에서 타당성 문제를 두려워하지 않을 것입니다. 심지어 그것을 사랑하십시오. 일반화에는 한계가 있습니다. 그러나 마지막 문장은 너무 일반화 (구형 소에 대한 감사)와 같이
윱 Eggen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.