“브루 브 역설”과 C ++


37

나는 여기에 기사를 읽고 있었다 : http://www.paulgraham.com/avg.html "blub paradox"에 관한 부분은 특히 흥미로웠다. 주로 C ++로 코딩하지만 다른 언어 (주로 Haskell)에 노출 된 사람으로서 나는이 언어에서 C ++로 복제하기 어려운 몇 가지 유용한 것을 알고 있습니다. 문제는 주로 c ++와 다른 언어에 능숙한 사람들에게 있습니다. c ++로만 작성하는 경우 개념화하거나 구현하기 어려운 언어에서 사용하는 강력한 언어 기능이나 관용구가 있습니까?

특히이 인용문은 내 관심을 끌었습니다.

귀납적으로, 다양한 언어들 사이의 모든 힘의 차이를 볼 수있는 유일한 프로그래머는 가장 강력한 언어를 이해하는 사람들입니다. (이것은 아마도 Eric Raymond가 Lisp가 당신을 더 나은 프로그래머로 만드는 것에 대한 의미 일 것입니다.) Blub 역설 때문에 다른 사람들의 의견을 믿을 수는 없습니다. Blub 역설 때문에 그들은 사용하는 언어에 만족합니다. 그들이 프로그램에 대해 생각하는 방식.

c ++를 사용하여 "Blub"프로그래머와 동등한 것으로 밝혀지면 다음과 같은 질문이 발생합니다. 다른 언어에서 경험 한 개념이나 기술이 있습니까? C ++에서 쓰거나 "생각"했습니까?

예를 들어 Prolog 및 Mercury와 같은 언어에서 볼 수있는 논리 프로그래밍 패러다임은 캐스터 라이브러리를 사용하여 c ++로 구현할 수 있지만 궁극적으로 Prolog 코드 측면에서 생각하고이를 사용할 때 C ++로 변환한다는 것을 알았습니다. 내 프로그래밍 지식을 넓히는 방법으로 c ++ 개발자로 알지 못하는 다른 언어로보다 효율적으로 표현되는 유용하고 강력한 관용구의 다른 유사한 예가 있는지 알아 내려고 노력 중입니다. 염두에 두어야 할 또 다른 예는 lisp의 매크로 시스템입니다. 프로그램 내에서 프로그램 코드를 생성하면 일부 문제에 많은 이점이있는 것 같습니다. 이것은 C ++ 내에서 구현하고 생각하기 어려운 것 같습니다.

이 질문은 "c ++ vs lisp"토론 또는 어떤 종류의 언어 전쟁 유형 토론이 아닙니다. 이와 같은 질문을하는 것은 내가 모르는 것에 대해 알 수있는 유일한 방법입니다.



2
동의한다. 이것이 C ++ vs Lisp 토론으로 바뀌지 않는 한 여기서 배울 것이 있다고 생각합니다.
jeffythedragonslayer 4

@MasonWheeler :-Lisp there are things that other languages can do that Lisp can't가 Turing-complete이기 때문에 그렇지 않습니다 . 아마도 당신 은 Lisp에서 수행하기에 실용적이지 않은 것들이 있다고 말하고 싶습니까? 나는 모든 프로그래밍 언어 에 대해 같은 것을 말할 수 있습니다.
Robert Harvey

2
@RobertHarvey : "모든 언어는 튜링과 동등한 의미로 강력하지만, 프로그래머가 관심을 갖는 단어의 의미는 아닙니다. (튜링 머신을 프로그래밍하고 싶은 사람은 없습니다.) 공식적으로 정의 할 수 있지만 설명 할 수있는 한 가지 방법은 더 강력한 언어의 통역사를 작성함으로써 덜 강력한 언어로만 얻을 수있는 기능을 의미한다고 말하는 것입니다. " -Paul Graham, 해당 트롤 포스트 각주 (내가 무슨 뜻인지
Mason Wheeler

@Mason Wheeler : (실제로 아닙니다.)
Robert Harvey

답변:


16

하스켈을 언급 한 이후 :

  1. 패턴 매칭. 읽고 쓰기가 훨씬 쉬운 패턴 일치를 찾습니다. 맵의 정의를 고려하고 패턴 일치없이 언어로 구현되는 방법에 대해 생각하십시오.

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs
  2. 타입 시스템. 때때로 고통이 될 수 있지만 매우 도움이됩니다. 실제로 이해하고 잡는 버그의 수를 이해하려면 프로그래밍해야합니다. 또한, 참조 투명성은 훌륭합니다. 명령형 언어로 상태를 관리함으로써 몇 개의 버그가 발생했는지 Haskell에서 프로그래밍 한 후에야 분명해집니다.

  3. 일반적인 기능 프로그래밍. 반복 대신 맵과 접기를 사용합니다. 재귀. 더 높은 수준의 사고에 관한 것입니다.

  4. 게으른 평가. 다시 한 번 더 높은 수준으로 생각하고 시스템이 평가를 처리하도록하는 것입니다.

  5. 오두막, 패키지 및 모듈. Cabal 다운로드 패키지가 있으면 소스 코드를 찾거나 makefile을 작성하는 것보다 훨씬 편리합니다. 특정 이름 만 가져올 수있는 것이 기본적으로 모든 소스 파일을 함께 덤프 한 다음 컴파일하는 것보다 훨씬 좋습니다.


2
패턴 일치에 대한 참고 사항 : 나는 일반적으로 작성하기가 쉽지 않다고 말하지만 식 문제에 대해 조금 읽은 후에 if 및 switch 문, 열거 형 및 관찰자 패턴과 같은 것은 대수 데이터 형식의 구현보다 열등하다는 것이 분명해집니다. + 패턴 매칭. (아마도 널 포인터 예외를 쓸모 없게 만드는 방법에 대해서는 시작할
수조차

당신이 말하는 것은 사실이지만 표현 문제는 대수 데이터 유형의 한계 (및 표준 OOP의 이중 한계)에 관한 것입니다.
Blaisorblade

@hugomg 관찰자 대신 방문자 패턴을 의미 했습니까?
Sebastian Redl

예. 난 항상 그 두 이름 : 스위치
hugomg

@hugomg 그것은 Maybe(C ++ 참조 std::optional)에 관한 것이 아니라 선택 사항 / nullable / maybe로 명시 적으로 표시해야한다는 것입니다.
중복 제거기

7

기억하세요!

C ++로 작성해보십시오. C ++ 0x에는 해당 되지 않습니다 .

너무 성가 시나요? 좋아, 그것을 시도 C ++ 0X.

D에서이 4 라인 (또는 5 라인, : P) 컴파일 타임 버전을 이길 수 있는지 확인하십시오 .

auto memoize(alias Fn, T...)(T args) {
    auto key = tuple(args);                               //Key is all the args
    static typeof(Fn(args))[typeof(key)] cache;           //Hashtable!
    return key in cache ? cache[key] : (cache[key] = Fn(args));
}

그것을 호출하기 위해해야 ​​할 일은 다음과 같습니다.

int fib(int n) { return n > 1 ? memoize!(fib)(n - 1) + memoize!(fib)(n - 2) : 1;}
fib(60);

Scheme에서 비슷한 것을 시도 할 수도 있습니다. 런타임에서 발생하기 때문에 여기에서 조회가 해시 대신 선형 적이기 때문에 (그리고 Scheme이기 때문에) 조금 느립니다.

(define (memoize f)
    (let ((table (list)))
        (lambda args
            (cdr
                (or (assoc args table)
                    (let ((entry (cons args (apply f args))))
                        (set! table (cons entry table))
                        entry))))))
(define (fib n)
        (if (<= n 1)
            1
            (+ (fib (1- n))
                (fib (- n 2)))))))
(set! fib (memoize fib))

1
한 줄에 무엇이든 쓸 수있는 APL을 좋아하십니까? 크기는 중요하지 않습니다!
보 퍼슨

@Bo : APL을 사용하지 않았습니다. "크기는 중요하지 않습니다"라는 의미가 무엇인지 잘 모르겠지만 내 코드에 문제가있는 것입니까? 그리고 내가 모르는 다른 언어 (예 : C ++) 로이 작업을 수행하는 방법에 이점이 있습니까? (나는 당신이 언급 한 경우 변수 이름을 약간 편집했습니다.)
Mehrdad

1
@Mehrdad-내 의견은 가장 컴팩트 한 프로그램에 대한 것이 최고의 프로그래밍 언어의 표시가 아니라는 것입니다. 이 경우 단일 문자 연산자로 대부분의 작업을 수행하기 때문에 APL실패 합니다. 유일한 문제는 읽을 수 없다는 것입니다.
보 퍼슨

@Bo : 내가 말했듯이, 나는 APL을 추천하지 않았다. 나는 그것을 본 적이 없다. 크기는 하나의 기준 이었습니다 (C ++로 시도하면 볼 수 있듯이 중요한 기준이지만 ...) 코드에 문제가 있습니까?
Mehrdad

1
@Matt : 코드 함수를 메모 했지만이 코드는 모든 함수를 메모 할 수 있습니다 . 이것들은 전혀 동등하지 않습니다. 실제로 C ++ 0x에서 이와 같은 고차 함수를 작성하려고하면 D보다 훨씬 지루합니다 (아직도 가능하지만 C ++ 03에서는 불가능합니다).
Mehrdad

5

C ++은 다중 패러다임 언어이므로 여러 가지 사고 방식을 지원하려고합니다. 함수형 프로그래밍의 경우처럼 C ++ 기능이 다른 언어의 구현보다 더 어색하거나 덜 유창한 경우가 있습니다.

즉, yieldPython 또는 JavaScript에서 수행하는 기본 C ++ 언어 기능의 머리 꼭대기를 생각할 수는 없습니다 .

또 다른 예는 동시 프로그래밍 입니다. C ++ 0x는 그것에 대해 말할 것이지만 현재 표준은 그렇지 않으며 동시성은 완전히 새로운 사고 방식입니다.

또한 C ++ 프로그래밍 영역을 떠나지 않으면 빠른 개발 (쉘 프로그래밍)조차도 배우지 못할 것입니다.


C ++ 2003을 사용하여 C ++에서 생성기를 만드는 것이 얼마나 어려울 지조차 생각조차 할 수 없습니다. C ++ 2011은 더 쉬워 지지만 여전히 쉽지는 않습니다. C ++, C # 및 Python에서 일상적으로 작업하는 생성기는 C ++에서 가장 놓치게되는 기능입니다 (현재 C ++ 2011에 람다가 추가됨).

나는 이것을 달성 할 것이라는 것을 알고 있지만 C ++에서 생성기를 절대적으로 구현 해야 한다면 ... setjmp및 을 사용해야 longjmp합니다. 나는 그것이 얼마나 깨지는 지 모른다. 그러나 나는 예외가 가장 먼저 갈 것이라고 생각한다. 실례합니다. Modern C ++ Design 을 다시 읽어야 합니다.
Mike DeSimone

@Mike DeSimone, setjmp 및 longjmp를 사용하여 솔루션을 시도하는 방법을 자세히 설명 할 수 있습니까?

1
코 루틴은 펑터에 동형이다.
GManNickG

1
@Xeo, @Mike : xkcd.com/292
Mehrdad

5

코 루틴 은 C ++에 비해 다른 언어의 많은 실질적인 이점을 뒷받침하는 매우 유용한 언어 기능입니다. 기본적으로 추가 스택을 제공하므로 기능을 중단하고 계속할 수 있으므로 필터를 통해 작업 결과를 다른 작업에 쉽게 제공하는 언어에 파이프 라인과 유사한 기능을 제공합니다. 훌륭합니다. Ruby에서는 매우 직관적이고 우아했습니다. 게으른 평가도 이것과 관련이 있습니다.

C ++에없는 강력한 기능은 무엇이든 내부 검사 및 런타임 코드 컴파일 / 실행 / 평가 / 무엇입니까?


코 루틴은 FreeRTOS ( 여기 참조 ) 에서 사용할 수 있으며 C로 구현되어 있습니다. C ++에서 작동하게하려면 무엇이 필요할까요?
Mike DeSimone

코 루틴은 C에서 객체를 에뮬레이트하기위한 불쾌한 해킹입니다. C ++에서 객체는 코드와 데이터를 묶는 데 사용됩니다. 그러나 C에서는 할 수 없습니다. 따라서 코 루틴 스택을 사용하여 데이터를 저장하고 코 루틴 함수를 사용하여 코드를 보유합니다.
MSalters


1
@ Ferruchio : 링크 주셔서 감사합니다 ... Wikipedia 기사에도 몇 가지가 있습니다. @MSalters : 공동 루틴을 "불쾌한 핵"으로 묘사하는 이유는 무엇입니까? 나에게 매우 임의의 관점으로 보인다. 스택을 사용하여 재귀 알고리즘으로도 상태를 저장합니다. FWIW, 코 루틴과 OOP가 같은시기 (1960 년대 초)에 등장했습니다. C의 객체에 대한 해킹은 기괴한 것 같습니다. C ++보다 15 년 전
Tony

4

Lisp와 C ++ 모두에서 컴퓨터 대수 시스템을 구현 한 후에는 언어에 대한 완전한 초보자 였지만 Lisp에서 작업이 훨씬 쉬웠다 고 말할 수 있습니다. 목록에있는 모든 것의 단순한 특성으로 인해 많은 알고리즘이 단순화됩니다. 물론 C ++ 버전은 수십 배 더 빨랐습니다. 그래, lisp 버전을 더 빨리 만들 수는 있었지만 코드는 lispy만큼 좋지 않을 것입니다. 예를 들어 스크립팅은 항상 더 쉬워 질 것입니다. 작업에 적합한 도구를 사용하는 것이 전부입니다.


속도의 차이는 무엇입니까?
quant_dev

1
@quant_dev : 물론 복수의 배수!
매트 엘렌

나는 그것을 실제로 측정하지는 않았지만 큰 O가 다르다는 느낌이 들었습니다. 필자는 원래 C ++ 버전을 기능적 스타일로 작성했으며 새롭고 변경된 것을 만드는 대신 데이터 구조를 수정하도록 가르 칠 때까지 속도 문제가있었습니다. 그러나
그로

2

한 언어가 다른 언어보다 "더 강력하다"고 할 때 무엇을 의미합니까? 언어가 "표현 적"이라고 말할 때 아니면 "부자?" 나는 생각 아니, 정말 상태 전이 - 우리는 시야각이 충분히 좁아 언어 이익 전원이 쉽고 자연의 문제를 설명 할 수 있도록 의미? -그것은 그 견해 안에 있습니다. 그러나 그 언어는 우리의 시야가 넓어 질 때 상당히 덜 강력하고 표현력이 떨어지며 유용하지 않습니다.

언어가 "강력하고"표현이 많을수록 사용이 제한됩니다. 따라서 "강력한"및 "표현 적"은 좁은 유틸리티 도구에 사용하는 잘못된 단어 일 수 있습니다. 어쩌면 "적절한"또는 "추상적 인"이 그러한 것들에 대한 더 나은 단어 일 것입니다.

나는 저수준의 많은 것들을 작성함으로써 프로그래밍을 시작했다 : 인터럽트 루틴을 가진 장치 드라이버; 임베디드 프로그램; 운영 체제 코드. 코드는 하드웨어와 밀접한 관계가 있으며 어셈블리 언어로 모두 작성했습니다. 우리는 어셈블러가 가장 추상적이지 않다고 말하지는 않았지만 어셈블러는 가장 강력하고 표현력이 뛰어난 언어였습니다. 어셈블리 언어로 문제를 표현할 수 있습니다. 어떤 기계로든 내가 원하는 것을 할 수있을만큼 강력합니다.

그리고 나중에 고급 언어에 대한 모든 이해는 어셈블러에 대한 모든 경험으로 인해 발생합니다. 나중에 배운 모든 것은 쉬웠습니다. 왜냐하면 아무리 추상적이더라도 결국에는 하드웨어 자체를 수용해야하기 때문입니다.

더 높고 높은 추상화 수준, 즉 좁고 좁은 시야를 잊고 싶을 수도 있습니다. 나중에 언제든지 선택할 수 있습니다. 며칠 만에 배우는 것은 간단합니다. 내 의견으로는 하드웨어 1 의 언어를 배우고 뼈에 최대한 가까이 접근하는 것이 더 나을 것 입니다.


1 아마도 아주 밀접한 관계가 아니지만, carcdr하드웨어에서 자신의 이름을 : 첫 번째 리스프 실제 감소시킵니다 등록 및 실제 주소 등록을 한 컴퓨터에서 실행. 어때요?


선택은 이중 칼입니다. 우리 모두는 그것을 추구하지만, 그것의 어두운면이 있으며 우리를 불행하게 만듭니다. 세상에 대한 정의 된 시야와 당신이 조작 할 수있는 경계를 정의하는 것이 좋습니다. 사람들은 매우 창조적 인 창조물이며 제한된 도구로 훌륭한 일을 할 수 있습니다. 요약하자면, 저는 프로그래밍 언어가 아니라 어떤 언어로든 노래 할 수있는 재능있는 사람들이 있다고 말하고 있습니다!
차드

"제안하는 것은 창조하는 것이며, 정의하는 것은 파괴하는 것이다." 다른 언어로 생활을 더 편하게 할 수 있다고 생각하면 기분이 좋아 지지만 일단 점프하면 새로운 언어의 사마귀를 처리해야합니다.
Mike DeSimone

2
저는 영어가 어떤 프로그래밍 언어보다 강력하고 표현력이 뛰어나지 만 그 유용성의 한계는 매일 확장되고 있으며 그 유용성은 엄청납니다. 힘과 표현력의 일부는 적절한 추상화 수준에서 의사 소통을 할 수 있고 nedded 때 새로운 추상화 수준을 발명하는 능력에서 비롯됩니다.
molbdnilo

@Mike 다음 새 언어 내에서 이전 언어와의 통신을 처리해야합니다.)
Chad

2

연관 배열

데이터를 처리하는 일반적인 방법은 다음과 같습니다.

  • 입력을 읽고 그로부터 계층 구조를 구성합니다.
  • 해당 구조에 대한 색인 작성 (예 : 다른 순서)
  • 그들의 추출물 (필터링 된 부분)을 생성하고,
  • 값 또는 값 그룹 찾기 (노드)
  • 구조를 다시 정렬합니다 (노드 삭제, 규칙에 따라 하위 요소 추가, 추가, 제거 등).
  • 나무를 통해 스캔하여 인쇄하거나 일부를 저장하십시오.

이를위한 올바른 도구는 연관 배열 입니다.

  • 내가 본 연관 배열에 대한 최상의 언어 지원은 MUMPS입니다 . 연관 배열은 다음과 같습니다. 1. 항상 정렬 됨 2. 동일한 구문을 사용하여 디스크 (소위 데이터베이스)에서 만들 수 있습니다. (부작용 : 데이터베이스로서 매우 강력하며, 프로그래머는 네이티브 btree에 액세스 할 수 있습니다. 최고의 NoSQL 시스템입니다.)
  • 내 두 번째상은 PHP에 간다 . 나는 $ a [] = x 또는 $ a [x] [y] [z] ++ 와 같은 foreach 와 쉬운 구문을 좋아한다 .

JavaScript의 연관 배열 구문이 마음에 들지 않습니다. 왜냐하면 a [x] [y] [z] = 8을 만들 수 없기 때문에 먼저 a [x]a [x] [y] 를 만들어야 합니다 .

좋아, C ++ (및 Java)에는 컨테이너 클래스, Map , Multimap 등 의 훌륭한 포트폴리오가 있지만 스캔하고 싶다면 반복자를 만들어야하며 새로운 심층 요소를 삽입 할 때 모든 상위 레벨 등을 작성해야합니다. 불편합니다.

C ++ (및 Java)에는 사용할 수있는 연관 배열이 없지만 유형이없는 (또는 엄격하지 않은 유형의) 스크립트 언어는 유형이없는 스크립트 언어이기 때문에 컴파일 된 언어를 능가합니다.

면책 조항 : C # 및 기타 .NET 언어에 익숙하지 않습니다 .AFAIK에는 우수한 연관 배열 처리 기능이 있습니다.


1
전체 공개 : MUMPS 모든 사람을 위한 것이 아닙니다 . 인용문 : MUMPS 인 공포에 대해 좀 더“실제적인”예를 제공하기 위해 International Obfuscated C Code Contest, Perl 대시, FORTRAN 및 SNOBOL의 두 가지 중복 측정, 그리고 독립적이고 조정되지 않은 기여에 대한 부분부터 시작하십시오. 수십 명의 의료 연구원들이 있습니다.
Mike DeSimone

1
파이썬에서는 내장 dict타입을 사용할 수 있습니다 (예 : x = {0: 5, 1: "foo", None: 500e3}키나 값이 같은 타입 일 필요는 없습니다). a[x][y][z] = 8언어는 미래를 들여다 보면서 가치를 설정하거나 다른 수준을 만들려고하기 때문에 어려운 일을 시도하는 것은 어렵습니다. 그 표현 a[x][y]자체는 당신에게 말하지 않습니다.
Mike DeSimone

MUMPS는 원래 연관 배열이있는 기본 언어입니다 (디스크에 직접 저장 될 수 있음). 최신 버전에는 절차 확장이 포함되어있어 핵심 PHP와 매우 유사합니다. 기본과 PHP를 두려워하는 사람들은 유행성 이하선염이 무섭지 만 다른 사람들은 그렇지 않습니다. 프로그래머는 그렇지 않습니다. 그리고 그것은 매우 오래된 시스템이며, 한 글자로 된 지시 사항 (전체 이름을 사용할 수도 있음), LR 평가 순서 등과 같은 모든 이상한 것들, 비 이상한 솔루션은 단 하나의 목표가 있습니다 : 최적화 .
ern0

"우리는 시간의 97 % 정도의 작은 효율성을 잊어야한다. 조기 최적화는 모든 악의 근원이다. 그러나 우리는 그 중요한 3 %의 기회를 포기해서는 안된다." - 도널드 크 누스 당신이 묘사 한 것은 이전 버전과의 호환성을 강조하는 레거시 언어처럼 들립니다. 개인적으로 이러한 응용 프로그램에서는 유지 관리 성이 최적화보다 중요하다고 생각하며 비대 수 식과 한 글자로 된 명령이 비생산적인 것처럼 들립니다. 나는 언어가 아닌 고객에게 봉사합니다.
Mike DeSimone

@ 마이크 : 당신이 게시 한 매우 재미있는 링크, 나는 그들을 읽는 동안 좋은 웃음을했다.
shuttle87

2

Java, C \ C ++, Assembly 및 Java Script를 배우지 않습니다. 나는 C ++을 사용하여 생계를 꾸려 나간다.

그러나 어셈블리 프로그래밍과 C 프로그래밍을 더 좋아한다고 말해야합니다. 이것은 대부분 명령형 프로그래밍과 인라인입니다.

프로그래밍 패러다임은 데이터 유형을 분류하는 데 중요하며 강력한 디자인 패턴 및 코드 형식화를 위해 더 높은 프로그래밍 추상 개념을 제공합니다. 어떤 의미에서는 각 패러다임은 기본 하드웨어 계층을 추상화하기위한 패턴 및 모음의 모음이므로 컴퓨터 내부의 EAX 또는 IP에 대해 생각할 필요가 없습니다.

이것에 대한 나의 유일한 문제는 사람들이 기계가 어떻게 작동하고 있는지에 대한 개념과 개념이 이데올로기 및 진행중인 일에 대한 모호한 주장으로 바뀔 수 있다는 것입니다. 이 빵은 프로그래머의 이데올로기 목표에 대한 초록 위에 멋진 추상화가 있습니다.

하루가 끝나면 CPU가 무엇인지, 컴퓨터가 어떻게 작동하는지에 대한 명확한 사고 방식과 경계를 갖는 것이 좋습니다. 모든 CPU는 메모리 안팎으로 데이터를 레지스터로 이동하고 명령을 수행하는 일련의 명령을 실행합니다. 데이터 유형 개념이나 고급 프로그래밍 개념이 없습니다. 데이터 만 이동합니다.

세상에 대한 우리의 시각이 모두 다르기 때문에 프로그래밍 패러다임을 믹스에 추가하면 더욱 복잡해집니다.


2

C ++로만 작성하는 경우 개념화하거나 구현하기 어려운 언어에서 사용하는 강력한 언어 기능 또는 관용구가 있습니까?

C ++로 작성하거나 "생각"했을 때 개념화하기 어려운 다른 언어에서 발견 된 유용한 개념이나 기술이 있습니까?

C ++은 많은 접근 방식을 다루기 어렵게 만듭니다. C ++로 자신을 제한하면 대부분의 프로그래밍이 개념화하기 어렵다고 말할 수 있습니다. 다음은 C ++이 어렵게 만드는 방식으로 훨씬 더 쉽게 해결되는 문제의 예입니다.

등록 할당 및 호출 규칙

많은 사람들이 C ++을 베어 메탈 저수준 언어로 생각하지만 실제로는 그렇지 않습니다. 기계의 중요한 세부 사항을 추상화함으로써 C ++은 레지스터 할당 및 호출 규칙과 같은 실용성을 개념화하기 어렵게 만듭니다.

이와 같은 개념에 대해 배우려면 어셈블리 언어 프로그래밍을 살펴보고 ARM 코드 생성 품질에 대한이 기사를 확인하는 것이 좋습니다 .

런타임 코드 생성

C ++ 만 알고 있다면 템플릿은 메타 프로그래밍의 전부라고 생각할 것입니다. 그렇지 않습니다. 실제로, 이들은 메타 프로그래밍을위한 객관적으로 나쁜 도구입니다. 다른 프로그램을 조작하는 모든 프로그램은 인터프리터, 컴파일러, 컴퓨터 대수 시스템 및 정리 프로 버를 포함한 메타 프로그램입니다. 런타임 코드 생성은이를위한 유용한 기능입니다.

나는 EVAL메타 구현 평가에 대해 배우기 위해 Scheme 구현을 시작하고 노는 것이 좋습니다 .

나무 조작

나무는 어디에나 프로그래밍에 있습니다. 파싱에는 추상 구문 트리가 있습니다. 컴파일러에는 트리 인 IR이 있습니다. 그래픽 및 GUI 프로그래밍에는 장면 트리가 있습니다.

"C ++ 용 엄밀하게 간단한 JSON 파서" 는 484 LOC에 불과하며 C ++에는 매우 작습니다. 이제 60 LOC의 F #으로 무게가 나가는 간단한 JSON 파서 와 비교하십시오 . ML의 대수 데이터 유형과 패턴 일치 (활성 패턴 포함)로 인해 나무를 훨씬 쉽게 조작 할 수 있기 때문에 차이점이 있습니다.

OCaml에서 붉은 검은 나무도 확인하십시오 .

순전히 기능적인 데이터 구조

C ++에서 GC가 부족하면 유용한 접근 방식을 채택하는 것이 사실상 불가능합니다. 순전히 기능적인 데이터 구조가 그러한 도구 중 하나입니다.

예를 들어, OCaml 에서이 47 줄 정규 표현식 매처 를 확인하십시오 . 간결함은 주로 순전히 기능적인 데이터 구조를 광범위하게 사용하기 때문입니다. 특히, 키가 설정된 사전을 사용합니다. stdlib 사전 및 세트는 모두 변경 가능하지만 사전 키를 변경하거나 콜렉션을 손상시킬 수 있기 때문에 C ++에서는 실제로 수행하기가 어렵습니다.

논리 프로그래밍과 실행 취소 버퍼는 순전히 기능적인 데이터 구조가 다른 언어에서는 C ++에서 어려운 작업을 만드는 다른 실용적인 예입니다.

테일 전화

C ++은 테일 호출을 보장하지는 않지만 소멸자는 테일 위치에서 호출을 방해하기 때문에 RAII와 근본적으로 상충됩니다. 테일 호출을 사용하면 제한된 양의 스택 공간 만 사용하여 무한한 수의 함수 호출을 수행 할 수 있습니다. 이것은 확장 가능한 상태 머신을 포함하여 상태 머신을 구현하는 데 유용하며, 많은 어색한 상황에서 훌륭한 "감옥 탈옥"카드입니다.

예를 들어, 금융 업계의 F #에 대한 메모와 함께 연속 전달 스타일을 사용하여 0-1 배낭 문제의 구현을 확인하십시오 . 꼬리 호출이있을 때 연속 전달 스타일은 확실한 솔루션 일 수 있지만 C ++은 다루기 어렵습니다.

동시성

또 다른 명백한 예는 동시 프로그래밍입니다. 비록 이것이 C ++에서 가능하지만 Erlang, Scala 및 F #과 같은 언어에서 볼 수있는 것과 같이 순차적 프로세스를 통신하는 다른 도구와 비교할 때 오류가 발생하기 쉽습니다.


1

이것은 오래된 질문이지만 아무도 언급하지 않았기 때문에 목록 이해력을 추가 할 것입니다. Fizz-Buzz 문제를 해결하는 Haskell 또는 Python에서 하나의 라이너를 작성하는 것은 쉽습니다. C ++에서 해보십시오.

C ++는 C ++ 11을 사용하여 현대화에 막대한 변화를 가져 왔지만이를 "현대"언어라고 부르는 것은 약간의 확장입니다. "현대"가 "이전 천년이 아닌"을 의미하는 한, C ++ 17 (아직 출시되지 않은)은 현대 표준에 따라 더 많은 움직임을 보이고 있습니다.

파이썬에서 한 줄로 작성하고 Guido의 79 문자 줄 길이 제한을 준수하는 가장 간단한 이해조차도 C ++로 변환 할 때 많은 코드 줄이되고 C ++ 코드 줄 중 일부는 다소 복잡합니다.


잘 참고 : 내 프로그래밍의 대부분은 C ++입니다. 나는 언어를 좋아한다.
David Hammen

나는 Ranges Proposal이 이것을 해결해야한다고 생각 했습니까? (C ++ 17조차도 아닙니다.)
Martin Ba

2
"근대성으로의 대규모 이동": 현재의 천년기에 발명 된 C ++ 11이 제공하는 "현대"기능은 무엇입니까?
조르지오

@MartinBa- "범위"제안에 대한 나의 이해는 작업하기 쉽고 오류가 적은 반복자를 대체한다는 것입니다. 나는 그들이 목록 이해만큼 흥미로운 것을 허용한다는 제안을 보지 못했습니다.
Jules

2
@Giorgio- 현재 밀레니엄에서 현재 인기있는 언어 의 어떤 기능 이 발명 되었습니까?
Jules

0

사용자 정의 클래스의 사용자 정의 멤버 함수 인 콜백을 호출하는 컴파일 된 라이브러리입니다.


이것은 Objective-C에서 가능하며 사용자 인터페이스 프로그래밍을 쉽게 해줍니다. "누르면이 객체에 대해이 메소드를 호출하십시오"라는 단추를 말할 수 있습니다. 그러면 단추가 그렇게됩니다. 원하는 콜백에 메소드 이름을 자유롭게 사용할 수 있습니다. 라이브러리 코드에 고정되지 않으며, 어댑터를 상속받지 않아도 컴파일러가 컴파일 타임에 호출을 해결하려고하지 않습니다. 마찬가지로 두 객체에 동일한 객체의 두 가지 다른 메소드를 호출하도록 지시 할 수 있습니다.

다른 언어로 콜백을 정의하는 비슷한 유연한 방법을 아직 보지 못했습니다 (그러나 그것에 대해 듣고 싶습니다.). C ++에서 가장 가까운 것은 아마도 필요한 호출을 수행하는 람다 함수를 전달하는 것입니다.이 함수는 라이브러리 코드를 다시 템플릿으로 제한합니다.

Objective-C 의이 기능은 언어가 모든 유형의 객체 / 함수 / 중요한 개념-언어가 포함 된 언어를 자유롭게 전달할 수있는 능력 과 함께 저장하는 힘과 함께 변수. 모든 유형의 개념을 정의하지만 사용 가능한 모든 종류의 변수에 개념을 저장하는 수단을 제공하지 않는 언어의 요점은 중요한 걸림돌이며 아마도 추악한 원인이 될 수 있습니다. 중복 된 코드. 불행히도 바로크 프로그래밍 언어는 다음과 같은 여러 가지 점을 나타냅니다.

  • C ++에서는 VLA 유형을 적거나 포인터를 저장할 수 없습니다. 이는 동적 크기의 실제 다차원 배열 (C99 이후 C에서 사용 가능)을 효과적으로 금지합니다.

  • C ++에서는 람다 유형을 기록 할 수 없습니다. 당신은 그것을 typedef 할 수 없습니다. 따라서 람다를 통과하거나 객체에 참조를 저장하는 방법이 없습니다. Lambda 함수는 템플릿에만 전달할 수 있습니다.

  • 포트란에서는 이름 목록의 유형을 기록 할 수 없습니다. 이름 목록을 어떤 종류의 루틴으로 전달할 수단은 없습니다. 따라서 두 개의 서로 다른 이름 목록을 처리 할 수있는 복잡한 알고리즘이 있다면 운이 좋지 않습니다. 알고리즘을 한 번만 작성하고 관련 이름 목록을 전달할 수는 없습니다.

이것들은 몇 가지 예일 뿐이지 만 공통점이 있습니다. 처음으로 그러한 제한을 볼 때마다 금지 된 일을하는 것이 미친 아이디어처럼 보이기 때문에 일반적으로 신경 쓰지 않을 것입니다. 그러나 해당 언어로 진지한 프로그래밍을 수행하면 결국이 정확한 제한이 실제로 귀찮은 지점이됩니다.


1
I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!) 방금 설명한 것은 이벤트 중심 UI 코드가 Delphi에서 작동하는 방식과 정확히 같습니다. (그리고 델파이의 영향을 많이받은 .NET WinForms에서)
Mason Wheeler

2
"C ++에서는 VLA의 유형을 기록 할 수 없습니다"[...] – C ++에서는 C99 스타일 VLA가 필요하지 std::vector않습니다. 스택 할당을 사용하지 않아 효율성이 떨어지지 만 VLA와 기능적으로 동형이므로 "블 러브"유형 문제로 간주되지 않습니다. C ++ 프로그래머는 작동 방식을보고 "아 예"라고 말할 수 있습니다. C는 C ++보다 더 효율적입니다. "
Jules

2
"C ++에서는 람다의 유형을 기록 할 수 없습니다. 심지어 typedef를 작성할 수도 없습니다. 따라서 람다를 전달하거나 객체에 참조를 저장할 수있는 방법이 없습니다 std::function."
Jules

3
"저는 다른 언어로 콜백을 정의하는 비슷한 유연한 방법을 아직 보지 못했습니다 (물론 이에 대해 매우 관심이 있습니다!)."-Java에서는 글을 쓸 수 object::method있으며 인스턴스로 변환됩니다. 수신 코드가 기대하는 인터페이스 C #에는 대리인이 있습니다. 모든 객체 기능 언어에는 기본적으로 두 패러다임의 단면이 있기 때문에이 기능이 있습니다.
Jules

@Jules 당신의 주장은 Blub-Paradox에 관한 것입니다. 숙련 된 C ++ 프로그래머로서, 당신은 이것들을 한계로 보지 않습니다. 그러나 제한 사항이며 C99와 같은 다른 언어가 이러한 특정 점에서 더 강력합니다. 마지막으로 : 많은 언어로 가능한 해결 방법이 있지만 다른 클래스에 메소드 이름을 전달하고 제공하는 객체에서 호출 할 수있는 방법을 모르겠습니다.
cmaster
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.