Dietrich Epp에 동의합니다 . GHC를 빠르게 만드는 여러 가지 요소 의 조합입니다 .
무엇보다 Haskell은 매우 높은 수준입니다. 이를 통해 컴파일러는 코드를 손상시키지 않고 적극적인 최적화 를 수행 할 수 있습니다.
SQL에 대해 생각하십시오. 이제 SELECT
명령문을 작성할 때 명령 루프 처럼 보일 수 있지만 그렇지 않습니다 . 그것은 수있는 모습 이 지정된 조건과 일치하는 하나를 찾기 위해 노력하고 그 테이블의 모든 행을 통해 루프하지만, 실제로는 완전히 다른 성능 특성을 가지고있는 -은 "컴파일러"(DB를 엔진) 조회 대신 인덱스를 수행 할 수있다. 그러나 SQL은 매우 수준이 높기 때문에 "컴파일러"는 완전히 다른 알고리즘을 대체하고 여러 프로세서 나 I / O 채널 또는 전체 서버를 투명하게 적용 할 수 있습니다.
하스켈은 같은 것으로 생각합니다. 방금 Haskell에 입력 목록을 두 번째 목록에 매핑하고 두 번째 목록을 세 번째 목록으로 필터링 한 다음 결과 항목 수를 계산하도록 요청 했다고 생각할 수 있습니다 . 그러나 GHC가 장면 뒤에서 스트림 퓨전 재 작성 규칙을 적용하여 전체 항목을 하나의 엄격한 기계 코드 루프로 변환하여 할당없이 데이터를 한 번에 전달하는 전체 작업을 수행하는 것을 보지 못했습니다. 지루하고 오류가 발생하기 쉬우 며 손으로 직접 작성하는 것이 불가능합니다. 코드에 하위 수준의 세부 정보가 없기 때문에 실제로 가능합니다.
그것을 보는 또 다른 방법은… 왜 Haskell이 빠르지 않아야 하는가? 속도를 늦추려면 어떻게해야합니까?
Perl 또는 JavaScript와 같은 해석 된 언어가 아닙니다. Java 나 C #과 같은 가상 머신 시스템도 아닙니다. 네이티브 머신 코드까지 완전히 컴파일되므로 오버 헤드가 없습니다.
OO 언어 [Java, C #, JavaScript…]와 달리 Haskell은 [C, C ++, Pascal…]과 같은 전체 유형을 지 웁니다. 모든 유형 검사는 컴파일 타임에만 발생합니다. 따라서 속도를 늦추기 위해 런타임 유형 검사가 없습니다. (이 문제에 대해서는 null 포인터 검사가 없습니다. Java의 경우 JVM에서 null 포인터를 검사하고 예외를 지연하면 예외를 throw해야합니다. Haskell은 해당 검사를 신경 쓸 필요가 없습니다.)
"런타임에서 함수를 즉시 생성"하는 것은 느리게 들리지만 매우주의 깊게 살펴보면 실제로 그렇게하지는 않습니다. 그것은 할 수 처럼 당신이,하지만 당신은하지 않습니다. 당신이 말한다면 (+5)
, 글쎄, 그건 하드 코딩 된 소스 코드에있다. 런타임시 변경할 수 없습니다. 따라서 실제로 동적 기능은 아닙니다. 카레 기능조차도 실제로 데이터 블록에 매개 변수를 저장합니다. 모든 실행 코드는 실제로 컴파일 타임에 존재합니다. 런타임 해석이 없습니다. "평가 기능"이있는 다른 언어와는 다릅니다.
파스칼에 대해 생각하십시오. 오래되어 아무도 더 이상 사용하지 않지만 파스칼이 느리다고 불평하는 사람은 아무도 없습니다 . 싫어하는 것이 많지만 느림은 실제로 그중 하나가 아닙니다. Haskell은 수동 메모리 관리가 아닌 가비지 수집을 제외하고는 Pascal과 다른 점을 실제로 많이하지 않습니다. 그리고 불변의 데이터는 GC 엔진에 몇 가지 최적화를 허용한다 [지연 한 평가는 다소 복잡하다].
문제는 하스켈 이 고급 스럽고 정교하고 고급 스러워 보인다 는 것입니다. 모두들 "오 와우, 이거 정말 강력 합니다. 놀랍도록 느려 야합니다! " 또는 적어도, 그것은 당신이 기대하는 방식이 아닙니다. 그렇습니다. 놀라운 유형의 시스템이 있습니다. 그러나 당신은 무엇을 알고 있습니까? 모든 것은 컴파일 타임에 발생합니다. 런타임에 사라졌습니다. 예, 한 줄의 코드로 복잡한 ADT를 구성 할 수 있습니다. 그러나 당신은 무엇을 알고 있습니까? ADT는 단순한 평범한 C union
입니다 struct
. 더 이상 없습니다.
진짜 살인자는 게으른 평가입니다. 코드의 엄격함 / 게으름을 올바르게 얻으면 여전히 우아하고 아름다운 어리석은 빠른 코드를 작성할 수 있습니다. 그러나이 문제가 발생하면 프로그램이 수천 배 느려집니다 . 이러한 이유는 분명하지 않습니다.
예를 들어, 파일에 각 바이트가 몇 번 나타나는지 계산하는 간단한 작은 프로그램을 작성했습니다. 25킬로바이트 입력 파일의 경우, 프로그램은했다 20분 실행하려면를 삼킬 6기가바이트 의 RAM을! 터무니없는! 그러나 문제가 무엇인지 깨달았고 단일 뱅 패턴을 추가했으며 런타임은 0.02 초로 떨어졌습니다 .
이곳 에서 Haskell이 예기치 않게 느리게 진행됩니다. 그리고 그것에 익숙해지기까지 확실히 시간이 걸립니다. 그러나 시간이 지남에 따라 정말 빠른 코드를 작성하는 것이 더 쉬워집니다.
하스켈을 그렇게 빨리 만드는 이유는 무엇입니까? 청정. 정적 유형. 게으름. 그러나 무엇보다도 컴파일러가 코드의 기대치를 손상시키지 않고 구현을 근본적으로 변경할 수있을 정도로 충분히 높은 수준입니다.
하지만 그건 내 의견 일뿐입니다 ...