Tại sao một ngôn ngữ nên thụt lề hơn các điểm đánh dấu rõ ràng cho các khối?


11

Tôi đang học Haskell, và tôi đang tìm kiếm một công cụ thụt tự động. Tôi đã không nhìn nhiều, và học được rằng trong Haskell (như trong Python), thụt đầu dòng biểu thị một khối. Do đó, tôi đoán rằng không thể tạo ra một công cụ định dạng tự động, mạnh như trong các ngôn ngữ khác trong họ C, sử dụng các dấu hiệu rõ ràng, chẳng hạn như {} (dấu ngoặc nhọn) hoặc begin endtừ khóa.

Tôi không ngại một ngôn ngữ thực thi thụt đầu dòng cho khả năng đọc, nhưng tôi không thể hiểu được lợi ích trên cả việc thực thi thụt lề và có một số điểm đánh dấu rõ ràng, để các công cụ tự động, có thể hiểu những gì thuộc về khối nào.

Nếu sở thích của thụt lề đánh dấu một khối, để mã đó trông tốt hơn, thì tôi vẫn không hiểu lợi thế. Cho rằng các tab và không gian được thể hiện khác nhau trong các trình soạn thảo khác nhau và các phông chữ khác nhau (ví dụ phông chữ không gian đơn giản trông gọn gàng hơn), không thể hy vọng lập trình viên sẽ trình bày mã một cách dứt khoát. Một công cụ có thể tính đến trình soạn thảo văn bản hiện tại, sẽ phù hợp hơn nhiều để định dạng mã chính xác.

Tại sao một nhà thiết kế ngôn ngữ sẽ chọn thụt lề trên các điểm đánh dấu khối rõ ràng?


8
Không phải là một câu trả lời, nhưng Haskell làm cho khoảng trắng nhạy cảm một nhiều hơn tùy chọn hơn trăn. Bạn có thể sử dụng dấu chấm phẩy cho hầu hết mọi thứ và bọc các khối trong dấu ngoặc nhọn nếu muốn. let x =1; y = 2; z = 3là hoàn toàn hợp lệ, như là do { putStrLn $ show x; putStrLn $ show y; putStrLn $ show z; }. Những người không cần phải ở trên cùng một dòng.
KChaloux 17/03/2016

8
"Không thể tạo một công cụ định dạng tự động" - thực ra, không cần một công cụ định dạng tự động như vậy trong Python vì các quy tắc thụt lề.
Doc Brown

13
Ừm, tăng thụt đầu dòng một điểm đánh dấu khối rõ ràng.
Karl Bielefeldt

3
@ K.Gkinis: Nguồn tốt nhất cho những động lực chính xác đằng sau quyết định thiết kế ngôn ngữ là chính các nhà thiết kế ngôn ngữ.
Robert Harvey

3
Câu hỏi này không thực sự chủ quan. Nó hỏi tại sao một số nhà thiết kế ngôn ngữ chọn một cú pháp nhất định. Điều này có thể được trả lời. Nếu câu hỏi đã hỏi cú pháp nào là tốt nhất , nó sẽ chủ quan.
JacquesB

Câu trả lời:


13

Guido Von Rossum

Từ một cuộc phỏng vấn với Guido Van Rossum , có thể được nhìn thấy trong toàn văn bản với Books.google.com (nhấn mạnh của tôi):

Sự lựa chọn thụt lề để nhóm không phải là một khái niệm mới trong Python; Tôi đã thừa hưởng điều này từ ABC , nhưng nó cũng xảy ra trong một ngôn ngữ cũ. Tôi không biết liệu các tác giả ABC có ý tưởng từ thỉnh thoảng, hoặc phát minh ra nó một cách độc lập, hoặc nếu có một tổ tiên chung. Tất nhiên, tôi có thể có quyết định không theo sự dẫn dắt của ABC, như tôi đã làm trong các lĩnh vực khác (ví dụ, ABC sử dụng chữ hoa cho các từ khóa ngôn ngữ và tên thủ tục, một ý tưởng tôi đã không sao chép), nhưng tôi đã đến như tính năng khá bit trong khi sử dụng ABC, vì nó dường như loại bỏ một loại tranh luận vô nghĩa phổ biến giữa những người dùng C tại thời điểm đó, về nơi đặt niềng răng xoăn .

Von Rossum được truyền cảm hứng rất nhiều từ ABC , và mặc dù anh ta không phải sao chép tất cả, việc sử dụng thụt đầu dòng được giữ vì nó có thể có lợi trong việc tránh các cuộc chiến tôn giáo.

Tôi cũng nhận thức rõ rằng mã có thể đọc được sử dụng thụt đầu dòng một cách tự nguyện để chỉ ra việc phân nhóm và tôi đã gặp phải các lỗi tinh vi trong mã mà việc thụt lề không đồng ý với nhóm cú pháp sử dụng dấu ngoặc nhọn mà lập trình viên và bất kỳ người đánh giá nào cũng cho rằng việc thụt lề phù hợp với nhóm và do đó không nhận thấy lỗi. Một lần nữa, một phiên gỡ lỗi dài đã dạy một bài học quý giá.

Rossum cũng chứng kiến ​​các lỗi do sự không nhất quán giữa nhóm và thụt lề, và rõ ràng mặc dù chỉ dựa vào thụt lề để cấu trúc mã sẽ an toàn hơn từ lỗi lập trình 1 .

Donald E. Knuth & Peter J. Landin

Trong cuộc phỏng vấn được tham chiếu, Guido đề cập đến ý tưởng sử dụng thụt đầu dòng của Don Knuth. Điều này được trình bày chi tiết trong Bản trích dẫn Knuth Indentation trích dẫn , trong đó trích dẫn Lập trình có cấu trúc với các Báo cáo goto . Knuth cũng tham khảo Peter John Landin 700 ngôn ngữ lập trình tiếp theo (xem phần Thảo luận về thụt lề). Landin đã thiết kế ISWIM trông giống như ngôn ngữ đầu tiên với thụt đầu dòng thay vì các khối bắt đầu / kết thúc. Những bài báo này nói nhiều hơn về tính khả thi của việc sử dụng thụt lề để cấu trúc các chương trình thay vì các lý lẽ thực tế có lợi cho việc đó.


1. Tôi nghĩ rằng trên thực tế đây là một đối số có lợi cho việc có cả cấu trúc nhóm và định dạng tự động, để bắt và phục hồi từ các lỗi lập trình, điều chắc chắn sẽ xảy ra. Nếu bạn thực hiện việc thụt lề trong Python, người gỡ lỗi mã của bạn sẽ phải đoán đúng:

if (test(x)):
  foo(x)
  bar(x)

Phải barluôn luôn được gọi hoặc chỉ khi thử nghiệm thành công?

Các cấu trúc nhóm nhóm thêm một mức độ dự phòng giúp bạn phát hiện ra một lỗi khi bạn tự động thụt mã của mình. Trong C, mã tương đương có thể được tự động thụt lề như sau:

if (test(x))
  foo(x);
bar(x);

Nếu tôi dự định barở cùng cấp độ foo, thì tự động thụt lề dựa trên cấu trúc mã cho tôi thấy rằng có một cái gì đó sai có thể được sửa bằng cách thêm dấu ngoặc xung quanh foobar.

Trong Python: Huyền thoại về thụt lề , có một ví dụ được cho là xấu từ C:

/*  Warning:  bogus C code!  */

if (some condition)
        if (another condition)
                do_something(fancy);
else
        this_sucks(badluck);

Đó là trường hợp tương tự như trên, trong Emacs, tôi làm nổi bật toàn bộ khối / chức năng, nhấn Tab và sau đó tất cả mã được giới thiệu lại. Sự khác biệt giữa thụt lề của con người và cấu trúc mã cho tôi biết có gì đó không ổn (điều đó và nhận xét trước đó!).

Bên cạnh đó, mã trung gian nơi thụt lề tắt trong C đơn giản là không đi qua nhánh chính, tất cả các kiểm tra kiểu tại chỗ sẽ khiến GCC / Jenkins hét vào mặt tôi. Gần đây tôi có một vấn đề tương tự như vấn đề được mô tả ở trên trong Python, với một tuyên bố tắt bởi một cấp độ thụt. Đôi khi tôi có mã trong C vượt ra ngoài dấu ngoặc nhọn, nhưng sau đó tôi nhấn Tab và mã thụt lề "sai": đó là một cơ hội nữa để thấy lỗi.


3
"Để tránh các cuộc chiến tôn giáo ..." Tôi ngạc nhiên rằng lý do thực sự rất tầm thường.
Robert Harvey

1
@RobertHarvey: Sự nhấn mạnh vào cụm từ đó là bởi coredump, không phải bởi van Rossum. Nó không phải là lý do chính nếu bạn đọc trích dẫn van Rossum trong bối cảnh.
JacquesB

@JacquesB Xin vui lòng cho tôi biết bối cảnh nào bị thiếu trong trích dẫn, để tôi có thể chỉnh sửa câu trả lời.
coredump

4
Tôi không nhận được bình luận cá nhân của bạn mặc dù: Nếu bạn làm hỏng thụt lề trong Python, thì bạn có một lỗi. Nếu bạn làm hỏng niềng răng trong C, bạn có một lỗi. Nếu bạn sử dụng tự động thụt lề, nó hoàn toàn giống nhau ở cả hai ngôn ngữ. Và nếu bạn không sử dụng tự động thụt lề, lỗi có thể được ẩn một cách lén lút trong C theo cách không thể có trong Python.
JacquesB

2
@JacquesB vì gõ một dấu ngoặc nhọn là điều mà bạn chủ động làm; không thụt đủ là điều bạn có thể quên làm. Tất nhiên bạn có thể quên đóng niềng răng đúng lúc, nhưng cuối cùng bạn sẽ phải làm điều đó và có cơ hội khác để suy nghĩ về nó. Tôi đoán trăn hoạt động tốt cho người mới bắt đầu vì nó buộc phải chú ý vào vết lõm.
marstato

7

Điều này rất chủ quan và là nguyên nhân cho nhiều cuộc chiến ngọn lửa. Tuy nhiên:

Có các biểu tượng phân định các khối thụt đầu dòng vi phạm nguyên tắc DRY , vì bạn thể hiện cùng một thông tin theo hai cách khác nhau. Sự tồn tại của các công cụ thụt lề tự động là một triệu chứng của vi phạm DRY này: Việc bạn có thể tự động tạo ra thụt lề cho thấy đó là thông tin dư thừa, và điều đó có nghĩa là thụt lề và các ký hiệu có thể không đồng bộ dẫn đến mã sai.

Câu hỏi thường gặp về Thiết kế và Lịch sử Python nêu rõ điều này:

Tại sao Python sử dụng thụt lề để nhóm các câu lệnh?

Guido van Rossum tin rằng việc sử dụng thụt lề để phân nhóm là cực kỳ thanh lịch và đóng góp rất nhiều cho sự rõ ràng của chương trình Python trung bình. Hầu hết mọi người học cách yêu thích tính năng này sau một thời gian.

Vì không có dấu ngoặc bắt đầu / kết thúc nên không thể có sự bất đồng giữa việc phân nhóm được nhận biết bởi trình phân tích cú pháp và trình đọc của con người.

Đúng là bạn không thể tạo một công cụ thụt lề tự động cho Python, nhưng đây là một điều tốt: Điều đó có nghĩa là bạn không có dự phòng trong cú pháp mà bạn cần các công cụ tự động để điều hòa.

Các tab so với khoảng trắng là mối quan tâm chính đáng trong Python và không bao giờ trộn lẫn các tab và khoảng trắng (để thụt lề) trong cùng một cơ sở mã.

Python thừa hưởng sự thụt dòng đáng kể từ ngôn ngữ tiền thân (hiện đã lỗi thời) ABC. ABC là một trong số rất ít ngôn ngữ lập trình đã sử dụng thử nghiệm khả năng sử dụng để chỉ đạo thiết kế. Vì vậy, trong khi các cuộc thảo luận về cú pháp thường đi đến ý kiến ​​chủ quan và sở thích cá nhân, sự lựa chọn của thụt lề đáng kể thực sự có một nền tảng tốt hơn.


6
Kế toán kép cũng vi phạm DRY. Dự phòng đôi khi là một tính năng.
coredump

3
@coredump: Đúng, nhưng nó là một sự dư thừa được thiết kế có chủ ý. Hầu hết các ngôn ngữ lập trình, bao gồm Python, đều chứa các dư thừa được lựa chọn có chủ ý - ví dụ: passtừ khóa có thể được suy luận tự động, nhưng yêu cầu nó phải rõ ràng giúp phát hiện ra các lỗi. Sự dư thừa ngẫu nhiên của việc có cả ký hiệu bắt đầu / kết thúc (đối với trình biên dịch) và thụt lề (đối với người đọc con người) dường như gây ra nhiều lỗi hơn so với bắt. Ít nhất đây dường như là quan điểm của van Rossum.
JacquesB

@coredump - Bây giờ tôi biết tại sao tôi không phải là kế toán viên.
JeffO 17/03/2016

3
@coredump Bạn cũng nhớ COBOL PROCEDURE DIVISION.chứ? Tôi không bao giờ có thể biết nơi DATA DIVISIONkết thúc và các thủ tục bắt đầu trong các ngôn ngữ mới này.
msw 18/03/2016

2
@coredump: "nhìn thấy vết lõm mâu thuẫn với những gì tôi có trong đầu là đủ để ngăn ngừa lỗi" - chính xác.
JacquesB

2

Các nhà thiết kế ngôn ngữ chọn khoảng trắng có ý nghĩa về mặt cú pháp bởi vì họ tin rằng (hoặc ít nhất là nghĩ rằng người dùng tiềm năng của họ tin rằng) dấu chấm phẩy và dấu ngoặc nhọn gây nhiễu khi đọc mã, gây hại cho năng suất. Một lý do phổ biến khác là phong cách mã hóa xấu / không nhất quán gây hại cho khả năng đọc - bằng cách buộc một sơ đồ thụt đầu dòng chung, ngôn ngữ có khả năng đọc tốt hơn tất cả. Lý do sau này ít quan trọng hơn bây giờ là các IDE định dạng tự động phổ biến hơn, nhưng vẫn có thể áp dụng.


1
Tôi có thể thấy lý do tại sao người ta sẽ xem xét dấu chấm phẩy và tiếng ồn niềng răng. Nhưng không phải là ít năng suất hơn khi phải gõ 4/8/12 lần không gian sao? Và nếu bạn bỏ lỡ một (vì chúng vô hình) bạn sẽ gặp rắc rối.
Phục hồi Monica

5
Đó là lý do tại sao bạn sử dụng các tab thay vì dấu cách hoặc IDE hiểu cách chuyển đổi các tab thành các khối bốn không gian.
Robert Harvey

@ K.Gkinis: Ấn không phải là vô hình. Chỉ khoảng trắng ở cuối dòng là vô hình, nhưng điều này không có ý nghĩa trong bất kỳ ngôn ngữ nào. Chỉ khi bạn trộn các tab và không gian, bạn sẽ gặp rắc rối. Vì vậy, đừng làm điều đó.
JacquesB

@JacquesB: vấn đề về khả năng hiển thị / tàng hình của vết lõm là khi là con người, bạn thường không thể nói được sự khác biệt giữa các khoảng trắng và tab, trong khi máy tính có thể và thường làm như vậy. Vì vậy, trong khi vết lõm có thể nhìn thấy, cách máy tính diễn giải vết lõm có thể khác nhau. Đó là vấn đề thực sự: khi máy tính đối xử với các nhân vật vô hình khác với con người. Con người đo độ thụt theo khoảng cách trên màn hình, máy tính có thể đo nó là số ký tự theo nghĩa đen. đó là phần vô hình.
Bryan Oakley

@BryanOakley: Vâng, đây là lý do tại sao bạn không nên trộn các tab và khoảng trắng trong thụt lề.
JacquesB
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.