ฉันเห็นด้วยกับ Dietrich Epp: เป็นการรวมกันของหลายสิ่งที่ทำให้ GHC รวดเร็ว
ก่อนอื่น Haskell อยู่ในระดับสูงมาก สิ่งนี้ทำให้คอมไพเลอร์สามารถทำการปรับให้เหมาะสมแบบก้าวร้าวโดยไม่ทำให้โค้ดของคุณเสียหาย
คิดเกี่ยวกับ SQL ตอนนี้เมื่อผมเขียนSELECT
คำสั่งก็อาจมีลักษณะเช่นห่วงความจำเป็นแต่มันไม่ได้ อาจดูเหมือนว่ามันวนซ้ำแถวทั้งหมดในตารางนั้นพยายามค้นหาหนึ่งที่ตรงกับเงื่อนไขที่ระบุ แต่จริงๆแล้ว "compiler" (เอ็นจิน DB) สามารถทำการค้นหาดัชนีแทนซึ่งมีลักษณะการทำงานที่แตกต่างกันโดยสิ้นเชิง แต่เนื่องจาก SQL อยู่ในระดับสูงดังนั้น "คอมไพเลอร์" จึงสามารถแทนที่อัลกอริธึมที่แตกต่างกันโดยสิ้นเชิงใช้ตัวประมวลผลหลายตัวหรือ I / O channel หรือเซิร์ฟเวอร์ทั้งหมดอย่างโปร่งใสและอื่น ๆ
ฉันคิดว่า Haskell เหมือนกัน คุณอาจคิดว่าคุณเพิ่งขอให้ Haskell ทำการแมปรายการอินพุตเข้ากับรายการที่สองกรองรายการที่สองลงในรายการที่สามแล้วนับจำนวนผลลัพธ์ที่ได้จากรายการ แต่คุณไม่เห็น GHC ใช้กฎการเขียนซ้ำแบบสตรีมฟิวชั่นเบื้องหลังทุกสิ่งกลายเป็นลูปรหัสเครื่องเดียวที่ทำงานทั้งหมดในการส่งผ่านข้อมูลเดียวโดยไม่มีการจัดสรร - สิ่งที่จะ จะน่าเบื่อข้อผิดพลาดได้ง่ายและไม่สามารถบำรุงรักษาได้ด้วยมือ เป็นไปได้จริง ๆ เท่านั้นเนื่องจากไม่มีรายละเอียดในระดับต่ำในรหัส
อีกวิธีในการดูอาจเป็น ... ทำไมHaskell ไม่ควรรวดเร็ว? มันควรทำอะไรช้า ๆ ?
มันไม่ใช่ภาษาที่แปลเช่น Perl หรือ JavaScript มันไม่ได้เป็นระบบเครื่องเสมือนเช่น Java หรือ C # มันรวบรวมไปจนถึงรหัสเครื่องดั้งเดิมดังนั้นจึงไม่มีค่าใช้จ่าย
ต่างจากภาษา OO [Java, C #, JavaScript …], Haskell มีการลบแบบเต็มรูปแบบ [เช่น C, C ++, Pascal …] การตรวจสอบประเภททั้งหมดเกิดขึ้นในเวลารวบรวมเท่านั้น ดังนั้นจึงไม่มีการตรวจสอบชนิดเวลาทำงานเพื่อทำให้คุณช้าลง (ไม่มีการตรวจสอบตัวชี้โมฆะสำหรับเรื่องนั้นในพูด, Java, JVM จะต้องตรวจสอบพอยน์เตอร์พอยน์เตอร์และโยนข้อยกเว้นถ้าคุณให้ความเคารพ Haskell ไม่ต้องกังวลกับการตรวจสอบนั้น)
คุณบอกว่าฟังดูช้าในการ "สร้างฟังก์ชั่นการบินในเวลาทำงาน" แต่ถ้าคุณดูอย่างระมัดระวังคุณจะไม่ทำอย่างนั้น มันอาจดูเหมือนคุณ แต่คุณทำไม่ได้ ถ้าคุณบอก(+5)
ว่านั่นเป็นรหัสที่ฮาร์ดโค้ดของคุณ มันไม่สามารถเปลี่ยนแปลงได้ในเวลาทำงาน ดังนั้นมันจึงไม่ใช่ฟังก์ชั่นไดนามิก แม้แต่ฟังก์ชั่น curried ก็แค่บันทึกพารามิเตอร์ลงในบล็อคข้อมูล รหัสปฏิบัติการทั้งหมดมีอยู่จริงในเวลารวบรวม ไม่มีการตีความขณะใช้งาน (ไม่เหมือนกับภาษาอื่น ๆ ที่มี "ฟังก์ชัน eval")
คิดเกี่ยวกับปาสกาล มันเก่าและไม่มีใครใช้มันใด ๆ มากขึ้น แต่ไม่มีใครจะบ่นว่าปาสคาลเป็นช้า มีหลายสิ่งที่ไม่ชอบเกี่ยวกับเรื่องนี้ แต่ความเชื่องช้าไม่ใช่หนึ่งในนั้น Haskell ไม่ได้ทำอะไรที่แตกต่างจาก Pascal มากนักนอกจากมีการรวบรวมขยะมากกว่าการจัดการหน่วยความจำด้วยตนเอง และข้อมูลที่ไม่เปลี่ยนรูปแบบนั้นทำให้เอ็นจิน GC หลายตัวสามารถทำการปรับให้เหมาะสม
ฉันคิดว่าสิ่งนี้คือ Haskell นั้นดูทันสมัยและมีความซับซ้อนและอยู่ในระดับสูงและทุกคนคิดว่า "โอ้ว้าวสิ่งนี้มีพลังมากจริงๆมันต้องช้าอย่างน่าอัศจรรย์! " แต่มันไม่ใช่ หรืออย่างน้อยก็ไม่ได้เป็นไปตามที่คุณคาดหวัง ใช่มันมีระบบการพิมพ์ที่น่าทึ่ง แต่คุณรู้อะไรไหม? ทุกอย่างเกิดขึ้นในเวลารวบรวม เมื่อถึงเวลาทำงานมันก็หายไป ใช่มันช่วยให้คุณสร้าง ADT ที่ซับซ้อนด้วยบรรทัดของโค้ด แต่คุณรู้อะไรไหม? ADT เป็นเพียง C สามัญธรรมดาunion
ของstruct
s ไม่มีอะไรเพิ่มเติม
นักฆ่าที่แท้จริงคือการประเมินผลที่ขี้เกียจ เมื่อคุณได้รหัสที่ถูกต้องแม่นยำ / เกียจคร้านคุณสามารถเขียนโค้ดที่รวดเร็วอย่างน่าประหลาดที่ยังคงสง่างามและสวยงาม แต่ถ้าคุณทำสิ่งนี้ผิดโปรแกรมของคุณจะช้าลงหลายพันครั้งและไม่ชัดเจนว่าทำไมสิ่งนี้จึงเกิดขึ้น
ตัวอย่างเช่นฉันเขียนโปรแกรมเล็ก ๆ น้อย ๆ เพื่อนับจำนวนครั้งที่แต่ละไบต์ปรากฏในไฟล์ สำหรับอินพุตไฟล์ 25KB โปรแกรมใช้เวลา20 นาทีในการรันและกลืนกินRAM ขนาด6 กิกะไบต์ ! นั่นไร้สาระ !! แต่แล้วฉันตระหนักว่าปัญหาได้รับการเพิ่มปังรูปแบบเดียวและเวลาทำงานลดลงถึง0.02 วินาที
นี่คือที่ที่ Haskell เดินช้าๆโดยไม่คาดคิด และแน่นอนว่าต้องใช้เวลาสักพักก่อนจะชินกับมัน แต่เมื่อเวลาผ่านไปมันจะง่ายต่อการเขียนโค้ดที่รวดเร็วมาก ๆ
อะไรทำให้แฮสเค็ลล์เร็วขึ้น ความบริสุทธิ์ ประเภทคงที่ ความเกียจคร้าน แต่เหนือสิ่งอื่นใดการมีระดับสูงพอที่คอมไพเลอร์สามารถเปลี่ยนแปลงการใช้งานได้อย่างรุนแรงโดยไม่ทำลายความคาดหวังของโค้ดของคุณ
แต่ฉันเดาว่าเป็นเพียงความคิดเห็นของฉัน ...