Các cuộc gọi đuôi được tối ưu hóa trong Frege. Tôi biết rằng có TCO không phải trong Java cũng không phải trong các ngôn ngữ biên dịch sang bytecode JVM như Clojure và Scala. Còn Frege thì sao?Frege có thực hiện tối ưu hóa cuộc gọi đuôi không?
Trả lời
Frege thực hiện Tối ưu hóa đệ quy đuôi bằng cách tạo ra các vòng lặp đơn giản.
Cuộc gọi đuôi chung được xử lý "bằng cách" thông qua sự lười biếng. Nếu trình biên dịch nhìn thấy một cuộc gọi đuôi đến một chức năng nghi ngờ được biết đến là (gián tiếp) đệ quy, một kết quả lười biếng (một mảnh) được trả về. Do đó, gánh nặng thực sự của việc gọi hàm đó nằm với người gọi. Bằng cách này, ngăn xếp có chiều sâu phụ thuộc vào dữ liệu được tránh.
Điều đó đang được nói, độ sâu ngăn xếp tĩnh là do bản chất sâu hơn trong ngôn ngữ chức năng hơn trong Java. Do đó, một số chương trình sẽ cần phải có một ngăn xếp lớn hơn (tức là với -Xss1m).
Có trường hợp bệnh lý, nơi khối lớn được xây dựng và khi chúng được đánh giá, tràn ngăn xếp sẽ xảy ra. Một ví dụ khét tiếng là hàm foldl (cùng một vấn đề như trong Haskell). Do đó, nếp gấp tiêu chuẩn trong Frege là gấp, mà là đệ quy đuôi và nghiêm ngặt trong ắc quy và do đó làm việc trong không gian ngăn xếp liên tục (như Haskells foldl ').
Các chương trình sau đây nên không stack overflow nhưng print "false" sau 2 hoặc 3s:
module Test
-- inline (odd)
where
even 0 = true
even 1 = false
even n = odd (pred n)
odd n = even (pred n)
main args = println (even 123_456_789)
này hoạt động như sau: println phải có giá trị để in, vì vậy cố gắng để đánh giá (ngay cả n). Nhưng tất cả nó được là một mảnh để (lẻ (pred n)). Do đó nó cố gắng để đánh giá thunk này, mà được một thunk để (thậm chí (pred (pred n))). thậm chí phải đánh giá (pred (pred n)) để xem đối số là 0 hay 1, trước khi trả về một đoạn khác (lẻ (pred (n-2)) trong đó n-2 đã được đánh giá. ở cấp độ JVM) được thực hiện từ bên trong println.Không có lúc nào thực sự gọi lẻ, hoặc ngược lại.
Nếu một chỉ thị không trực tiếp, một phiên bản có đuôi đệ quy, và kết quả thu được mười lần . nhanh
Không cần phải nói, thuật toán vụng về này chỉ dành cho trình diễn -. Thông thường người ta sẽ kiểm tra thậm chí-Ness với một thao tác chút
Dưới đây là một phiên bản khác, đó là bệnh lý và sẽ stack overflo w:
even 0 = true
even 1 = false
even n = not . odd $ n
odd = even . pred
Vấn đề là ở đây mà not
là tiếng gọi đuôi và nó là nghiêm ngặt trong đối số của nó (ví dụ, để phủ nhận điều gì đó, trước tiên bạn phải có một cái gì đó). Do đó, khi tính toán even n
, thì not
phải đánh giá đầy đủ odd n
, do đó, phải đánh giá đầy đủ even (pred n)
và do đó, nó sẽ có khung 2 ngăn xếp * n.
Thật không may, điều này sẽ không thay đổi, ngay cả khi JVM có cuộc gọi đuôi thích hợp một ngày. Lý do là đệ quy trong đối số của một chức năng nghiêm ngặt.
Câu trả lời tuyệt vời, cảm ơn rất nhiều! BTW có chú thích nghiêm ngặt trong Frege? – haskelline
Có. Bang mẫu. – Ingo
@Landei TCO không được hỗ trợ đầy đủ trong Scala ... hãy thử cái này.
def foo() { def bar() { println("bar"); foo() }; println("foo"); bar() }
Lưu ý, tôi không có đủ danh tiếng để nhận xét trực tiếp. Tìm nhận xét Tôi đang trả lời trong phần bình luận của câu hỏi gốc.
- 1. MATLAB có thực hiện tối ưu hóa cuộc gọi đuôi không?
- 2. Tối ưu hóa cuộc gọi đuôi bên cạnh đệ quy đuôi?
- 3. Có thể bắt buộc tối ưu hóa cuộc gọi đuôi trên GCC/Clang không?
- 4. Liệu array_walk_recursive có sử dụng tối ưu hóa cuộc gọi đuôi không?
- 5. Có thể tối ưu hóa cuộc gọi đuôi và RAII cùng tồn tại?
- 6. Tại sao mã này ngăn chặn gcc & llvm từ tối ưu hóa cuộc gọi đuôi?
- 7. GHC có thể kết nối cuộc gọi tối ưu hóa các hành động IO không?
- 8. Trạng thái hiện tại của tối ưu hóa cuộc gọi đuôi cho F # trên Mono (2.11) là gì?
- 9. Có bất kỳ đuôi đuôi động cơ Javascript nào được tối ưu hóa không?
- 10. Tôi có thể xây dựng một cuộc gọi đuôi được gọi là biểu thức tối ưu đệ quy không?
- 11. Tại sao tối ưu hóa cuộc gọi đuôi không được sử dụng trong chương trình Haskell này?
- 12. Cách tối ưu hóa để thực hiện RPC trong .Net
- 13. Scala có hỗ trợ tối ưu đệ quy đuôi không?
- 14. Tối ưu hóa nào là OK để thực hiện ngay?
- 15. Chức năng foldl được viết lại của tôi có được tối ưu hóa không?
- 16. Tối ưu hóa được quản lý cho các cuộc gọi gốc
- 17. Tối ưu hóa một cuộc gọi chức năng lưu trữ trong điều khoản SELECT và ĐÂU
- 18. Tối ưu hóa các cuộc gọi tiếp theo đến số nguyên và modulo (phần còn lại)
- 19. Có thể tối ưu hóa ASP.NET WebForms để thực hiện nhanh như ASP.NET MVC không?
- 20. Tối ưu hóa Java: biến cục bộ hoặc gọi hàm
- 21. Tối ưu hóa một haversine thức gọi SQL trong PHP
- 22. Có thể constexpr chức năng đánh giá làm đuôi đệ quy tối ưu hóa
- 23. Có thể tối ưu hóa chức năng này không?
- 24. Tôi có hiểu chính xác tối ưu hóa sớm không?
- 25. Loại bỏ cuộc gọi đuôi ở Clojure?
- 26. Trong .NET, các cuộc gọi phương thức trống sẽ được tối ưu hóa?
- 27. Return Value Tối ưu hóa - C++ - Destructor gọi
- 28. Làm cách nào để tắt tối ưu hóa đuôi trong gcc
- 29. Tối ưu hóa CVPixelBufferRef
- 30. Tối ưu hóa ABAP
Tiêu đề câu hỏi của bạn là điều đầu tiên mọi người nhìn thấy và “TCO” chỉ là một TLA khác. –
Cần phải đề cập rằng Scala có TCO và một số JVM (như IBM) cũng thực hiện nó. – Landei
@Landei là một tính năng mới trong Scala? TCO đã không được hỗ trợ ở Scala trong thời gian dài! – haskelline