함수형 프로그래밍 언어가 컴파일 시간 최적화를 수행 할 기회가 더 있습니까?


10

"실제 세계를위한 기능 프로그래밍"책을 읽고있었습니다. 명령형과 기능적 프로그래밍 언어 간의 비교로 시작했습니다. 그리고 함수형 프로그래밍에서 '값'과 '표현식'이 명령형 프로그래밍의 '변수'및 '함수'와 어떻게 다른지 언급했습니다. 토론에서 나는 일종의 아이디어를 개발했습니다.

함수형 프로그래밍 언어는 명령형 언어보다 컴파일 시간 최적화를 수행 할 수있는 기회가 더 많습니다.

사실인가요?

답변:


16

함수형 프로그래밍 언어는 훨씬 더 컴파일 시간을 최적화합니다. 그 이유 중 하나는 순도입니다. 상태가 없기 때문에 동시성은 사소합니다. 따라서 컴파일러는 프로그램의 동작을 변경하지 않고 두 개의 브랜치를 가져 와서 쉽게 동시화 할 수 있습니다.

동시에, 상태없이 계산할 수있는 것 (즉, haskell에서 비 모나 딕 한 것)은 컴파일러에 의해 미리 계산 될 수 있지만, 그러한 계산은 비용이 많이들 수 있으며 아마도 부분적으로 만 수행 될 수 있습니다.

또한 계산에 필요하지 않은 것은 프로그램에서 완전히 최적화 할 수 있습니다.


1
+1 : 부작용없는 프로그래밍은 최적화하기가 매우 쉽습니다.
S.Lott

@mathepic : 실제로 병렬화 (Haskell에서)는 컴파일 타임과 런타임 모두에서 발생합니다. 컴파일 타임은 지정한 스레드 수에 따라 샤드 (스레드 시드)를 생성 할 가치가 있는지 여부를 결정 하고 런타임은 샤드를 가능한 한 처리합니다. 단일 스레드 만 지정하면 샤드가 작성되지만 차례로 처리됩니다.
Matthieu M.

2
@mathepic : 순도의 또 다른 사용-> 게으름과 계산의 부재. 값이 필요하지 않다는 것을 증명할 수 있으면 계산을 완전히 제거하십시오. 필요할 경우 게으른 썽크를 사용하십시오. 그것이 필요하다는 것을 안다면 게으른 오버 헤드를 피하기 위해 똑바로 계산하십시오. 순도는 (단지) 놀랍습니다 :)
Matthieu M.

@Matthieu 좋은 지적
대안

1
@Masse IO 모나드조차도 순수합니다. IO 모나드를 "실행"한 결과는 그렇지 않습니다.
대안

7

원칙적으로 함수형 언어에 비해 컴파일 타임 최적화 가능성이 더 중요하다는 것은 아마도 사실 일 것입니다.

더 흥미로운 점은 이들이 현재 컴파일러에서 실제로 구현되고 이러한 최적화가 실제로 얼마나 관련성이 있는지 (예 : 예측 가능한 컴파일러 설정이있는 프로덕션 환경에서 관용적 인 '실제 (TM)'코드의 최종 성능)입니다.

예를 들어 악명 높은 Computer Language Benchmarks Game에 대한 Haskell의 제출 (그것이 나쁘지만-현재-거기에 훨씬 더 나은 것이 없습니다)은 상당한 시간이 소비되었다는 인상을줍니다. "최적화 가능한 컴파일러 최적화"에 대한 주장에 직면 한 수동 최적화 insert some property about FP languages here는 최적화가 관련 현실보다 이론적으로 가능한 것 이상으로 보인다.

나는이 시점에서 잘못 입증 된 것이 기쁘다.


1
Haskell에서 수동 최적화를 수행 한 이유는 Haskell에서 특정 "직선"작업이 다소 복잡하다는 점과 관련이 있습니다. 예를 들어, 목록의 마지막 요소를 가져오고 싶다고 가정하십시오. Java에서 이것은 매우 간단한 작업입니다. Haskell에서는 순진한 접근 방식을 사용하면 목록의 게으른 속성으로 인해 끝까지 올 때까지 전체 목록을 걸어 O (n) 연산으로 만들어야합니다. 수동 최적화가 시작되는 부분입니다.
mipadi

2
Haskell의 수동 롤링 최적화에 대한 정당한 이유가 있다고 확신하지만, "직접적인"작업에 필요한 것은 코드 최적화를위한 더 큰 기회가 이론적으로 만 관련이 있다는 인상을줍니다.
Alexander Battisti

6
알고리즘 최적화와 생성 된 코드 최적화의 차이가 더 큽니다. C 예제를 보자. 검색 알고리즘을 작성하는 경우 단순히 목록을 안내하는 순진한 알고리즘을 작성하거나 이진 검색을 사용할 수 있습니다. 두 경우 모두, 컴파일러는 내 코드를 최적화하지만 순진한 검색 알고리즘을 이진 검색으로 바꾸지 않습니다. Haskell 코드의 많은 수동 최적화는 생성 된 코드를 최적화하는 것이 아니라 알고리즘 자체를 최적화하는 것과 더 관련이 있습니다.
mipadi

2
@mipadi, 그러나 Haskell 알고리즘의 간단한 버전은 다른 언어의 알고리즘의 간단한 버전만큼 좋지 않은 것 같습니다. (기능 모델과 컴퓨터 아키텍처 사이의 불일치로 인해 의심됩니다) 코드 생성에 능숙하더라도이 문제를 극복하기에는 충분하지 않습니다.
Winston Ewert

>> 그것이 나쁘다 <<-나쁜지 아닌지 아십니까? "나쁘다"는 말의 의미는 무엇입니까? 구체적으로 설명하십시오.
igouy

2

기능적 스타일에서 프로그램을 통한 값의 흐름은 컴파일러와 프로그래머 모두에게 매우 가시적입니다. 따라서 컴파일러는 값을 저장할 위치, 보존 기간 등을 결정할 수 있습니다.

명령형 언어에서 컴파일러는 프로그래머에게 대부분의 변수가 정의 된 수명 동안 유지되는 메모리의 실제 위치에 해당하는 모델을 약속합니다. 잠재적으로 모든 명령문은 이러한 위치 중 하나에서 읽거나 쓸 수 있으므로 컴파일러는 메모리 위치를 레지스터 할당으로 바꾸거나 두 변수를 단일 저장 위치로 병합하거나 위치에 대한 어려운 분석을 수행 한 후 유사한 최적화를 수행 할 수 있습니다. 그렇지 않으면 프로그램에서 해당 변수를 참조 할 수 있습니다.

이제 두 가지 경고가 있습니다.

  • 프로그래밍 언어 커뮤니티는 지난 50 년 동안이 분석을 수행하는 영리한 방법을 개발하기 위해 많은 노력을 기울였습니다. 대부분의 경우 더 쉬운 경우를 처리하기 위해 레지스터 색상과 같은 잘 알려진 트릭이 있습니다. 그러나 이것은 크고 느린 컴파일러와 결과 코드의 품질에 대한 컴파일 복잡성의 끊임없는 균형을 만듭니다.
  • 동시에, 대부분의 기능적 프로그래밍 언어는 순수한 기능도 아닙니다. I / O에 대한 응답과 같이 프로그램이 실제로해야하는 많은 것들이 본질적으로 작동하지 않기 때문에 컴파일러가 이러한 속임수를 완전히 제거 할 수 없으며 언어가이를 완전히 피할 수 없으며 심지어 Haskell 도 마찬가지입니다. 내 취향에 순결 (Your Mileage May Vary)은 코드의 비 기능적 부분 만 제어하고 차단 할 수는 있지만 완전히 피할 수는 없습니다.

그러나 일반적인 질문에 대답하기 위해, 기능적 패러다임은 컴파일러에게 명령형 설정이없는 것을 최적화 할 수있는 많은 자유를 부여합니다.


Haskell의 모든 기능은 기능적이며 main, 상태 자체를 사용하는 것이 아니라 상태 변환 기능이라는 것입니다.
대안

예, 아니오-개념적으로, Haskell 프로그램은 사용자가 해당 프로그램과의 상호 작용 (및 시스템의 난수 생성기 상태, 현재 네트워크 대기 시간 및 기타 본질적으로 다른 것)에 대한 순수한 기능이라고 말할 수 있습니다. 비 기능적 입력은 프로그램이 응답합니다) 그러나 실제로는 차이가없는 구별입니다.
jimwise

@jimwise 참조 투명도는 매우 큰 차이입니다.
대안

적어도 여기에 논의 된 목적으로 그것을 가지고 있지 않다는 것을 제외하고. IO 또는 난수 생성과 같은 작업의 요점은 동일한 입력으로 호출 될 때마다 다른 값을 반환 해야 하며, 이는 프로그래머 컴파일러에 대해 기능적으로 추론을 제한 합니다.
jimwise

1
@mathepic 예, 물론 무작위 또는 사용자 입력 (또는 네트워크 대기 시간 또는 시스템 부하)을 개념적으로 무한 스트림 또는 상태에 따른 함수로 볼 수는 있지만 프로그램 동작에 대한 유용한 추론에 적합하지는 않습니다. 귀하 또는 귀하의 컴파일러-Bob Harper는 최근 CMU의 새로운 기능 프로그래밍 우선 CS 교과 과정에 대한 블로그 게시물 에서이 내용을 잘 다룹니다 .
jimwise
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.