Tại sao một số ngôn ngữ lập trình Turing hoàn chỉnh nhưng thiếu một số khả năng của các ngôn ngữ khác?


42

Tôi đã gặp một vấn đề kỳ lạ khi viết một trình thông dịch (nên) móc vào các chương trình / chức năng bên ngoài: Các hàm trong 'C' và 'C ++' không thể móc các hàm matrixdic , ví dụ: tôi không thể tạo một hàm gọi 'printf' với các đối số chính xác tương tự mà nó có được, và thay vào đó phải gọi một phiên bản thay thế có một đối tượng biến đổi. Điều này rất có vấn đề vì tôi muốn có thể tạo ra một đối tượng giữ một cái móc ẩn danh.

Vì vậy, tôi nghĩ rằng điều này thật kỳ lạ vì Forth , JavaScript và có lẽ rất nhiều ngôn ngữ khác có thể thực hiện điều này rất dễ dàng mà không cần phải dùng đến ngôn ngữ lắp ráp / mã máy. Vì các ngôn ngữ khác có thể thực hiện việc này một cách dễ dàng, điều đó có nghĩa là lớp các vấn đề mà mỗi ngôn ngữ lập trình có thể giải quyết thực sự thay đổi theo ngôn ngữ, mặc dù các ngôn ngữ này đã hoàn tất Turing ?


33
Bạn nên nhìn vào tarpits turing . Chúng là một loại ngôn ngữ lập trình hấp dẫn mà cố tình có ít hoạt động nhất có thể trong khi vẫn hoàn thành. Hầu hết chúng thiếu các kiểu dữ liệu cơ bản, các hàm, thậm chí cả những thứ đơn giản như khai báo các biến. Cá nhân, tôi nghĩ rằng mã hóa trong chúng là niềm vui lớn, vì nó buộc bạn ra khỏi vùng thoải mái của bạn để thử một thứ gì đó không cần thiết.
DJMcMayhem

8
Nhìn vào những gì một máy Turing làm, và bạn sẽ thấy rằng "Turing-perfect" là một trở ngại rất thấp để xóa. Về cơ bản bất cứ điều gì có thể 'đọc', 'viết' và 'nhảy' trong khi hỗ trợ số học cơ bản là Turing-Complete. Đó là dưới mức các tính năng ngôn ngữ bạn đang xem.
vào

2
Thậm chí còn kỳ cục hơn: hướng dẫn MOV trên bộ xử lý x86 là Turing-Complete. Xem cl.cam.ac.uk/~sd601/ con / mov.pdf để biết chi tiết.
Gareth McCaughan

3
Ngay cả Magic cardgame: The Gathering cũng hoàn chỉnh. Turing-đầy đủ gần như không có gì để làm với các tính năng của ngôn ngữ.
Mast

2
BTW cũng có những ngôn ngữ lập trình rất phức tạp không hoàn thành, chẳng hạn như những trình kiểm tra bằng chứng.
盛安安

Câu trả lời:


68

NkN

λ

Tính đầy đủ của Turing không cho biết gì về việc có các loại, được xây dựng trong mảng / số nguyên / từ điển, khả năng đầu vào / đầu ra, truy cập mạng, đa luồng, phân bổ động, ...

Chỉ vì Java không có tính năng X (giả sử, macro, loại có thứ hạng cao hơn hoặc loại phụ thuộc), nên nó không đột nhiên ngừng hoàn thành Turing.

Turing hoàn thiện và biểu cảm ngôn ngữ là hai khái niệm khác nhau.


42
Edwin Brady, nhà thiết kế của Idris, (chỉ một nửa) sử dụng một cách đùa cợt (tôi không biết liệu anh ta có phát minh ra nó không) thuật ngữ "Tetris-Complete" để diễn tả sự khác biệt này giữa "có thể tính toán bất kỳ hàm tính toán nào trên các số tự nhiên" và "có thể được sử dụng để viết các chương trình không tầm thường tương tác với môi trường ".
Jörg W Mittag

12
Bạn cũng có thể đề cập rằng bạn có thể có những thứ đó trong C / C ++. Bạn chỉ cần viết một số mã đóng vai trò là trình biên dịch trong C / C ++ cho một ngôn ngữ khác có mã nơi mã của bạn biên dịch một chuỗi trong mã C / C ++ của bạn. Sau đó, bạn có thể chỉ cần lập trình trong một cái gì đó như Java trong tệp C của bạn. Đây sẽ là rất nhiều công việc, nhưng nó có thể (có thể là như vậy bởi vì C / C ++ là Turing Complete).
Shufflepants

4
@Shufflepants Tuy nhiên, tôi tự hỏi liệu nó có thực sự hữu ích khi nói "Tôi có thể làm điều đó trong C ++ vì tôi có thể diễn giải một ngôn ngữ khác". Bởi mã thông báo đó, Java, ML, C ++ là tương đương. TM với một lời tiên tri cho các tòa nhà chọc trời (I / O) cũng tương đương. Tôi sợ rằng, bằng lý luận đó, hầu như tất cả các ngôn ngữ đều biểu cảm như nhau. Nếu vậy, nó không phải là một khái niệm hữu ích để so sánh các ngôn ngữ.
chi

9
@chi Bạn nói đúng, chúng tương đương. Đó là ý nghĩa của việc Turing Complete. Bất cứ điều gì có thể được thực hiện với một hệ thống Turing Complete đều có thể được thực hiện trong một hệ thống Turing Complete khác. Nó có thể không thuận tiện để làm điều đó trong một hệ thống cụ thể. Và sự thuận tiện khi làm nhiều việc khác nhau là cách chính để chúng ta so sánh các ngôn ngữ lập trình khác nhau. Nhưng đó không phải là những gì câu hỏi đang hỏi.
Shufflepants

5
@Rhymoid Nếu C không Turing Complete vì lý do truy cập bộ nhớ hoặc vì có thể gửi tín hiệu tùy ý đến thiết bị được kết nối có dung lượng lưu trữ lớn tùy ý không tính, thì người ta có thể lập luận rằng không có ngôn ngữ hoặc thiết bị trong thế giới thực nào là Turing Complete . Nhưng tôi không cảm thấy đó là một lý luận rất hiệu quả.
Shufflepants

47

Turing hoàn thiện là một khái niệm trừu tượng về khả năng tính toán. Nếu một ngôn ngữ là Turing hoàn chỉnh, thì nó có khả năng thực hiện bất kỳ tính toán nào mà bất kỳ ngôn ngữ hoàn chỉnh Turing nào khác có thể làm.

Điều này không, tuy nhiên, nói rằng nó thuận tiện như thế nào để làm như vậy. Một số tính năng dễ sử dụng trong một số ngôn ngữ có thể rất khó ở những ngôn ngữ khác, do lựa chọn thiết kế. Turing hoàn chỉnh chỉ nói rằng bạn có thể làm tính toán. Như một ví dụ cực đoan, có thể khó móc các hàm varadic trong C ++, nhưng có thể viết trình thông dịch JavaScript trong C ++, có thể nối các hàm matrixdic.

Thiết kế ngôn ngữ là một nghệ thuật khá thú vị. Một trong những bước chính người ta phải thực hiện là xác định hành vi nào bạn muốn tạo thành xương sống của ngôn ngữ của bạn. Những hành vi này là những điều dễ thực hiện trong ngôn ngữ của bạn vì chúng được tích hợp ở tầng trệt. Chúng tôi đưa ra quyết định thiết kế về các tính năng sẽ bao gồm trong mọi ngôn ngữ.

Theo ví dụ cụ thể của bạn, khi C được phát triển, nó được thiết kế để hoạt động rất gần với cách ngôn ngữ lắp ráp trong ngày vận hành. Các hàm Variadic chỉ đơn giản đẩy các đối số lên ngăn xếp, với rất ít kiểu an toàn. Việc thực hiện các hàm matrixdic này được để lại cho trình biên dịch, để đảm bảo tính di động tối đa. Theo đó, rất ít giả định được đưa ra về khả năng của phần cứng. Vào thời điểm JavaScript xuất hiện, khung cảnh đã thay đổi. Nó đã hoạt động trong một máy ảo như một ngôn ngữ được giải thích, vì vậy sự cân bằng sẽ chuyển sang hướng thuận tiện. Cho phép hook các hàm matrixdic trở nên hợp lý. Ngay cả trong trường hợp JavaScript được biên dịch đúng lúc, các trình biên dịch của chúng tôi sẵn sàng lưu trữ nhiều thông tin hơn về các đối số so với các trình biên dịch C của yore sẵn sàng lưu trữ.


1
@Wildcard Tôi coi (hầu như) tất cả các trình biên dịch là không rõ ràng. Hầu hết các ngôn ngữ là Turing-Complete, nhưng cuối cùng cần được giải thích bằng / biên dịch để lắp ráp, điều này không phải. Nhưng đây là một giới hạn vật lý cần thiết - phần cứng không bao giờ là Turing mạnh mẽ. Tuy nhiên, khả năng tính toán cung cấp nhiều khái niệm hữu ích "áp dụng", theo nghĩa thực tế, cho các máy tính trong thế giới thực.
chi

3
@Wildcard Theo nghĩa tầm thường đó. Hội (và C) có con trỏ kích thước cố định, chỉ có thể giải quyết một lượng bộ nhớ giới hạn. Về mặt lý thuyết, chúng ta có thể định nghĩa một hội đồng trong đó các con trỏ là tự nhiên không bị ràng buộc, nhưng tôi sẽ không gọi đó là "lắp ráp" nữa - tôi gọi đó là URM hoặc đại loại như thế. Trong thực tế, chúng tôi chỉ đơn giản giả vờ giới hạn vật lý đủ lớn để cho phép các chương trình của chúng tôi chạy, vì vậy ngay cả khi máy tính chỉ là một máy trạng thái hữu hạn (ngụ ý rằng nó không thể thực hiện bổ sung), chúng tôi nghĩ nhiều hơn về nó như một máy Turing ( vì vậy bổ sung là có thể làm được).
chi

4
@chi Điều đó không hoàn toàn chính xác. Trước hết, hầu như mọi người đều coi C là Turing hoàn chỉnh bởi vì chúng tôi thường chỉ định cụm từ đó xung quanh giả định rằng "bạn có đủ bộ nhớ". Đối với số lượng rất ít người phải lo lắng về từ ngữ nghiêm ngặt hơn trong đó các giả định đó không hợp lệ, C không chỉ định kích thước của một con trỏ và không chỉ định ràng buộc về số lượng bộ nhớ có thể được xử lý. Vì vậy, ngay cả trong ý nghĩa nghiêm ngặt tuyệt đối nhất của "Turing hoàn thành", C thực sự là Turing hoàn chỉnh.
Cort Ammon

3
@CortAmmon Tôi phải không đồng ý. Nếu chúng tôi chính thức hóa ngữ nghĩa của C, cố gắng nhúng giả định "đủ bộ nhớ", chúng tôi sẽ thất bại vì sizeof(void *)bắt buộc phải đánh giá một cái gì đó theo tiêu chuẩn ISO C. Điều này buộc chúng ta phải giới hạn dung lượng bộ nhớ cho bất kỳ chương trình nào, cho một thứ lớn - nhưng vẫn bị ràng buộc. Ví dụ, tôi không thể viết một chương trình có ngữ nghĩa là thêm hai tự nhiên tùy ý. C vẫn có thể được tạo ra Turing mạnh mẽ thông qua I / O, sử dụng các tệp như băng TM (như @Hurkyl chỉ ra ở trên). Tôi đồng ý rằng đây không phải là vấn đề trong thực tế.
chi

7
Tôi đề xuất ngôn ngữ mới C-inf, giống hệt C, ngoại trừ khi có quá nhiều bộ nhớ được phân bổ thông qua đệ quy hoặc phân bổ heap, chương trình bị hủy bỏ, được biên dịch lại với giá trị lớn hơn cho sizeof (void *) và sizeof (size_t), và bắt đầu chạy lại từ đầu.
gnasher729

26

Hãy nghĩ về ngôn ngữ lập trình như các phương tiện giao thông đường bộ khác nhau: xe đạp, ô tô, tàu lượn, xe lửa.

Turing Completeness cho biết "phương tiện này có thể đi bất cứ nơi nào mà bất kỳ phương tiện nào khác có thể đi." Đó là, bạn có thể tính toán tất cả các chức năng tương tự. Đầu vào đầu ra, bắt đầu kết thúc.

Nhưng, tuyên bố đó không nói về cách bạn đến đó. Nó có thể là trên đường ray, nó có thể là trên đường, nó có thể ở trên không. Theo cùng một cách, Turing Completeness không nói gì về cách bạn tính toán một hàm. Bạn có thể sử dụng đệ quy, hoặc lặp hoặc một số automata di động kỳ lạ. Bạn có thể sử dụng các loại hoặc không, bạn có thể sử dụng các kỹ thuật động hoặc tĩnh. Nhưng, nếu tất cả những gì bạn xem xét là các hàm (hoặc bộ / ngôn ngữ chính thức) bạn có thể tính toán, miễn là bạn là Turing Complete, các tính năng này cung cấp cho bạn sức mạnh tương tự.


4
Đây là một sự tương tự tuyệt vời. Nó cũng mở rộng độc đáo cho câu hỏi tôi đã thấy ở nơi khác trên trang web này, về việc liệu có thể có các mô hình tính toán khác vượt qua máy Turing hay không: Trong sự tương tự này, máy bay và tàu vũ trụ còn hơn cả Turing Complete, và tàu cao tốc là một loại khác loại máy hoàn toàn. :)
tự đại diện

2
Nhanh hơn du lịch Ánh sáng có lẽ là một sự tương tự tốt hơn cho tính toán siêu Turing. Có thể là có thể, nhưng hầu hết mọi người nghĩ rằng nó không phải.
jmite

@jmite Tất nhiên, vẫn chưa có bằng chứng tốt nào cho thấy bộ não của chúng ta là những máy tính siêu bền. Việc chúng tôi không có khả năng xem xét các máy không bảo vệ có thể xuất phát từ đó, mặc dù đó không nhất thiết là rào cản không thể vượt qua. Máy bay thực sự là một sự tương tự khá tốt - chúng chỉ đi "thẳng" giữa hai điểm, bỏ qua địa hình. Nếu chúng ta có thể bỏ qua cấu trúc liên kết của không thời gian, chúng ta cũng có thể bay nhanh hơn ánh sáng. Không phải là tôi đang nói rằng có thể bỏ qua cấu trúc liên kết của không thời gian, hãy nhớ đến bạn :)
Luaan

1
@Luaan Đúng, nhưng bộ não của chúng ta không nhất thiết phải siêu Turing để hiểu một máy tính siêu Turing. Tôi có thể mô tả ngữ nghĩa của Máy Turing bằng ngôn ngữ kết thúc yếu hơn, như Simply Typed Lambda Tính, bằng cách viết một hàm lấy TM và trạng thái của nó, và chuyển nó sang trạng thái tiếp theo. Tôi thực sự không thể chạy máy theo ngôn ngữ đó (vì nó có thể thực hiện các bước vô hạn), nhưng tôi có thể viết mỗi bước trông như thế nào.
jmite

@Luaan, "vẫn chưa có bằng chứng tốt nào cho thấy bộ não của chúng ta là những máy tính siêu bền bỉ" , nhưng cũng không có bằng chứng nào cho thấy tâm trí con người chỉ là một cỗ máy Turing. Vì không có máy Turing có thể được chỉ ra ở bất cứ đâu mà không thể được bắt nguồn từ ý tưởng bắt nguồn bởi một con người tâm-vẫn là sự khác biệt mà cuộc sống có thể bắt nguồn từ ý tưởng, và contrivances cơ khí không thể. Nhưng đối với các mô hình tính toán, tôi nghĩ rằng máy Turing thực hiện thành công bao gồm bất kỳ thứ gì có thể được gọi là "tính toán" một cách hợp lý, những ý tưởng và giấc mơ và mặc dù vậy.
tự đại diện

17

Những gì bạn chủ yếu hỏi về sự khác biệt giữa sức mạnh tính toán và cái thường được gọi là sức mạnh biểu cảm (hoặc chỉ là biểu cảm ) của một ngôn ngữ (hoặc hệ thống tính toán).

Khả năng tính toán

Sức mạnh tính toán đề cập đến những loại vấn đề mà ngôn ngữ có thể tính toán. Loại sức mạnh tính toán nổi tiếng nhất là tương đương với Máy Turing phổ dụng . Có rất nhiều hệ thống tính toán khác, chẳng hạn như Máy truy cập ngẫu nhiên , tính toán ,, tính toán tổ hợp SK , hàm đệ quy , WHILEchương trình và nhiều hệ thống khác. Và hóa ra, tất cả những thứ này có thể mô phỏng lẫn nhau, điều đó có nghĩa là tất cả chúng đều có sức mạnh tính toán như nhau.

Điều này dẫn đến Luận án Turing Church (được đặt theo tên của Alonzo Church , người đã tạo ra calcul-tính toán và Alan Turing , người đã tạo ra Máy Turing phổ dụng). Luận án Giáo hội là một giả thuyết về khả năng tính toán với hai khía cạnh:

  1. tất cả các hệ thống máy tính có khả năng tính toán chung đều mạnh như nhau và
  2. một người theo thuật toán có thể tính toán chính xác các chức năng mà Máy Turing (và do đó, bất kỳ hệ thống nào khác) có thể tính toán.

Thứ hai là quan trọng trong lĩnh vực triết học của tâm trí hơn là khoa học máy tính.

Tuy nhiên, có hai điều mà Luận án Giáo hội không nói, rất phù hợp với câu hỏi của bạn:

  1. cách hiệu quả các mô phỏng khác nhau đang có và
  2. làm thế nào thuận tiện mã hóa của một vấn đề là.

Một ví dụ đơn giản cho (1): trên Máy truy cập ngẫu nhiên, sao chép một mảng sẽ mất thời gian tỷ lệ thuận với độ dài của mảng. Trên một máy Turing, tuy nhiên, phải mất thời gian tỉ lệ với bình phương của chiều dài của mảng, bởi vì máy Turing không có quyền truy cập bộ nhớ ngẫu nhiên, nó chỉ có thể di chuyển trên băng một tế bào cùng một lúc. Do đó, nó cần phải di chuyển qua n phần tử của mảng n lần để sao chép chúng. Vì vậy, các mô hình tính toán khác nhau có thể có các đặc tính hiệu suất khác nhau, ngay cả trong trường hợp tiệm cận, nơi chúng tôi cố gắng trừu tượng hóa khỏi các chi tiết thực hiện.

Ví dụ cho (2) rất nhiều: cả-tính toán và Python đều hoàn thành Turing. Nhưng bạn có muốn viết một chương trình bằng Python hoặc bằng calcul-tính toán không?

Ngoài ra còn có một nếp nhăn thứ ba mà tôi đã bỏ qua cho đến bây giờ: tất cả các hệ thống ban đầu đó được thiết kế bởi các nhà logic học, triết gia hoặc nhà toán học, không phải bởi các nhà khoa học máy tính, đơn giản là vì máy tính và do đó khoa học máy tính không tồn tại. Tất cả đều quay trở lại đầu những năm 1930, ngay cả trước những thử nghiệm đầu tiên của Konrad Zuse (dù sao không thể lập trình và / hoặc Turing hoàn thành). Họ chỉ nói về "các hàm tính toán trên các số tự nhiên".

Bây giờ, hóa ra, có rất nhiều bạn có thể biểu thị dưới dạng các hàm trên số tự nhiên - xét cho cùng, các máy tính hiện đại của chúng ta thậm chí còn hoạt động ít hơn thế (về cơ bản là 3-4 hàm trên các số 0 và 1, và đó là ), nhưng, ví dụ, hệ điều hành có chức năng gì?

Khái niệm I / O này, tác dụng phụ, tương tác với môi trường, không bị bắt bởi ý tưởng "các hàm trên số tự nhiên". Tuy nhiên, điều này rất quan trọng, vì, Simon Peyton Jones đã từng nói rằng "Tất cả chức năng thuần túy không có tác dụng phụ nào, làm cho CPU của bạn nóng lên" , mà một thành viên khán giả đã trả lời "thực sự, đó một mặt -có hiệu quả quá! "

Edwin Brady , nhà thiết kế của Idris , (chỉ một nửa) sử dụng một cách đùa cợt (tôi không biết liệu anh ta có phát minh ra nó không) thuật ngữ "Tetris-Complete" để diễn tả sự khác biệt này giữa "có thể tính toán bất kỳ hàm tính toán nào trên các số tự nhiên" và "có thể được sử dụng để viết các chương trình không tầm thường tương tác với môi trường ". Trớ trêu hơn nữa, anh ta chứng minh điều này bằng cách thực hiện một bản sao Kẻ xâm lược không gian trong Idris , nhưng anh ta nói rằng anh ta tin tưởng rằng Tetris giảm xuống cho Kẻ xâm lược không gian.

Một điều cần chỉ ra là không chỉ là Turing-tương đương không nhất thiết phải đủ để nói về việc viết chương trình "hữu ích", nó có thể OTOH cũng thậm chí không được necesssary . Ví dụ: SQL chỉ trở nên tương đương Turing với ANSI SQL: 1999 , nhưng nó vẫn hữu ích trước đó. Trên thực tế, một số người có thể lập luận rằng làm cho nó tương đương với Turing chưa thêm vào tính hữu dụng của nó. Có nhiều ngôn ngữ dành riêng cho tên miền không tương đương với Turing. Ngôn ngữ mô tả dữ liệu thường không (và không nên). Total Languages ​​rõ ràng không thể tương đương với Turing, nhưng bạn vẫn có thể viết các vòng lặp sự kiện, máy chủ web hoặc hệ điều hành trong đó. Cũng có những ngôn ngữ tương đương với Turing nhưng trong đó điều này thực sự được coi là một sai lầm.

Vì vậy, tất cả trong tất cả, Turing-tương đương không phải là quá thú vị, trừ khi bạn muốn phân tích tĩnh các chương trình.

Biểu cảm

Giả sử rằng hệ thống tính toán của chúng tôi đủ mạnh về mặt tính toán để thậm chí giải quyết vấn đề của chúng tôi, điều chúng tôi phải làm tiếp theo là thể hiện thuật toán của chúng tôi để giải quyết vấn đề đó theo một loại ký hiệu chính thức nào đó cho hệ thống đó. Nói cách khác: chúng ta cần viết một chương trình bằng một số ngôn ngữ máy tính. Đó là nơi mà khái niệm biểu cảm xuất hiện .

Về cơ bản, nó đề cập đến việc "dễ dàng" hay "thú vị" như thế nào khi viết chương trình của chúng tôi bằng ngôn ngữ lập trình cụ thể của chúng tôi. Như bạn có thể thấy, khái niệm này khá mơ hồ, chủ quan và mang tính tâm lý nhiều hơn là kỹ thuật.

Tuy nhiên, có những nỗ lực tại các định nghĩa chính xác hơn. Cuốn sách nổi tiếng nhất (và khắt khe nhất mà tôi biết) là của Matthias Felleisen trong bài viết về Sức mạnh biểu cảm của ngôn ngữ lập trình (hai trang đầu tiên có phần giới thiệu nhẹ nhàng, phần còn lại của bài báo có nhiều thịt hơn).

Trực giác chính là thế này: khi dịch một chương trình từ ngôn ngữ này sang ngôn ngữ khác, một số thay đổi bạn cần thực hiện được chứa cục bộ (ví dụ như biến FORvòng lặp thành WHILEvòng lặp hoặc vòng lặp thành GOTOs có điều kiện ) và một số yêu cầu thay đổi toàn cầu cấu trúc của chương trình.

Khi bạn có thể thay thế một tính năng của một ngôn ngữ bằng một tính năng khác của ngôn ngữ khác bằng cách chuyển đổi cục bộ, thì các tính năng này được cho là không có tác dụng đối với sức mạnh biểu cảm. Đây được gọi là đường cú pháp .

Mặt khác, nếu nó yêu cầu thay đổi cấu trúc toàn cầu của chương trình, thì ngôn ngữ bạn đang dịch được cho là không thể diễn tả tính năng này. Và ngôn ngữ bạn đang dịch từ được cho là biểu cảm hơn (đối với tính năng này).

Lưu ý rằng điều này đưa ra một định nghĩa khách quan có thể đo lường được về tính biểu cảm. Cũng lưu ý rằng khái niệm này phụ thuộc vào ngữ cảnh vào tính năng và nó mang tính so sánh. Vì vậy, nếu tất cả các chương trình trong ngôn ngữ Một có thể được dịch sang ngôn ngữ B với chỉ thay đổi địa phương, và có ít nhất một chương trình bằng ngôn ngữ B mà có thể không được dịch sang Một chỉ thay đổi địa phương, sau đó ngôn ngữ B là đúng biểu cảm hơn ngôn ngữ Một. Tuy nhiên, kịch bản nhiều khả năng là nhiều chương trình ở cả hai ngôn ngữ có thể được dịch qua lại, nhưng có một số chương trình ở cả hai ngôn ngữ không thể dịch sang ngôn ngữ khác. Điều này có nghĩa là không ngôn ngữ nào biểu cảm rõ ràng hơn ngôn ngữ kia, chúng chỉ có các tính năng khác nhau cho phép các chương trình khác nhau được thể hiện theo những cách khác nhau.

Điều này đưa ra một định nghĩa chính thức về ý nghĩa của việc "biểu cảm hơn", nhưng nó vẫn không nắm bắt được các khái niệm tâm lý đằng sau hiện tượng này. Ví dụ, đường cú pháp, theo mô hình này, không làm tăng sức mạnh biểu cảm của ngôn ngữ, bởi vì nó có thể được dịch chỉ bằng những thay đổi cục bộ. Tuy nhiên, chúng tôi biết từ kinh nghiệm rằng có FOR, WHILEIFcó sẵn, ngay cả khi chúng chỉ là đường cú pháp cho điều kiện GOTOlàm cho việc thể hiện ý định của chúng tôi dễ dàng hơn .

Thực tế là, các ngôn ngữ khác nhau có các tính năng khác nhau giúp thể hiện cách suy nghĩ khác nhau về một vấn đề dễ hơn hoặc khó hơn. Và một số người có thể tìm thấy một cách để thể hiện ý định của họ dễ dàng hơn và những người khác theo một cách khác.

Một ví dụ tôi tìm thấy trong thẻ Ruby trên StackOverflow: nhiều người dùng theo dõi thẻ Ruby cho rằng các vòng lặp dễ hiểu hơn đệ quy và đệ quy chỉ dành cho các lập trình viên chức năng nâng cao và các vòng lặp trực quan hơn cho người mới, nhưng tôi đã thấy nhiều trường hợp hoàn thành những người mới trực giác viết mã như thế này:

def rock_paper_scissors
  get_user_input
  determine_outcome
  print_winner
  rock_paper_scissors # start from the top
end

Điều này thường dẫn đến một số người bình luận rằng "điều này không hiệu quả" và "họ đang làm sai" và "cách chính xác" là:

def rock_paper_scissors
  loop do
    get_user_input
    determine_outcome
    print_winner
  end
end

Vì vậy, rõ ràng, có một số người mà đệ quy đuôi là một cách tự nhiên hơn để diễn tả khái niệm "vòng lặp" hơn là các cấu trúc vòng lặp.

Tóm lược

Thực tế là hai ngôn ngữ tương đương với Turing nói lên một và chính xác một điều: chúng có thể tính toán cùng một bộ hàm trên các số tự nhiên như một máy Turing có thể. Đó là nó.

Nó không nói bất cứ điều gì về việc họ tính toán các hàm đó nhanh như thế nào. Nó không nói bất cứ điều gì về việc dễ dàng thể hiện các chức năng đó. Và nó không nói bất cứ điều gì khác về những gì họ có thể làm ngoài chức năng tính toán trên các số tự nhiên (ví dụ: liên kết đến thư viện C, đọc đầu vào từ người dùng, ghi đầu ra ra màn hình).

điều đó có nghĩa là lớp các vấn đề mà mỗi ngôn ngữ lập trình có thể giải quyết thay đổi theo ngôn ngữ, mặc dù các ngôn ngữ này đã hoàn tất?

Đúng.

  1. Có những vấn đề không được đề cập trong thuật ngữ "Turing-Complete" (chỉ liên quan đến chức năng tính toán trên các số tự nhiên) như in ra màn hình. Hai ngôn ngữ có thể là Turing-Complete nhưng một ngôn ngữ có thể cho phép in ra màn hình và ngôn ngữ kia thì không.
  2. Ngay cả khi cả hai ngôn ngữ có thể giải quyết cùng một vấn đề, điều đó không nói lên điều gì về mức độ phức tạp của mã hóa và việc thể hiện mã hóa này dễ dàng như thế nào. Ví dụ: C có thể giải quyết mọi vấn đề mà Haskell có thể, chỉ đơn giản bằng cách viết trình thông dịch Haskell bằng Cọ nhưng trước tiên bạn phải viết trình thông dịch Haskell để giải quyết vấn đề theo cách này!

7

Tất cả các ngôn ngữ lập trình hoàn chỉnh Turing có thể thực hiện cùng một bộ thuật toán. Vì vậy, nếu bạn thấy rằng một số thuật toán rất khó thực hiện bằng một ngôn ngữ cụ thể, điều đó không có nghĩa là không thể.

Hãy nhớ rằng một ngôn ngữ bao gồm cú pháp và ngữ nghĩa. Đôi khi, tập hợp các từ thuộc một số ngôn ngữ không phải là tối thiểu để được coi là Turing hoàn chỉnh, có những tính năng giúp mọi việc dễ dàng hơn (đó là lý do tại sao chúng được gọi là tính năng ). Nếu bạn loại bỏ các tính năng đó, ngôn ngữ vẫn hoàn thành Turing.

Một số trong số này có thể được quan tâm:


5

Tất cả các ngôn ngữ Turing-Complete có thể tính toán những thứ giống nhau.

Nếu bạn cố gắng thực hiện một ngôn ngữ hiện đại, bạn sẽ nhận thấy rằng hầu hết các tính năng của nó không thêm bất kỳ khả năng tính toán nào. Nhiều tính năng trong số đó có thể được hạ xuống thành các tính năng đơn giản hơn đã tồn tại trong cùng một ngôn ngữ.

Dưới đây là một số ví dụ:

  • Nếu bạn không có enums, bạn có thể sử dụng số nguyên.
  • Nếu bạn không có bộ đệm biết kích thước của chúng, bạn có thể tạo một loại có chứa kích thước và bộ đệm không biết kích thước của nó.
  • Nếu bạn không kiểm tra giới hạn bộ đệm, bạn chỉ có thể kiểm tra chỉ mục mỗi khi bạn sử dụng chúng.
  • Nếu bạn không có các hàm matrixdic, bạn có thể tạo một hàm lấy bộ đệm biết kích thước của nó và đọc từ bộ đệm đó cùng thông tin mà bạn nhận được từ các đối số chính thức.
  • Nếu bạn không có toán tử, bạn có thể sử dụng các hàm.
  • Nếu bạn không có các loại có thể kế thừa lẫn nhau, bạn có thể tạo các loại có chứa lẫn nhau và truy cập chúng thông qua một mức độ bổ sung khác, với kiểu con chỉ đơn giản là một sự chuyển đổi của kiểu xử lý thành toàn bộ thành một xử lý theo kiểu chứa.
  • Nếu bạn không có đại biểu nhưng bạn có con trỏ hàm, bạn có thể tạo một loại có chứa đối tượng tham chiếu và con trỏ hàm.
  • Nếu bạn không có đại biểu nhưng bạn có giao diện, bạn có thể khai báo một giao diện chứa một phương thức duy nhất với chữ ký bạn muốn.
  • Nếu bạn không có các loại chung chung, bạn có thể sử dụng các loại không chung chung mà chỉ giả sử các giới hạn trên hoặc dưới mà bạn quan tâm (và có thể thực hiện các phôi phù hợp tại các điểm sử dụng, để giữ cho trình biên dịch hài lòng).
  • Nếu bạn không có hệ thống loại tuyến tính / affine, bạn chỉ có thể tránh sử dụng bất kỳ biến nào nhiều lần.
  • ... và cứ thế.

Thiết kế ngôn ngữ chính tập trung vào các tính năng giúp chúng tôi dễ dàngthuận tiện hơn để tính toán mọi thứ nhanh hơn, nhận ra lỗi của chúng tôi trước đó, chương trình chống lại các thành phần chưa biết, làm cho song song an toàn hơn, v.v.

Các công cụ tính toán thuần túy đã bị đóng đinh từ lâu.


4

Các câu trả lời hiện có chỉ ra rằng Turing hoàn chỉnh không phải là một cách tốt để so sánh các ngôn ngữ. Thật vậy, gần như tất cả các ngôn ngữ đều Turing hoàn chỉnh. ("Nếu mọi người đều đặc biệt, thì không ai là đặc biệt", như The Incredibles thường nói.)

Tuy nhiên, nó có thể so sánh các biểu cảm của ngôn ngữ với độ chính xác toán học. Hãy xem Felleisen về sức mạnh biểu cảm của ngôn ngữ lập trình . Một cách thô bạo, ý tưởng là đặt câu hỏi sau: Tôi có thể chuyển đổi bất kỳ chương trình nào trong ngôn ngữ A thành chương trình bằng ngôn ngữ B bằng cách chỉ thực hiện các thay đổi cục bộ không? Nói cách khác, Felleisen đưa ra một hình thức chính xác về mặt toán học cho trực giác của bạn.


2

Trên đầu câu trả lời của người khác, đây là một tương tự khác.

Để giặt quần áo, bạn cần ba thứ: một số hồ chứa nước, chất tẩy rửa nào đó và cơ chế khuấy trộn. Điều này có thể được nhận ra theo nhiều cách. Hồ chứa nước là bất cứ thứ gì chứa đủ nước (ví dụ: bồn, hồ, sông). Cơ chế khuấy trộn có thể là một thiết bị cơ khí, một tấm rửa hoặc thậm chí là một tảng đá mà quần áo bị đập. Và chất tẩy rửa cũng có nhiều dạng khác nhau.

Vì vậy, sự khác biệt giữa một máy giặt máy tính hiện đại và một tảng đá bên cạnh một dòng sông là gì?

Nó nắm rõ ba điều: hiệu quả, an toàn và tiện lợi. Một số phương pháp rửa sử dụng ít năng lượng hơn, gây ô nhiễm môi trường ít hơn, sử dụng ít nước hơn, v.v. Một số phương pháp giặt đòi hỏi các hoạt động thủ công ít lặp đi lặp lại (dẫn đến thương tích) hoặc ở ngoài trời trong thời tiết khắc nghiệt. Và một số phương pháp giặt không đòi hỏi con người phải trông nom quá trình.

Các ngôn ngữ lập trình hoàn chỉnh là mục đích chung, vì vậy chúng được đặt vào nhiều hơn một nhiệm vụ. Tuy nhiên, đối với một tác vụ nhất định, một số ngôn ngữ lập trình hiệu quả hơn, thuận tiện hơn và an toàn hơn (theo nghĩa là ít có thể sai khi chương trình thực sự được sử dụng) so với các ngôn ngữ khác.


2

Những người khác đã cung cấp rất nhiều câu trả lời hay, nhưng họ không đề cập rõ ràng đến một lời cảnh báo đã từng làm tôi bối rối rất nhiều: Tính đầy đủ của Turing không ngụ ý rằng một ngôn ngữ có thể diễn đạt các chức năng tính toán tùy ý từ đầu vào của nó đến đầu ra của nó. Nó yếu hơn: phải có một số cách biểu diễn miền và phạm vi của tập hợp các hàm tính toán là đầu vào và đầu ra sao cho mỗi hàm này ánh xạ tới một chương trình có biểu diễn đầu vào của nó cho đầu ra tương ứng.

Lấy ví dụ, một ngôn ngữ diễn tả các máy Turing. Mỗi chương trình trong ngôn ngữ là một máy Turing.

Bây giờ hãy xem xét ngôn ngữ con của tất cả các máy Turing chỉ đọc và viết các ký tự a, b và trống. Nó hoàn thành Turing, nhưng nó không thể diễn tả bất kỳ chương trình nào, ví dụ, tạo ra c trên tất cả các đầu vào, vì nó không thể viết bất kỳ cs nào. Nó chỉ có thể biểu thị tất cả các hàm tính toán trên đầu vào và đầu ra được mã hóa dưới dạng chuỗi của as và bs.

Vì vậy, không phải sự thật là tất cả các ngôn ngữ hoàn chỉnh Turing đều có thể tính toán những thứ giống nhau, ngay cả khi chúng ta giới hạn những thứ này là các hàm tính toán từ đầu vào tiềm năng của chúng đến đầu ra tiềm năng của chúng. Ngôn ngữ có thể yêu cầu đầu vào và đầu ra được mã hóa theo những cách nhất định.

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.