모든 기능 언어가 가비지 콜렉션을 사용합니까?


32

범위의 끝에 스택 의미론 (자동 결정 론적 파괴)을 사용할 수있는 기능적 언어가 있습니까?


결정 론적 파괴는 실제로 부작용에만 도움이됩니다. 순수한 함수형 프로그래밍 의 맥락에서 이는 특정 (모노 딕) 동작이 항상 시퀀스의 끝에서 실행되도록하는 것을 의미합니다. 그 외에도 가비지 수집이 필요없는 기능적인 연결 언어 를 작성하는 것은 쉽습니다 .
Jon Purdy

나는 질문의 contect에 관심이 있는데, otehr과 어떤 관계가 있습니까?
mattnz

1
가비지 수집 기능이없는 함수형 언어에서는 변경 불가능한 데이터 구조의 구조적 공유가 어떻게 가능한지 알 수 없습니다. 그러한 언어를 만드는 것이 가능할 수도 있지만 제가 사용하는 언어는 아닙니다.
dan_waterworth 2009 년

Rust는 일반적으로 '기능적'으로 식별되는 많은 기능을 가지고 있습니다 (적어도 기능이 아닌 언어에서는 기능적 기능으로 원합니다). 무엇이 빠졌는지 궁금합니다. 기본적으로, 클로저, 함수 전달, 원칙적 오버로드, ADT (GADT는 없음), 패턴 일치, GC가없는 경우 불변. 또 뭐요?
Noein

답변:


10

함수형 프로그래밍 전문가는 아니지만 내가 아는 것은 없습니다.

함수에서 반환 된 값에는 동일한 함수 내에서 생성 된 (스택에서) 다른 값에 대한 참조가 포함되거나 매개 변수로 쉽게 전달되거나 전달 된 무언가에 의해 참조 될 수 있기 때문에 원칙적으로 매우 어려운 것 같습니다. 매개 변수로. C 에서이 문제는 프로그래머가 올바르게 작동하지 않으면 매달려있는 포인터 (또는 더 정확하게는 정의되지 않은 동작)가 발생할 수 있도록하여 처리됩니다. 기능적 언어 디자이너가 승인하는 솔루션이 아닙니다.

그러나 잠재적 인 해결책이 있습니다. 한 가지 아이디어는 값의 수명을 값에 대한 참조와 함께 값 유형의 일부로 만들고 스택 할당 값이 반환되거나 무언가에서 참조되는 것을 방지하는 유형 기반 규칙을 정의하는 것입니다. 기능. 나는 그 의미를 극복하지 못했지만 그것이 끔찍한 것으로 생각됩니다.

모나 딕 코드의 경우 (실제로 또는 거의) 모나 딕이며 자동으로 결정적으로 파괴되는 IORef를 제공 할 수있는 또 다른 솔루션이 있습니다. 원칙은 "중첩"동작을 정의하는 것입니다. 결합 연산자를 사용하여 결합하면 중첩 제어 흐름을 정의합니다. "XML 요소"라고 생각합니다. 가장 왼쪽의 값은 바깥 시작 태그와 끝 태그 쌍을 제공합니다. 이 "XML 태그"는 다른 추상화 레벨에서 모나 딕 동작의 순서를 정의합니다.

어떤 시점에서 (연관 구성 체인의 오른쪽에) 중첩을 끝내려면 중간에 구멍을 채우는 일종의 터미네이터가 필요합니다. 터미네이터가 필요하다는 것은 아마도 네스트 컴포지션 연산자가 모나 딕하지 않다는 것을 의미하지만, 세부 사항을 다루지 않았으므로 완전히 확실하지 않습니다. 터미네이터를 적용하면 중첩 동작을 효과적으로 구성된 일반 모나 딕 동작으로 변환 할 수 있습니다. 반드시 중첩 컴포지션 연산자에 영향을 미치지는 않습니다.

이러한 특수 조치 중 많은 부분이 널 "종료 태그"단계를 가지며 "시작 태그"단계를 간단한 monadic 조치와 동일시합니다. 그러나 일부는 변수 선언을 나타냅니다. 이것들은 begin-tag를 가진 생성자와 end-tag를 가진 소멸자를 나타냅니다. 그래서 당신은 같은 것을 얻습니다 ...

act = terminate ((def-var "hello" ) >>>= \h ->
                 (def-var " world") >>>= \w ->
                 (use-val ((get h) ++ (get w)))
                )

다음과 같은 실행 순서로 모나 딕 구성으로 변환하면 각 태그 (요소가 아님)는 정상적인 모나 딕 동작이됩니다.

<def-var val="hello">  --  construction
  <def-var val=" world>  --  construction
    <use-val ...>
      <terminator/>
    </use-val>  --  do nothing
  </def-val>  --  destruction
</def-val>  --  destruction

이와 같은 규칙을 사용하면 C ++ 스타일 RAII를 구현할 수 있습니다. 일반 IORef가 모나드를 이스케이프 할 수없는 이유와 유사한 이유로 IORef와 같은 참조는 범위를 벗어날 수 없습니다. 연관 구성 규칙은 참조를 이스케이프 할 방법을 제공하지 않습니다.

편집 -나는 거의 말을 잊어 버렸습니다-여기에 확실하지 않은 명확한 영역이 있습니다. 외부 변수가 내부 변수를 참조 할 수 없도록하는 것이 중요하므로 기본적으로 이러한 IORef와 같은 참조로 수행 할 수있는 작업에 제한이 있어야합니다. 다시, 나는 모든 세부 사항을 다루지 않았습니다.

따라서 구성은 예를 들어 파괴가 닫히는 파일을 열 수 있습니다. 건축은 소켓이 열리고 파괴가 닫힙니다. 기본적으로 C ++에서와 같이 변수는 자원 관리자가됩니다. 그러나 C ++과 달리 자동으로 파괴 할 수없는 힙 할당 객체는 없습니다.

이 구조는 RAII를 지원하지만 가비지 수집기가 여전히 필요합니다. 중첩 작업이 메모리를 할당하고 해제하여 리소스로 취급 할 수는 있지만 해당 메모리 덩어리 및 다른 곳에 기능적 값에 대한 모든 참조가 여전히 존재합니다. 메모리가 스택에 간단하게 할당 될 수 있고 힙이 필요없는 것을 피할 수 있다면 다른 종류의 리소스 관리에있어 중요한 의미가 있습니다.

따라서 이것이 달성하는 것은 RAII가 단순한 중첩 범위를 기반으로하는 경우 RAII 스타일 자원 관리를 메모리 관리와 분리하는 것입니다. 메모리 관리를 위해 가비지 수집기가 여전히 필요하지만 다른 리소스를 안전하고시기 적절하게 자동으로 정리할 수 있습니다.


모든 기능 언어에서 GC가 필요한 이유를 알 수 없습니다 . C ++ 스타일 RAII 프레임 워크가있는 경우 컴파일러에서도 해당 메커니즘을 사용할 수 있습니다. 공유 값은 RAII 프레임 워크 (C ++ 참조)에는 문제가되지 않지만 shared_ptr<>여전히 결정 론적 파괴를 유지합니다. RAII에 까다로운 것은 순환 참조입니다. 소유권 그래프가 방향 비순환 그래프 인 경우 RAII가 제대로 작동합니다.
MSalters

문제는 함수형 프로그래밍 스타일이 실제로 클로저 / 람다 / 익명 함수를 중심으로 구축 된 것입니다. GC가 없으면 클로저를 사용할 자유가 동일하지 않으므로 언어의 기능이 크게 저하됩니다.
오는 폭풍 17

@comingstorm-C ++에는 람다 (C ++ 11 현재)가 있지만 표준 가비지 수집기는 없습니다. 람다는 폐쇄 환경에서도 환경을 유지하며 해당 환경의 요소는 참조로 전달 될 수 있으며 포인터가 값으로 전달 될 수 있습니다. 그러나 두 번째 단락에서 썼 듯이 C ++은 포인터를 매달 수있는 가능성을 허용합니다. 컴파일러 또는 런타임 환경이 아닌 프로그래머가 책임지지 않습니다.
Steve314

@MSalters-참조주기를 만들 수 없도록하는 데 드는 비용이 있습니다. 그러므로 언어가 그러한 제한을 책임지게하는 것은 최소한 사소한 일입니다. 포인터에 할당하는 것은 일정하지 않은 시간 작업이 될 것입니다. 경우에 따라 여전히 최선의 선택 일 수 있습니다. 가비지 콜렉션은 다른 비용으로이 문제를 방지합니다. 프로그래머에게 책임을 부여하는 것도 또 다른 일입니다. 기능적 언어가 아닌 필수 언어에서 매달려있는 포인터가 괜찮아 야하는 강력한 이유는 없지만 여전히 포인터 매달려있는 Haskell을 작성하지 않는 것이 좋습니다.
Steve314

수동 메모리 관리는 Lisp 또는 Haskell 클로저와 마찬가지로 C ++ 11 클로저를 사용할 자유가 거의 없다는 것을 의미한다고 주장합니다. (실제로 함수형 시스템 프로그래밍 언어를 작성하고
싶기 때문에이

3

C ++을 함수형 언어 (람다가 있음)로 간주하면 가비지 수집을 사용하지 않는 언어의 예입니다.


8
C ++을 기능적 언어로 간주하지 않으면 어떻게해야합니까 (IMHO는 그렇지 않습니다. 기능적 프로그램을 작성할 수는 있지만 비 기능적 (기능적 ....) 프로그램을 작성할 수도 있습니다)
mattnz

@ mattnz 그렇다면 대답이 적용되지 않는 것 같습니다. 다른 언어로 어떤 일이 발생하는지 잘 모르겠습니다 (예 : haskel)
BЈовић

9
C ++이 기능적이라고 말하는 것은 Perl이 객체 지향적이라고 말하는 것과 같습니다.
Dynamic

최소한 c ++ 컴파일러는 부작용을 확인할 수 있습니다. (const를 통해)
tp1

@ tp1-(1) 이것이 누구의 언어가 가장 좋은지에 회귀하지 않기를 바랍니다. (2) 사실이 아닙니다. 첫째, 실제로 중요한 효과는 대부분 I / O입니다. 둘째, 가변 메모리에 영향을 주더라도 const는 차단하지 않습니다. 형식 시스템을 대체 할 가능성이 없다고 가정하더라도 (일반적으로 C ++에서는 합리적 임) 논리적 constness와 "mutable"C ++ 키워드에 문제가 있습니다. 기본적으로 const에도 불구하고 여전히 돌연변이가있을 수 있습니다. 결과가 여전히 "논리적으로"동일하지만 반드시 동일한 표현이 아닌지 확인해야합니다.
Steve314

2

나는 "기능적 언어"의 표준 모음이 있다고 가정하기 때문에 질문이 잘못 정의되었다고 말해야한다. 거의 모든 프로그래밍 언어는 어느 정도의 기능적 프로그래밍을 지원합니다. 그리고 거의 모든 프로그래밍 언어는 일정량의 명령형 프로그래밍을 지원합니다. 문화적 편견과 대중적인 교리에 의해 인도되는 것 외에, 기능적 언어와 명령형 언어 중 어느 것을 말할 수 있는가?

문제를 표현하는 더 좋은 방법은 "스택 할당 메모리에서 기능적 프로그래밍을 지원하는 것"입니다. 이미 언급했듯이 대답은 매우 어렵습니다. 함수형 프로그래밍 스타일은 필요에 따라 재귀 데이터 구조의 할당을 촉진합니다. 여기에는 힙 메모리 (가비지 수집 또는 참조 횟수)가 필요합니다. 그러나 영역 기반 메모리 분석 이라고하는 매우 정교한 컴파일러 분석 기술이 있습니다.이를 사용하면 스택 할당과 유사한 방식으로 힙을 큰 블록으로 분할하여 자동으로 할당 및 할당 해제 할 수 있습니다. Wikipedia 페이지에는 "기능적"및 "제 국적"언어에 대한 다양한 기술 구현이 나열되어 있습니다.


1
IMO 참조 계산 가비지 수집이며 힙이 있다고해서 이것이 유일한 옵션임을 암시하지는 않습니다. C malloc 및 mfrees는 힙을 사용하지만 (표준) 가비지 수집기가 없으며 참조 코드 만 작성하면 참조 횟수 만 있습니다. C ++은 거의 동일합니다-참조 카운트가 내장 된 스마트 포인터 (C ++ 11의 표준)가 있지만 실제로 필요한 경우 수동으로 새로 작성하고 삭제할 수 있습니다.
Steve314

참조 횟수가 가비지 수집이 아니라고 주장하는 일반적인 이유는 참조주기를 수집하지 못하기 때문입니다. 그것은 간단한 구현 (아마도 C ++ 스마트 포인터 포함-확인하지 않은)에 적용되지만 항상 그런 것은 아닙니다. 하나 이상의 Java 가상 머신 (IBM, IIRC)이 가비지 콜렉션의 기초로 참조 계수를 사용했습니다.
Steve314
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.