Làm thế nào để cầu nối lý thuyết và thực hiện trong khi vòng lặp?


8

Tôi đang làm việc với ngôn ngữ lập trình nhỏ của riêng mình cho mục đích giáo dục và tôi gặp phải một chút vấn đề. Có một vài giải pháp khác nhau cho nó, nhưng tất cả chúng đều có vẻ không phù hợp - và từ những gì tôi hiểu, không cần thiết. Nhưng đọc qua những cuốn sách tôi có và tìm kiếm trên google, tôi không thể tìm thấy giải pháp tao nhã.

Vì vậy, vấn đề là tôi đang xây dựng tính toán lambda cơ bản khi tôi hiểu nó. Tôi đã định nghĩa đúng / sai là các thuật ngữ trừu tượng. Tôi có thể kết hợp những thứ này với các hàm để thực hiện loại hành vi if / then / other. Vấn đề đi kèm với các vòng lặp. Tôi có thể định nghĩa một vòng lặp while cơ bản thông qua đệ quy, nhưng trong thực tế, điều đó gây ra tràn ngăn xếp. Theo tôi hiểu, giải pháp thông thường sẽ là thực hiện Tối ưu hóa cuộc gọi Đuôi, nhưng tôi không thấy cách tôi có thể - các điều kiện được xác định bằng ngôn ngữ. Do đó, trình biên dịch không biết rằng phần thân của vòng lặp while nằm ở vị trí đuôi.

Cuốn sách rồng tập trung vào việc thực hiện vòng lặp giả định có nhãn và gotos. Tôi chắc chắn có thể làm điều đó. Dường như các ngôn ngữ khác không xây dựng trong các cấu trúc lặp ít nhất là xây dựng trong các điều kiện và sau đó thực hiện TCO. Và tôi chắc chắn cũng có thể làm điều đó. Nhưng sự hiểu biết của tôi là miễn là tôi có thể áp dụng trừu tượng và thực hiện giảm, thì các vòng lặp (và mọi thứ khác) sẽ có thể được xây dựng từ các khối cơ bản đó.

Vậy tôi còn thiếu gì? Hoặc đây có phải là một trong những trường hợp "bạn có thể mô hình hóa mọi thứ một khi bạn có X và Y" không giống như "bạn có thể mô hình hóa mọi thứ một khi bạn có X và Y trên máy tính thật" và tích hợp là cần thiết cho thực tế mục đích?


Tôi nghĩ bạn đã trả lời câu hỏi của riêng bạn trong đoạn cuối đó. Chỉ vì lý thuyết nói rằng bạn có thể làm điều gì đó không có nghĩa là thực tế để làm điều đó.
Svick 16/2/2015

1
Rất nhiều ngôn ngữ có điều kiện và đệ quy và thực hiện tối ưu hóa cuộc gọi đuôi. Tìm kiếm ngoài cuốn sách rồng.
Dave Clarke

Hãy để tôi làm rõ chuyện này: bạn đang bắt đầu từ tinh khiết -calculus? Nghĩa là, nó có gì, nhưng λ 's và trừu tượng? λλ
Andrej Bauer

Svick - chắc chắn, nhưng là người học, tôi không thể biết đó là trường hợp ở đây hay nếu tôi không biết gì về nó. dave clarke - rất nhiều ngôn ngữ đã được xây dựng trong các điều kiện và thực hiện tối ưu hóa cuộc gọi đuôi. Tôi đã thực hiện tìm kiếm và không tạo ra kết quả nào cho ngôn ngữ có điều kiện và TCO. Nếu bạn có một tài liệu tham khảo tôi đã bỏ qua ... Andrej Bauer - không hoàn toàn, nhưng đủ gần. Không được xây dựng trong các loại, không có chức năng được xây dựng. Bạn có thể khai báo các hàm và áp dụng các hàm. Đi sâu về tình huống cụ thể của tôi sẽ làm cho một câu hỏi kém chất lượng.
Telastyn 16/2/2015

1
@Raphael Sử dụng phép tính lambda như một ngôn ngữ trung gian là một điều quan trọng trong thập niên 1970. Tôi tin rằng mục đích là để phát hiện tối ưu hóa ngữ nghĩa. Sự hiểu biết của tôi (coi chừng tôi không phải là chuyên gia về kỹ thuật biên dịch) là hóa ra việc tối ưu hóa ngữ nghĩa thực sự khó khăn, trong khi tối ưu hóa cục bộ có thể trả nhiều tiền và dễ nhìn hơn trên ngôn ngữ với các bài tập đăng ký và sử dụng goto vừa phải. Tuy nhiên, các ý tưởng từ phép tính lambda có liên quan đến thiết kế trình biên dịch, ví dụ như ý tưởng về phép gán đơn và khái niệm tiếp tục.
Gilles 'SO- ngừng trở thành ác quỷ'

Câu trả lời:


5

Vì vậy, tôi đã giải quyết vấn đề này ngày hôm nay. Mã cho vòng lặp while của tôi:

while (condition: ~>bool) (body: ~>void) => void {
    if condition { 
        body; 
        while condition body; 
    };
}

Khi tôi xây dựng nó thành CIL (thời gian chạy dựa trên ngăn xếp, quan trọng đối với mã psuedocode, không quan trọng đối với câu trả lời), nó trông giống như:

ldarg 0
<build closure from { body; while condition body; }>
call if

Điều quan trọng tôi đã thiếu là trong whilemã, điều kiện là thứ ở vị trí đuôi. Từ phối cảnh của trình biên dịch, khối và hàm while là hai hàm riêng biệt, với hai "đuôi" riêng biệt. Mỗi trong số đó được đánh giá dễ dàng cho vị trí đuôi, làm cho việc tối ưu hóa trở nên khả thi mặc dù thiếu các điều kiện tích hợp.


5

Tôi nghĩ bạn đang thiếu khái niệm về tiếp tục . Mặc dù trình biên dịch của bạn có thể không dựa vào khái niệm đó, với tư cách là nhà thiết kế trình biên dịch với ngôn ngữ chức năng là ngôn ngữ nguồn hoặc trung gian (hoặc đích), điều quan trọng là phải hiểu khái niệm đó và ghi nhớ điều này.

Việc tiếp tục một đoạn mã mô tả những gì mã thoát ra. Theo nghĩa bắt buộc, nó không chỉ thể hiện vị trí mà mã nhảy qua hoặc rơi vào mà còn cả trạng thái chương trình (stack và heap) tại thời điểm đó. Trong thuật ngữ tính toán lambda, sự tiếp tục của một subterm là bối cảnh mà nó được đánh giá.

Khi bạn dịch mã mệnh lệnh sang ngôn ngữ chức năng, một trong những khó khăn là đối phó với mã có thể thoát theo nhiều cách khác nhau. Ví dụ, mã có thể trả về hoặc đưa ra một ngoại lệ. Hoặc, phần thân của một vòng lặp có thể tiếp tục kiểm tra lại điều kiện hoặc thoát hoàn toàn vòng lặp ( breakcấu trúc). Có hai cách chính để đối phó với điều này:

  • Ghép kênh: làm cho mã trả về một loại tổng cho tất cả các lối thoát có thể. Trong trường hợp của một cơ thể vòng lặp, đó sẽ là Continue | Break.
  • Kiểu tiếp tục truyền : dịch mã sang một hàm có thêm một tham số là hàm để thực thi tiếp theo. Tham số phụ này là sự tiếp tục của hàm. Mã có thể thoát theo các cách khác nhau sẽ nhận được một tham số như vậy cho mỗi cách.

λx,y.xλx,y.y , các đối số xy là hai phần tiếp theo có thể có và boolean là một câu lệnh if if nếu chọn một hoặc một phần tiếp theo.

Trong phong cách tiếp tục đi qua,

while (condition) body

được dịch sang

let rec f (continuation) =
  if (condition, body (f (continuation)), continuation)

Trong bản dịch của một chương trình bằng ngôn ngữ mệnh lệnh điển hình theo kiểu tiếp tục truyền, phần tiếp theo luôn là điều cuối cùng mà một đoạn mã thực thi. Ví dụ, việc tiếp tục bodyở trên được thực hiện sau tất cả các mã của body, do đó, kết quả tối ưu hóa cuộc gọi đuôi sẽ giải phóng tất cả các biến cục bộ bodyngay trước khi thực hiện tiếp tục.

Một số ngôn ngữ cung cấp các phần tiếp theo hạng nhất với cấu trúc như tiếp tục cuộc gọi với hiện tại . Cuộc gọi / cc nói chung không phù hợp để tối ưu hóa cuộc gọi - thực tế nó có thể là một hoạt động khá tốn kém vì nó có thể dẫn đến sao chép toàn bộ trạng thái chương trì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.