함수형 프로그래밍 제안자는 Code Complete에서이 문장에 어떻게 대답합니까?


30

Steve McConnell은 두 번째 버전의 839 페이지에서 프로그래머가 대규모 프로그램에서 "복잡성을 극복 할 수있는"모든 방법을 논의하고 있습니다. 그의 조언은이 진술로 끝납니다.

"객체 지향 프로그래밍은 알고리즘과 데이터에 동시에 적용되는 추상화 수준을 제공합니다. 이는 기능 분해만으로는 제공하지 않는 일종의 추상화입니다."

"복잡성을 줄이는 것이 효과적인 프로그래머가되기위한 가장 중요한 열쇠"(동일한 페이지)라는 결론과 함께, 이것은 함수형 프로그래밍에있어 거의 도전적인 것으로 보인다.

FP와 OO 사이의 논쟁은 종종 동시성 또는 병렬화의 문제에서 파생되는 복잡성 문제에 대한 FP 지지자에 의해 결정됩니다. 그러나 동시성은 소프트웨어 프로그래머가 정복해야 할 복잡한 종류는 아닙니다. 아마도 한 종류의 복잡성을 줄이는 데 초점을 맞추면 다른 차원에서는 복잡성이 크게 증가하여 많은 경우 이익이 비용이 들지 않습니다.

FP와 OO의 비교 조건을 동시성 또는 재사용 성과 같은 특정 문제에서 글로벌 복잡성 관리로 전환하면 그 논쟁은 어떻게 보일까요?

편집하다

내가 강조하고 싶었던 대조는 OO가 데이터와 알고리즘의 복잡성을 피하고 요약하는 것처럼 보이지만, 기능적 프로그래밍은 데이터 구조의 구현 세부 사항을 프로그램 전체에 더“노출”하게 남겨 두는 것 같습니다.

참조, 예를 들어, 스튜어트 Halloway (A Clojure의 FP의 지지자) 여기 의 "데이터 유형의 오버 사양" "관용적 OO 스타일의 부정적인 결과"라고 말하는 간단한 벡터 등의 주소록을 개념화 또는 그 대신 풍부한 OO 객체의지도 선호 추가 (벡터가 아닌 & 비맵과 같은) 속성 및 메서드 또한 OO 및 도메인 기반 디자인 제안자는 주소록을 벡터 또는 맵으로 노출하면 캡슐화 된 데이터를 도메인의 관점에서 무관하거나 위험한 방법에 노출 시킨다고 말할 수 있습니다.


3
질문이 무질서하게 짜여져 있음에도 불구하고 +1은 좋은 질문입니다.
mattnz

16
많은 사람들이 답변에서 언급했듯이, 기능적 분해와 기능적 프로그래밍은 두 가지 다른 짐승입니다. 따라서 "이것은 함수형 프로그래밍에 많은 어려움을 겪는 것 같습니다"라는 결론은 명백히 잘못되었습니다.
Fabio Fracassi

5
현대의 기능적 데이터 유형 시스템 및 고차 1 급 모듈에 대한 McConnel의 지식은 다소 고르지 않습니다. 그의 말은 우리가 첫 번째 클래스 모듈과 펑터 (SML 참조), 타입 클래스 (하스켈 참조)를 가지고 있기 때문에 전혀 말이되지 않습니다. 이것은 OO 사고 방식이 존경받는 디자인 방법론보다 종교가되는 방법의 또 다른 예일뿐입니다. 그런데, 동시성에 대해이 부분을 어디서 얻었습니까? 기능 프로그래머 대부분은 병렬 처리를 전혀 신경 쓰지 않습니다.
SK-logic

6
@ SK-logic 모든 McConnell은 "기능적 분해 만"이 OOP와 동일한 추상화 수단을 제공하지 않는다고 말했는데, 이는 나에게 꽤 안전한 진술로 보인다. 그는 FP 언어가 OOP만큼 강력한 추상화 수단을 가지고 있지 않다고 말합니다. 실제로 그는 FP 언어를 전혀 언급하지 않았습니다. 그것은 OP의 해석 일뿐입니다.
sepp2k

2
@ sepp2k, 알겠습니다. 그러나 여전히 매우 복잡하고 계층화 된 데이터 구조 및 처리 추상화 시스템은 모듈 동작을 시뮬레이션하여 거의 순수한 람다 미적분학에 대한 기능적 분해 외에 아무것도 구축 할 수 없습니다. OO 추상화가 전혀 필요하지 않습니다.
SK-logic

답변:


13

이 책은 20 년 넘게 쓰여졌다는 것을 명심하십시오. 오늘날의 전문 프로그래머에게는 FP가 존재하지 않았습니다. 전적으로 학계 및 연구원의 영역에있었습니다.

우리는 작업의 적절한 맥락에서 "기능적 분해"를 구성해야합니다. 저자는 함수형 프로그래밍을 언급하지 않습니다. 우리는 이것을 "구조화 된 프로그래밍"과 그 GOTO이전 의 채워진 엉망으로 묶어야합니다. 참조 지점이 함수가없는 오래된 FORTRAN / COBOL / BASIC 인 경우 (아마 운이 좋으면 단일 수준의 GOSUB를 얻을 수 있음) 모든 변수가 전역 변수이므로 프로그램을 분석 할 수 있습니다 기능의 층으로 들어가는 것이 큰 혜택입니다.

OOP는 이런 종류의 '기능적 분해'에 대한 추가 개선입니다. 함수에 명령어를 함께 묶을 수있을뿐만 아니라 관련 함수를 작업중인 데이터와 그룹화 할 수 있습니다 . 결과적으로 코드베이스 주위를 쫓아 데이터에서 다른 것이 작동하는 것을 찾지 않고도 (이상적으로)보고 이해할 수있는 명확하게 정의 된 코드가 생성됩니다.


27

함수형 프로그래밍 지지자들은 대부분의 FP 언어가 "함수 분해 만"보다 더 많은 추상화 수단을 제공하고 실제로 객체 지향 언어와 비슷한 수준의 추상화를 허용한다고 주장합니다. 예를 들어, 하스켈의 타입 클래스 나 ML의 상위 모듈을 추상화 수단으로 인용 할 수 있습니다. 따라서 진술 (기능 프로그래밍이 아닌 객체 지향 대 절차 프로그래밍에 관한 것임)은 적용되지 않습니다.

또한 FP와 OOP는 직교 개념이며 상호 배타적이지 않다는 점을 지적해야합니다. 따라서 서로 비교하는 것은 의미가 없습니다. "imperative OOP"(예 : Java)와 "functional OOP"(예 : Scala)를 잘 비교할 수 있지만 인용 한 내용은 해당 비교에 적용되지 않습니다.


10
+1 "함수 분해"! = "함수 프로그래밍". 첫 번째는 상속, 캡슐화 및 다형성이없는 바닐라 데이터 구조를 사용하는 클래식 순차 코딩에 의존합니다. 두 번째는 람다 미적분학을 사용하여 솔루션을 표현합니다. 완전히 다른 두 가지.
이진 걱정

4
사과하지만 "절차 프로그래밍"이라는 문구는 완고하게 생각하기를 거부했다. "기능 분해"는 함수형 프로그래밍보다 절차 적 프로그래밍을 훨씬 더 잘 나타냅니다.
이진 걱정

네 말이 맞아. Functional Programming은 동일한 단순한 데이터 구조 (목록, 트리, 맵)에서 반복적으로 작동하는 재사용 가능한 함수를 선호한다고 가정하고 실제로 이것이 OO를 통한 판매 포인트라고 주장합니다. Stuart Halloway (Clojure FP 지지자)를 참조하십시오. 여기에서 "데이터 유형의 과잉 지정"은 "관용적 OO 스타일의 부정적인 결과"이며 주소록을 다른 OO 객체가 아닌 풍부한 OO 객체 대신 벡터 또는 맵으로 개념화하는 것을 선호합니다 -벡터 및 비맵과 같은 속성 및 메서드
dan

Stuart Halloway 인용구 링크 : thinkrelevance.com/blog/2009/08/12/…
dan

2
@dan 그것은 동적으로 유형이 지정된 언어 Clojure (나는 Clojure를 사용하지 않는다)에서 어떻게 수행 될지 모르지만, 결론적으로 말하면 위험하다고 생각합니다. 일반적으로 FP에서 수행 된 방식입니다. 예를 들어, Haskell 사람들은 추상 유형과 정보 숨기기에 매우 큰 것 같습니다 (아마도 Java 사람들만큼 많지는 않습니다).
sepp2k

7

기능 프로그래밍이 복잡성을 관리하는 데 매우 도움이된다는 것을 알게되었습니다. 복잡성을 다른 방식으로 생각하는 경향이 있지만, OOP 의미의 캡슐화가 아닌 다른 수준에서 불변의 데이터에 작용하는 함수로 정의하는 경향이 있습니다.

예를 들어, 최근 Clojure에서 게임을 작성했으며 게임의 전체 상태는 단일 불변 데이터 구조로 정의되었습니다.

(def starting-game-state {:map ....
                          :player ....
                          :weather ....
                          :other-stuff ....}

그리고 메인 게임 루프는 루프에서 게임 상태에 순수한 함수를 적용하는 것으로 정의 할 수 있습니다.

 (loop [initial-state starting-game-state]
   (let [user-input (get-user-input)
         game-state (update-game initial-state user-input)]
     (draw-screen game-state)
     (if-not (game-ended? game-state) (recur game-state))))

라는 주요 기능은 update-game이전 게임 상태와 일부 사용자 입력이 주어지면 시뮬레이션 단계를 실행하고 새 게임 상태를 반환합니다.

복잡성은 어디에 있습니까? 내 견해로는 꽤 잘 관리되었습니다.

  • 확실히 업데이트 게임 기능은 많은 작업을 수행하지만 실제로는 다른 기능을 구성하여 구성되므로 실제로는 매우 간단합니다. 몇 단계 아래로 내려가도 "맵 타일에 객체 추가"와 같은 기능을 수행하는 기능은 여전히 ​​간단합니다.
  • 확실히 게임 상태는 큰 데이터 구조입니다. 그러나 다시 한 번 더 낮은 수준의 데이터 구조를 구성하여 구축되었습니다. 또한 메소드가 내장되어 있거나 클래스 정의가 필요하지 않고 "순수 데이터"이므로 (원하는 경우 매우 효율적인 불변 JSON 객체로 생각할 수 있음) 상용구가 거의 없습니다.

OOP는 또한 캡슐화를 통해 복잡성을 관리 할 수 ​​있지만, 이것을 OOP와 비교하면 기능은 몇 가지 큰 장점에 접근합니다.

  • 게임 상태 데이터 구조는 변경할 수 없으므로 많은 처리를 쉽게 병렬로 수행 할 수 있습니다. 예를 들어, 게임 로직과 다른 스레드에서 드로우 스크린을 호출하는 렌더링은 안전합니다. 서로 영향을 미치거나 일관성이없는 상태를 볼 수 없습니다. 큰 가변 객체 그래프로는 놀라 울 정도로 어렵습니다 .......
  • 언제든지 게임 상태의 스냅 샷을 만들 수 있습니다. Clojure의 지속적인 데이터 구조 덕분에 대부분의 데이터가 공유되므로 사본은 거의 메모리를 차지하지 않습니다. AI가 다른 움직임을 평가하는 데 도움이되도록 "미래 예측"을 위해 업데이트 게임을 실행할 수도 있습니다.
  • 엄격한 계급 계층 구조를 정의하는 것과 같이 OOP 패러다임에 맞추기 위해 어려운 절충점을 만들 필요는 없었습니다. 이러한 의미에서 기능적 데이터 구조는 유연한 프로토 타입 기반 시스템과 유사하게 작동합니다.

마지막으로, 기능적 언어와 OOP 언어의 복잡성을 관리하는 방법에 대한 더 많은 통찰력에 관심이있는 사람들을 위해 Rich Hickey의 기조 연설 Simple Made Easy ( Strange Loop 기술 컨퍼런스 에서 촬영) 비디오를 강력히 추천합니다.


2
게임이 강제 불변성의 "장점"을 보여줄 수있는 최악의 예 중 하나라고 생각합니다. 게임에서 상황이 계속 움직이고 있기 때문에 항상 게임 상태를 다시 만들어야합니다. 그리고 모든 것이 불변 인 경우, 게임 상태를 재 구축해야 할뿐만 아니라 그래프에 대한 참조를 보유하거나 그에 대한 참조를 보유하는 그래프의 모든 것을 재순환해야합니다. 30 + FPS에서 프로그램, 수많은 GC 이탈로 부팅! 좋은 성능을 얻을 수있는 방법은 없습니다.
Mason Wheeler

7
물론 게임은 불변성에 어려움을 겪습니다. 그것이 여전히 작동한다는 것을 보여주기 위해 선택한 이유입니다! 그러나 영구적 인 데이터 구조가 할 수있는 일에 놀랄 것입니다. 대부분의 게임 상태는 재건 될 필요가 없으며 변경되는 것만 필요합니다. 그리고 약간의 오버 헤드가 있지만 작은 상수 요인 일뿐입니다. 코어가 충분하면 싱글 스레드 C ++ 게임 엔진을 이길 것입니다 .....
mikera

3
@Mason 휠러 : 사실, 이다 사실상 동일한 얻을 수있는 모든 훨씬 GC없는 불변의 객체와 성능, (돌연변이와 좋은 등). Clojure의 속임수는 지속적인 데이터 구조를 사용하는 것입니다 . 프로그래머에게는 불변이지만 실제로는 변할 수 있습니다. 두 세계의 최고.
Joonas Pulakka

4
@quant_dev 더 많은 코어가 더 나은 코어보다 저렴합니다 ... escapistmagazine.com/news/view/…
deworde

6
@quant_dev-변명은 아닙니다. 수학적으로나 건축 적 사실이기 때문에 코어 수와 거의 선형으로 성능을 확장하여 보완 할 수 있다면 일정한 오버 헤드가 발생하는 것이 좋습니다. 기능적 언어가 궁극적으로 우수한 성능을 제공하는 이유는 단일 코어 성능을 위해 라인의 끝에 왔으며 앞으로 동시성과 병렬성에 관한 것이기 때문입니다. 기능적 접근 방식 (특히 불변성)이이 작업을 수행하는 데 중요합니다.
mikera

3

"객체 지향 프로그래밍은 알고리즘과 데이터에 동시에 적용되는 추상화 수준을 제공합니다. 기능 분해만으로는 제공하지 않는 일종의 추상화입니다."

함수 분해 만으로는 어떤 종류의 알고리즘이나 프로그램도 만들 수 없습니다. 데이터도 표현해야합니다. 위의 진술은 기능적 경우의 "데이터"가 가장 기초적인 종류, 즉 기호 목록 만 있고 다른 것은 없다고 암시 적으로 가정한다고 생각합니다. 그러한 언어로 프로그래밍하는 것은 그리 편리하지 않습니다. 그러나 Clojure와 같은 새롭고 현대적인 기능적 (또는 다중 패러다임) 언어는 목록뿐만 아니라 문자열, 벡터, 맵 및 세트, 레코드, 구조체 및 객체와 같은 풍부한 데이터 구조를 제공합니다. -메타 데이터와 다형성.

OO 추상화의 실질적인 성공은 논쟁의 여지가 없습니다. 그러나 마지막 단어입니까? 당신이 쓴 것처럼 동시성 문제는 이미 큰 고통이며 고전적인 OO에는 동시성에 대한 아이디어가 전혀 없습니다. 결과적으로 동시성 처리를위한 사실상의 OO 솔루션은 단순히 겹친 덕트 테이프입니다. 아마도 많은 세계를 최대한 활용할 수있을 것입니다. 그것이 현대의 멀티 패러다임 언어가 추구하는 것입니다.


1
어딘가에서 "OO에서 큰, FP에서 작은"이라는 문구를 들었습니다. Michael Feathers가 인용 한 것 같습니다. 즉, FP는 큰 프로그램의 특정 부분에 적합 할 수 있지만 일반적으로 OO 여야합니다.
dan

또한 모든 것에 대해 Clojure를 사용하는 대신 더 전통적인 OO 구문으로 더 명확하게 표현 된 것, 더 깨끗한 데이터 처리 비트에 Clojure를 사용하고 다른 비트에 Java 또는 다른 OO 언어를 사용하는 방법은 어떻습니까? 프로그램의 모든 부분에 대해 동일한 언어로 다중 패러다임 프로그래밍 대신 폴리 글 로트 프로그래밍. (대부분의 웹 응용 프로그램이 서로 다른 계층에 대해 SQL과 OO를 사용하는 방식과 비슷합니다.)?
dan

@dan : 작업에 가장 적합한 도구를 사용하십시오. 폴리 글 로트 프로그래밍에서 결정적인 요소는 언어 간의 편리한 통신이며 Clojure와 Java는 더 잘 어울리지 않습니다 . 나는 가장 실질적인 Clojure 프로그램이 여기저기서 JDK의 표준 Java 라이브러리 중 적어도 일부를 사용한다고 생각합니다.
Joonas Pulakka

2

가변 상태는 프로그래밍 및 소프트웨어 / 시스템 설계와 관련된 대부분의 복잡성과 문제의 근본입니다.

OO는 변경 가능한 상태를 수용합니다. FP는 변경 가능한 상태를 싫어합니다.

OO와 FP 모두 용도와 스위트 스팟이 있습니다. 현명하게 선택해. 그리고 속담을 기억하십시오. "마감은 가난한 사람의 대상입니다. 물건은 가난한 사람의 폐쇄입니다."


3
귀하의 개설 주장이 사실인지 잘 모르겠습니다. 복잡성의 "가장"의 뿌리? 내가 보거나 보았던 프로그래밍에서 문제는 추상화가 부족하고 코드를 통해 세부 사항이 지나치게 많기 때문에 변경 가능한 상태가 아닙니다.
dan

1
@ Dan : 흥미 롭습니다. 나는 실제로 많은 반대를 보았습니다. 문제는 추상화의 과도한 사용으로 인해 발생하므로 실제로 진행되고있는 세부 사항을 이해하고 필요할 때 수정하는 것이 어렵습니다.
메이슨 휠러

1

함수형 프로그래밍에는 개체가있을 수 있지만 이러한 개체는 변경할 수없는 경향이 있습니다. 그런 다음 순수한 기능 (부작용이없는 기능)은 해당 데이터 구조에서 작동합니다. 객체 지향 프로그래밍 언어로 불변의 객체를 만들 수는 있지만 그렇게하도록 설계되지 않았으므로 사용 방식이 아닙니다. 이로 인해 객체 지향 프로그램에 대해 추론하기가 어렵습니다.

아주 간단한 예를 들어 보자. Oracle이 Java Strings에 역 방법이 필요하다고 결정하고 다음 코드를 작성했다고 가정 해 봅시다.

String x = "abc";
StringBuffer y = new StringBuffer(x);
y.reverse();
x.reverse();
x.toString().equals(y.toString());

마지막 줄은 무엇을 평가합니까? 이것이 거짓으로 평가됨을 알기 위해서는 String 클래스에 대한 특별한 지식이 필요합니다.

내 자신의 클래스 WuHoString을 만든 경우 어떻게

String x = "abc";
WuHoString y = new WuHoString(x);
y.reverse();
x.reverse();
x.toString().equals(y.toString())

마지막 줄이 무엇을 평가하는지 아는 것은 불가능합니다.

함수형 프로그래밍 스타일에서는 다음과 같이 작성됩니다.

String x;
equals(toString(reverse(x)), toString(reverse(WuHoString(x))))

그리고 사실이어야합니다.

가장 기본적인 클래스 중 하나의 함수 하나가 추론하기가 어려우면 변경 가능한 객체에 대한 아이디어를 도입하여 복잡성을 증가 또는 감소 시켰는지 궁금합니다.

분명히 객체 지향적 구성 요소와 기능적 의미와 둘 다 갖는 의미에 대한 모든 종류의 정의가 있습니다. 나에게 당신은 일급 함수와 같은 것이 없지만 다른 언어로 만들어진 언어로 "기능적 프로그래밍 스타일"을 가질 수 있습니다.


3
OO 언어는 변경할 수없는 객체를 위해 만들어진 것이 아니라 나중에 문자열 (Java를 포함한 대부분의 OO 언어에서는 변경할 수없는)을 사용하는 예제를 사용하는 것이 재미 있습니다. 또한 불변 객체에 중점을 둔 OO (또는 다중 패러다임) 언어가 있음을 지적해야합니다 (예 : Scala).
sepp2k

@ sepp2k : 익숙해 지십시오. FP 옹호자들은 항상 실제 코딩과 관련이없는 기괴하고 고안된 예를 피하고 있습니다. 불변 강제 시행과 같은 핵심 FP 개념을보기 좋게 만드는 유일한 방법입니다.
메이슨 휠러

1
@Mason : 응? 불변성을보기 좋게 만드는 가장 좋은 방법은 "Java (및 C #, python 등)가 불변 문자열을 사용하고 훌륭하게 작동한다"고 말하는 것입니까?
sepp2k

1
@ sepp2k : 불변 문자열이 그렇게 훌륭하게 작동하면 왜 StringBuilder / StringBuffer 스타일 클래스가 계속 나타 납니까? 그것은 당신의 방식으로 추상화 추상화 반전의 또 다른 예일뿐입니다.
메이슨 휠러

2
많은 객체 지향 언어를 사용하면 불변의 객체를 만들 수 있습니다. 그러나 메소드를 클래스에 묶는 개념은 실제로 내 관점에서 그것을 낙담시킵니다. String 예제는 실제로 고안된 예제가 아닙니다. Java에서 mehtod를 호출 할 때마다 매개 변수가 해당 함수 내에서 변경되는지 여부를 알 수 있습니다.
WuHo1

0

대부분의 경우 클래식 OOP 추상화는 동시성 복잡성을 다루지 않는다고 생각합니다. 따라서 OOP (원래의 의미로)는 FP를 배제하지 않으므로 스칼라와 같은 것을 볼 수 있습니다.


0

대답은 언어에 따라 다릅니다. 예를 들어, 리스프는 코드 데이터 라는 점에서 정말 깔끔 합니다. 작성한 알고리즘은 실제로 리스프 목록 일뿐입니다! 프로그램을 작성하는 것과 같은 방식으로 데이터를 저장합니다. 이 추상화는 동시에 OOP보다 단순하고 철저하며 일부 깔끔한 작업을 수행 할 수 있습니다 (매크로 확인).

Haskell (그리고 비슷한 언어)은 완전히 다른 대답을 가지고 있습니다 : 대수 데이터 유형. 대수 데이터 형식은 C구조체와 비슷하지만 더 많은 옵션이 있습니다. 이러한 데이터 유형은 데이터를 모델링하는 데 필요한 추상화를 제공합니다. 함수는 알고리즘을 모델링하는 데 필요한 추상화를 제공합니다. 타입 클래스 및 기타 고급 기능은 둘 다에 대해 더 높은 수준의 추상화를 제공합니다.

예를 들어, 저는 재미있게 TPL이라는 프로그래밍 언어로 작업하고 있습니다. 대수 데이터 형식은 만들기 정말 쉽게 값을 나타냅니다 :

data TPLValue = Null
              | Number Integer
              | String String
              | List [TPLValue]
              | Function [TPLValue] TPLValue
              -- There's more in the real code...

이것이 매우 시각적으로 말하면 TPLValue (내 언어의 모든 값) 는 값 또는 값 목록 (매개 변수) 및 최종 값 (본문)과 함께 Null또는 a Number가 될 수 있다는 것입니다 ).IntegerFunction

다음으로 형식 클래스를 사용하여 일반적인 동작을 인코딩 할 수 있습니다. 예를 들어, TPLValue인스턴스를 만들면 인스턴스를 Show문자열로 변환 할 수 있습니다.

또한 특정 유형 (자체 구현하지 않은 유형 포함)의 동작을 지정해야 할 때 고유 한 유형 클래스를 사용할 수 있습니다. 예를 들어, a Extractable를 사용 TPLValue하고 적절한 정상 값을 반환하는 함수를 작성할 수 있는 유형 클래스가 있습니다 . 따라서 extract개종자 수 NumberInteger또는 StringA와이 String긴만큼 IntegerString의 인스턴스입니다 Extractable.

마지막으로 내 프로그램의 주요 논리는 evaland과 같은 여러 기능에 apply있습니다. 이것들은 실제로 핵심입니다. 그것들은 상태와 오류를 처리 할뿐만 아니라 TPLValue더 많이 가져 와서 더 많이 TPLValue만듭니다.

전반적으로, Haskell 코드에서 사용하는 추상화는 실제로 OOP 언어에서 사용했던 것보다 훨씬 강력합니다.


그래, 꼭 사랑 eval. "이봐, 날 봐! 나만의 보안 허점을 쓸 필요가 없습니다. 프로그래밍 언어에 임의의 코드 실행 취약점이 내장되어 있습니다!" 코드로 데이터를 병합하는 것이 가장 인기있는 두 가지 보안 취약점 클래스 중 하나의 근본 원인입니다. SQL 주입 공격으로 인해 누군가가 해킹당하는 것을 볼 때마다 (다른 많은 것들 중에서) 일부 프로그래머는 데이터를 코드에서 올바르게 분리하는 방법을 모르기 때문입니다.
메이슨 휠러

evalLisp의 구조에 크게 의존하지 않습니다 eval. JavaScript 및 Python과 같은 언어로 사용할 수 있습니다 . 진정한 힘은 기본적으로 데이터와 같은 프로그램에서 작동하고 다른 프로그램을 출력하는 프로그램 인 매크로 작성에 있습니다. 이것은 언어를 매우 유연하게 만들고 강력한 추상화를 쉽게 만듭니다.
Tikhon Jelvis

3
예, "매크로가 대단하다"는 말을 여러 번 들었습니다. 그러나 나는 1) 실용적이고 실제 코드에서 실제로해야 할 일을하는 Lisp 매크로의 실제 예를 본 적이 없으며 2) 함수를 지원하는 모든 언어에서 쉽게 달성 할 수 없습니다.
메이슨 휠러

1
@MasonWheeler 단락 and. 단락 or. let. let-rec. cond. defn. 이 중 어느 것도 적용 순서 언어의 함수로 구현할 수 없습니다. for(목록 이해력). dotimes. doto.

1
@ MatFenwick : 좋아, 나는 위의 두 가지에 세 번째 요점을 추가 했어야합니다. 3) 제정신 프로그래밍 언어에 이미 내장 되어 있지 않습니다 . 그게 내가 유일하게 볼 수있는 유일하게 유용한 매크로 예제이기 때문에 "이봐, 내 언어는 너무 유연해서 내 단락을 구현할 수있어 and!" "저는 저를 쳐다 봐요. 언어가 너무 무너져서 단락이되지 않아서 모든 것을and 위해 바퀴를 다시 만들어야합니다 !"
메이슨 휠러

0

인용 된 문장은 내가 볼 수있는 한 더 이상 유효하지 않습니다.

현대 OO 언어는 종류가 *가 아닌 유형, 즉 더 높은 유형의 유형을 알 수없는 유형에 대해서는 추상화 할 수 없습니다. 그들의 타입 시스템은 "Int 요소를 가진 일부 컨테이너, 그 요소에 함수를 맵핑 할 수있는 컨테이너"라는 아이디어를 표현할 수 없습니다.

따라서 Haskells와 같은 기본 기능

fmap :: Functor f => (a -> b) -> f a -> f b 

예를 들어 적어도 안전한 형식으로는 Java *로 쉽게 작성할 수 없습니다. 따라서 기본 기능을 얻으려면 보일러 플레이트를 많이 작성해야합니다.

  1. 리스트의 요소에 간단한 함수를 적용하는 방법
  2. 배열의 요소에 동일한 간단한 함수를 적용하는 방법
  3. 해시 값에 동일한 간단한 함수를 적용하는 방법
  4. .... 세트
  5. .... 나무
  6. ... 10. 같은 단위 테스트

그럼에도 불구하고이 다섯 가지 방법은 기본적으로 동일한 코드입니다. 반대로 하스켈에서는 다음이 필요합니다.

  1. 목록, 배열, 맵, 세트 및 트리에 대한 Functor 인스턴스 (대부분 사전 정의되거나 컴파일러에 의해 자동으로 파생 될 수 있음)
  2. 간단한 기능

이것은 Java 8에서는 변경되지 않을 것입니다 (함수를 더 쉽게 적용 할 수 있지만 정확하게 위의 문제가 구체화 될 것입니다. 더 높은 종류의 유형이 어떤 것인지 이해할 수 있습니다.)

실론과 같은 새로운 OO 언어조차도 더 높은 종류의 유형을 가지고 있지 않습니다. (최근에 개빈 킹에게 물었고, 현재로서는 중요하지 않다고 말했다.) 코 틀린에 대해서는 모른다.

*) 공정하게, fmap 메소드를 가진 인터페이스 Functor를 가질 수 있습니다. 나쁜 점은 말할 수 없습니다. 이봐, 나는 도서관 클래스 SuperConcurrentBlockedDoublyLinkedDequeHasMap에 fmap을 구현하는 방법을 알고 있습니다.


FTR : 실론 typechecker와 자바 스크립트는 이제 백엔드 이상 지원 손 유형 (또한 더 높은 순위 유형). "실험적인"기능으로 간주됩니다. 그러나 우리 커뮤니티는이 기능에 대한 실용적인 응용 프로그램을 찾기 위해 고군분투했기 때문에 이것이 언어의 "공식적인"부분이 될지 여부는 분명한 질문입니다. 나는 않습니다 는 자바로 백엔드 어떤 단계에서 지원 될 것으로 기대합니다.
개빈 킹

-2

dBase로 프로그래밍 한 사람이라면 누구나 단일 라인 매크로가 재사용 가능한 코드를 만드는 데 얼마나 유용한 지 알 것입니다. Lisp로 프로그래밍하지는 않았지만 컴파일 타임 매크로로 맹세하는 많은 사람들로부터 읽었습니다. 컴파일 타임에 코드에 코드를 삽입한다는 아이디어는 "include"지시문을 사용하여 모든 C 프로그램에서 간단한 형태로 사용됩니다. Lisp은 Lisp 프로그램으로이 작업을 수행 할 수 있고 Lisp는 반사성이 높으므로 훨씬 유연하게 포함 할 수 있습니다.

웹에서 임의의 텍스트 문자열을 가져 와서 데이터베이스에 전달하는 프로그래머는 프로그래머가 아닙니다. 마찬가지로 "사용자"데이터가 자동으로 실행 코드가되도록하는 사람은 어리석은 일입니다. 그렇다고해서 프로그램이 실행 시간에 데이터를 조작 한 다음 코드로 실행할 수 있다는 것은 나쁜 생각입니다. 나는이 기술이 미래에 없어서는 안될 것이라고 믿는다.이 기술은 실제로 대부분의 프로그램을 작성하는 "스마트 한"코드를 가질 것이다. "데이터 / 코드 문제"의 전체 여부는 언어의 보안 문제입니다.

대부분의 언어의 문제점 중 하나는 한 명의 오프라인 사람이 자신을 위해 일부 기능을 실행하도록 만들어 졌다는 것입니다. 실제 프로그램에서는 많은 사람들이 여러 Core 및 여러 컴퓨터 클러스터에서 항상 동시에 액세스 할 수 있어야합니다. 보안은 운영 체제가 아닌 언어의 일부 여야하며 먼 미래에는 그렇지 않을 것입니다.


2
프로그래머에 오신 것을 환영합니다. 답변에서 수사를 없애고 일부 클레임을 외부 참조로 뒷받침하십시오.

1
사용자 데이터가 자동으로 실행 코드가 될 수있게하는 프로그래머는 분명 무지하다 . 바보가 아닙니다. 그렇게하는 것은 종종 쉽고 분명한 일이며, 왜 그것이 나쁜 생각인지 왜 더 나은 해결책이 있는지 모른다면, 그 일을한다고 비난 할 수 없습니다. (그러나 더 좋은 방법이 있다는 것을 배운 후에도 계속 그렇게하는 사람은 분명히 바보입니다.)
Mason Wheeler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.