Liệu một vòng lặp do-while có đủ cho Turing-đầy đủ không?


22

Tôi biết rằng, trong các ngôn ngữ lập trình bắt buộc, vòng lặp while-do đủ để xây dựng luồng điều khiển để làm cho ngôn ngữ trở nên hoàn chỉnh (theo như luồng điều khiển đi - tất nhiên chúng ta cũng cần bộ nhớ không giới hạn và các toán tử nhất định ...) . Ý chính của câu hỏi của tôi là: vòng lặp do-while có sức mạnh tính toán tương tự như vòng lặp while-do không? Nói cách khác, một ngôn ngữ có thể hoàn thành Turing nếu không thể bỏ qua các hướng dẫn hoàn toàn.

Tôi nhận ra rằng một số ngữ nghĩa ở đây có thể hơi mơ hồ, vì vậy hãy để tôi diễn đạt câu hỏi thực tế bằng một ví dụ cụ thể:

Brainfuck (BF) là một tarpit Turing trong đó luồng điều khiển duy nhất là vòng lặp while-do, được ký hiệu là [...](có một thông số ngôn ngữ hoàn chỉnh ở cuối câu hỏi, trong trường hợp bạn không quen thuộc với Brainfuck). Chúng ta hãy định nghĩa một ngôn ngữ mới BF *, nơi ,.+-<>có cùng ngữ nghĩa như trong BF, nhưng thay vì []chúng ta có ngôn ngữ {}biểu thị một vòng lặp do-while. Đó là, sự khác biệt duy nhất với BF là mỗi vòng lặp được thực hiện ít nhất một lần trước khi các lần lặp tiếp theo có thể được bỏ qua.

BF * Turing đã hoàn thành chưa? Nếu đúng như vậy, tôi sẽ quan tâm đến cách tôi có thể dịch BF sang BF *. Nếu không, làm thế nào để tôi chứng minh điều đó?

Một số quan sát của riêng tôi:

  • Không phải mọi chương trình BF đều có thể được dịch sang BF *. Chẳng hạn, không thể viết chương trình bằng BF * có thể đọc hoặc in một giá trị - nếu chương trình có khả năng in một hoặc nhiều giá trị, nó sẽ luôn in ít nhất một giá trị. Tuy nhiên, có thể có một tập hợp con Turing hoàn chỉnh của BF có thể được dịch sang BF *.
  • Chúng ta không thể đơn giản dịch [f]( fchương trình Brainfuck tùy ý chỉ bao gồm +-[]<>) thành (trong nỗ lực hủy hiệu ứng của lần lặp đầu tiên), bởi vì a) không phải mọi hàm tính toán đều có nghịch đảo tính toán và b) ngay cả khi nó đã làm, sẽ không nhất thiết phải có ít vòng lặp hơn vì vậy áp dụng bước này một cách đệ quy không được đảm bảo chấm dứt ngay từ đầu.f-1{f}f-1f

Dưới đây là một tổng quan nhanh về ngôn ngữ Brainfuck. Brainfuck hoạt động trên một băng vô hạn trong đó mỗi ô chứa một giá trị byte, ban đầu bằng không. Tràn đầy bao quanh, do đó, tăng 255 cho 0 và ngược lại. Ngôn ngữ bao gồm 8 hướng dẫn:

+   Increment the current cell.
-   Decrement the current cell.
>   Move tape head to the right.
<   Move tape head to the left.
,   Input a character from STDIN into the current cell.
.   Output the current cell as a character to STDOUT.
[   If the current cell is zero, jump past the matching ].
]   If the current cell is non-zero, jump back to just behind the matching [.


thú vị nhưng nghĩ rằng nó không được xây dựng đầy đủ cẩn thận. []không chính xác xác định vòng lặp "while do" trong BF. như trong bảng của bạn, dấu ngoặc trái và phải đánh giá ô hiện tại zero / nonzero. Vì vậy, mô tả chính xác của {}logic đánh giá niềng răng tương ứng là gì? đề nghị thêm cuộc đối thoại / thảo luận trong Trò chuyện Khoa học Máy tính . ngoài ra "các quan sát" của bạn giống như "các định đề" hoặc "các mệnh đề" mà không có bằng chứng.
vzn

@vzn Đó là những điểm tốt. Tôi đoán rằng định nghĩa rõ ràng là {}sẽ {không làm gì cả và }giống như ]. Tôi sẽ không có nhiều thời gian trong vài ngày tới, nhưng tôi sẽ cùng bạn trò chuyện khi tôi tìm thấy chút thời gian.
Martin Ender

Vì vậy, than ôi điều này rõ ràng là hơi tinh tế để hỏi và dường như có hai câu hỏi hoàn toàn khác nhau ở đây. (1) được cung cấp bất kỳ ngôn ngữ hoàn chỉnh Turing nào với vòng lặp while-do (và "những thứ khác"), nó có thể được chuyển đổi thành ngôn ngữ hoàn chỉnh Turing chỉ bằng một vòng lặp do-while. nhưng sau đó người ta cần biết thêm về "những thứ khác" một cách chi tiết để trả lời. (2) đã cho BF và BF * mới với định nghĩa đã cho {}và lấy đi [], là BF * Turing hoàn tất. với sự hiểu biết rằng BF []là một cấu trúc chỉ giống như một cái gì đó tương tự / tương tự như một vòng lặp while-do trong các ngôn ngữ hoàn chỉnh Turing.
vzn

1
@vzn phần (1) chỉ là phần TL; DR trong câu hỏi của tôi. Tôi hoàn toàn biết rằng điều này có lẽ không thể trả lời cho "một số ngôn ngữ". Đây là lý do tại sao tôi đặt câu hỏi thực tế theo ngôn ngữ đồ chơi rất đơn giản (BF) để thực sự thu hẹp nó thành hành vi của các vòng lặp (vì tôi đã hình dung nếu BF * có thể được hiển thị là TC sẽ làm cho nó đơn giản hơn để hiển thị nó cho các ngôn ngữ khác chỉ có các vòng lặp do-while). Tôi không chắc rằng bạn nghĩ các vòng lặp BF khác với các vòng lặp trong khi làm ngôn ngữ khác như thế nào.
Martin Ender

Câu trả lời:


10

Tôi không biết Brainfuck vì vậy bạn sẽ phải thực hiện một số bản dịch từ mã giả của tôi. Nhưng, giả sử rằng Brainfuck hành xử hợp lý (ha!), Mọi thứ dưới đây nên được áp dụng.

do-while tương đương với while-do. do X while Ytương đương với X; while Y do Xvà, giả sử bạn có điều kiện, while Y do Xtương đương với if Y then (do X while Y).

Cuộc sống sẽ khó khăn hơn một chút nếu bạn không có điều kiện. Nếu bạn có while-do, bạn có thể mô phỏng if Y then Xbằng cách sử dụng một cái gì đó như thế này:

B := true
while (Y and B) do
    X
    B := false
endwhile

Nhưng nếu bạn chỉ có thời gian thì sao? Tôi cho rằng các mô phỏng sau đây if Y then X, giả sử rằng Xchấm dứt với giá trị hiện tại của các biến. (Điều này không được đảm bảo: chương trình if y=0 then loopforeverchấm dứt nếu y != 0, mặc dù Xcác vòng lặp cho bất kỳ giá trị nào của các biến). Hãy V1, ..., Vnlà biến đổi bởi Xvà để X'được Xsửa đổi để nó sử dụng Vi'thay vì Vicho mỗi người trong số các biến. swap(A,B)biểu thị mã rõ ràng hoán đổi các biến AB.

V1' := V1; ...; Vn' := Vn
V1'' := V1; ...; Vn'' := Vn
C := 0
do
    X'
    swap (V1',V1''); ...; swap (Vn',Vn'')
    C := C+1
while Y and C<2
V1 := V1'; ...; Vn := Vn'

Ý tưởng như sau. Đầu tiên, giả sử đó Ylà sai. Chúng tôi mô phỏng làm Xmột lần và lưu trữ kết quả vào V1'', ..., Vn''; V1', ..., Vn'giữ các giá trị ban đầu của V1, ..., Vn. Sau đó, chúng tôi chỉ định V1 := V1'; ...; Vn := Vn', mà không làm gì. Vì vậy, nếu Ylà sai, chúng tôi không làm gì cả. Bây giờ, giả sử đó Ylà sự thật. Bây giờ chúng ta sẽ mô phỏng X hai lần , lưu trữ các kết quả trong cả hai biến "mồi" và "mồi kép". Vì vậy, bây giờ, các bài tập ở cuối vòng lặp có hiệu lực Xđược tính một lần. Lưu ý rằng Ychỉ phụ thuộc vào các biến "không xác định", vì vậy giá trị của nó không bị ảnh hưởng bằng cách chạy vòng lặp nhiều lần.

OK, vậy nếu Xkhông thể chấm dứt giá trị hiện tại của các biến thì sao? (Cảm ơn Martin Ender đã chỉ ra khả năng này.) Trong trường hợp đó, chúng ta cần mô phỏng Xhướng dẫn theo hướng dẫn, sử dụng các ý tưởng tương tự như những ý tưởng trên. Mỗi lệnh chắc chắn chấm dứt để chúng ta có thể sử dụng ifmô phỏng ở trên để thực hiện giải mã hướng dẫn, dọc theo dòng "Nếu opcode là foo, hãy làm điều này; nếu đó là thanh, hãy làm điều đó; ...". Vì vậy, bây giờ, chúng ta sử dụng một vòng lặp để lặp qua các hướng dẫn của X, sử dụng một con trỏ lệnh và để chúng ta biết lệnh nào sẽ thực hiện tiếp theo. Vào cuối mỗi lần lặp của vòng lặp, hãy kiểm tra Yvà kiểm tra xem Xđã dừng chưa. Nếu Ylà sai, kỹ thuật tráo đổi cho phép chúng ta hoàn tác các hiệu ứng củaXHướng dẫn đầu tiên.


1
Đây là một ý tưởng gọn gàng, nhưng tôi nghĩ có một vấn đề ở đây: xem xét trường hợp Ysai nhưng Xkhông chấm dứt trên tập các giá trị biến hiện tại. if Y then Xchấm dứt, nhưng bản dịch của bạn thì không, bởi vì nó luôn cần phải thực thi X'ít nhất một lần.
Martin Ender

1
@ MartinBüttner Urgh. Bạn đúng. Vì vậy, chúng ta cần sử dụng vòng lặp để mô phỏng Xhướng dẫn theo chỉ dẫn và kiểm tra Ysau mỗi hướng dẫn. Mỗi hướng dẫn được đảm bảo để chấm dứt vì vậy mọi thứ sẽ hoạt động. Nhưng đó là một nỗi đau để viết ra.
David Richerby

1
Tôi không hoàn toàn chắc chắn liệu có thể giải cấu trúc Xnhư vậy hay không nếu nó bắt đầu bằng một vòng lặp while / chính nó có điều kiện. Tôi sẽ phải suy nghĩ về điều này nhiều hơn nữa.
Martin Ender

Ngoài ra "Vì vậy, bây giờ, chúng tôi sử dụng một vòng lặp để lặp qua các hướng dẫn của X, sử dụng một con trỏ lệnh và cứ thế để chúng tôi biết lệnh nào sẽ thực hiện tiếp theo." Tôi cảm thấy như thế này có thể đòi hỏi một điều kiện nào đó.
Martin Ender

1
Tôi vẫn không hoàn toàn chắc chắn về cách bạn định nghĩa "mỗi hướng dẫn" nếu X'không tuyến tính. Bạn có phiền bao gồm một số chi tiết cho một đồ chơi đơn giản nhưng không tầm thường X? Ví dụ do (while A do B) while C? (bên ngoài do whileđến từ bên ngoài while domà chúng tôi hiện đang dịch)
Martin Ender
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.