Các ngôn ngữ lập trình chức năng có nhiều cơ hội hơn để thực hiện tối ưu hóa thời gian biên dịch không?


10

Tôi đang đọc cuốn sách "Lập trình chức năng cho thế giới thực". Nó bắt đầu với việc so sánh giữa các ngôn ngữ lập trình mệnh lệnh và chức năng. Và nó đã cho biết 'giá trị' và 'biểu thức' trong lập trình chức năng khác với 'biến' và 'hàm' của lập trình mệnh lệnh như thế nào. Từ cuộc thảo luận tôi đã phát triển một ý tưởng rằng -

Các ngôn ngữ lập trình hàm có nhiều cơ hội để thực hiện tối ưu hóa thời gian hơn so với các đối tác bắt buộc của chúng.

Có đúng không

Câu trả lời:


16

Các ngôn ngữ lập trình hàm thực hiện tối ưu hóa thời gian biên dịch nhiều hơn. Một trong những lý do là độ tinh khiết - đồng thời là tầm thường vì không có trạng thái. Vì vậy, trình biên dịch có thể lấy hai nhánh và đồng hóa chúng một cách dễ dàng mà không thay đổi hành vi của chương trình.

Đồng thời, mọi thứ có thể được tính mà không có trạng thái (nghĩa là bất cứ thứ gì không đơn điệu trong haskell) đều có thể được tính toán trước bởi trình biên dịch, nhưng các tính toán như vậy có thể tốn kém và do đó có lẽ chỉ được thực hiện một phần.

Ngoài ra, mọi thứ không cần tính toán đều có thể được tối ưu hóa hoàn toàn khỏi chương trình.


1
+1: Lập trình miễn phí hiệu ứng phụ rất, rất dễ tối ưu hóa.
S.Lott

@mathepic: thực sự sự song song hóa (trong Haskell) xảy ra ở cả thời gian biên dịch và thời gian chạy. Thời gian biên dịch quyết định xem có đáng để tạo phân đoạn (hạt giống luồng) và quy trình thời gian chạy phân đoạn hay không , tùy thuộc vào số lượng luồng bạn đã chỉ định. Nếu bạn chỉ chỉ định một chủ đề, các phân đoạn sẽ được tạo, nhưng chúng được xử lý lần lượt từng luồng.
Matthieu M.

2
@mathepic: một cách sử dụng khác của sự thuần khiết -> sự lười biếng và sự vắng mặt của tính toán. Nếu bạn có thể chứng minh rằng giá trị là không cần thiết, thì hãy loại bỏ hoàn toàn tính toán. Nếu nó có thể là cần thiết, sử dụng một thunk lười biếng. Nếu bạn biết nó sẽ cần thiết, hãy tính toán thẳng về phía trước (để tránh tình trạng lười biếng trên cao). Độ tinh khiết là (chỉ) tuyệt vời :)
Matthieu M.

@Matthieu điểm tốt
thay thế

1
@Masse Ngay cả đơn vị IO là thuần túy. Nó chỉ là kết quả của việc "chạy" đơn vị IO là không.
thay thế

7

Về nguyên tắc, có nhiều khả năng tối ưu hóa thời gian biên dịch cho các ngôn ngữ chức năng hơn so với các đối tác bắt buộc của chúng có lẽ là đúng.

Mặc dù vậy, điều thú vị hơn là, nếu chúng thực sự được triển khai trong các trình biên dịch hiện tại và mức độ tối ưu hóa của các ứng dụng này trong thực tế (nghĩa là hiệu suất cuối cùng của mã 'đời thực (TM)' trong môi trường sản xuất, với các cài đặt trình biên dịch có thể dự đoán trước).

ví dụ như các bản đệ trình Haskell cho khét tiếng Computer Language Benchmark game (xấu như nó có thể là - nhưng nó không phải là như vậy có - vào lúc này - bất cứ điều gì đáng kể tốt hơn trên mạng) cho ấn tượng rằng một số lượng đáng kể thời gian đã được chi tiêu trên tối ưu hóa thủ công, đối mặt với tuyên bố về "tối ưu hóa trình biên dịch có thể do insert some property about FP languages here" làm cho nó trông giống như tối ưu hóa (hiện tại ít nhất) nhiều khả năng lý thuyết hơn là thực tế có liên quan.

Tôi sẽ rất vui khi được chứng minh là sai về điểm này.


1
Lý do tối ưu hóa thủ công trong Haskell có liên quan nhiều hơn đến thực tế là một số thao tác "đơn giản" nhất định có phần tốn thời gian (từ góc độ phức tạp) trong Haskell. Ví dụ: giả sử bạn muốn lấy phần tử cuối cùng của danh sách. Trong Java, đó là một hoạt động khá đơn giản; trong Haskell, cách tiếp cận ngây thơ yêu cầu bạn đi bộ toàn bộ danh sách cho đến khi bạn kết thúc (do tính chất lười biếng của danh sách), biến nó thành một hoạt động O (n). Đó là (một phần) khi tối ưu hóa thủ công.
mipadi

2
Tôi chắc chắn rằng có những lý do hợp lệ cho việc tối ưu hóa cuộn tay của Haskell, nhưng chúng cần thiết cho các hoạt động "đơn giản" mang lại ấn tượng rằng các cơ hội lớn hơn để tối ưu hóa mã (hiện tại) chỉ có liên quan trên lý thuyết.
Alexander Battisti

6
Đó là sự khác biệt giữa tối ưu hóa thuật toán và tối ưu hóa mã được tạo. Lấy một ví dụ C: nếu tôi đang viết một thuật toán tìm kiếm, tôi có thể viết một thuật toán ngây thơ chỉ đơn giản là đi qua một danh sách hoặc tôi có thể sử dụng tìm kiếm nhị phân. Trong cả hai trường hợp, trình biên dịch sẽ tối ưu hóa mã của tôi, nhưng nó sẽ không biến thuật toán tìm kiếm ngây thơ thành tìm kiếm nhị phân. Rất nhiều tối ưu hóa thủ công trong mã Haskell có liên quan nhiều hơn đến việc tự tối ưu hóa các thuật toán, thay vì tối ưu hóa mã được tạo.
mipadi

2
@mipadi, nhưng có vẻ như phiên bản đơn giản của thuật toán Haskell không tốt bằng phiên bản đơn giản của thuật toán của các ngôn ngữ khác. (Tôi nghi ngờ do sự không phù hợp giữa mô hình chức năng và kiến ​​trúc máy tính) Ngay cả khi nó tạo mã tốt, nó không đủ để khắc phục vấn đề này.
Winston Ewert

>> xấu như nó có thể là << - Bạn có biết nó xấu hay không? Bạn thậm chí có ý gì khi cho rằng nó "xấu"? Hãy cụ thể.
igouy

2

Trong phong cách chức năng, luồng giá trị thông qua một chương trình là rất, rất rõ ràng (cho cả trình biên dịch và lập trình viên). Điều này cung cấp cho trình biên dịch rất nhiều thời gian để quyết định nơi lưu trữ các giá trị, thời gian giữ chúng xung quanh, v.v.

Trong một ngôn ngữ bắt buộc, trình biên dịch hứa hẹn cho lập trình viên một mô hình trong đó hầu hết các biến tương ứng với các vị trí thực tế trong bộ nhớ tồn tại trong suốt vòng đời xác định. Có khả năng, bất kỳ câu lệnh nào cũng có thể đọc từ (hoặc ghi vào!) Bất kỳ vị trí nào trong số các vị trí này, vì vậy trình biên dịch chỉ có thể thay thế các vị trí bộ nhớ bằng phân bổ đăng ký, hợp nhất hai biến vào một vị trí lưu trữ hoặc thực hiện tối ưu hóa tương tự sau khi thực hiện phân tích khó khăn về nơi khác trong chương trình mà biến có thể được tham chiếu.

Bây giờ, có hai hãy cẩn thận:

  • Cộng đồng ngôn ngữ lập trình đã dành (lãng phí?) Rất nhiều nỗ lực trong năm mươi năm qua để phát triển các cách thông minh để thực hiện phân tích này. Có những thủ thuật nổi tiếng như đăng ký tô màu và vv để có được một số trường hợp dễ dàng hơn được thực hiện hầu hết thời gian; nhưng điều này làm cho các trình biên dịch lớn, chậm và sự đánh đổi liên tục về độ phức tạp của quá trình biên dịch đối với chất lượng của mã kết quả
  • Đồng thời, hầu hết các ngôn ngữ lập trình chức năng cũng không hoàn toàn là chức năng; rất nhiều điều mà các chương trình thực sự cần làm, như trả lời I / O vốn không có chức năng, vì vậy không có trình biên dịch nào có thể hoàn toàn không có các thủ thuật này và không có ngôn ngữ nào tránh được chúng hoàn toàn - ngay cả Haskell, cũng hơi khó hoàn toàn phù hợp với sở thích của tôi (Your Mileage May Vary) chỉ có thể kiểm soát và loại bỏ các phần không có chức năng trong mã của bạn, không thể tránh chúng hoàn toàn.

Nhưng để trả lời câu hỏi chung, vâng, một mô hình chức năng cung cấp cho trình biên dịch rất nhiều sự tự do để tối ưu hóa mà nó không có trong một thiết lập bắt buộc.


Mọi thứ trong Haskell đều hoạt động, chỉ có điều bạn mainlà một hàm biến đổi trạng thái chứ không phải là thứ sử dụng chính trạng thái đó.
thay thế

Có và không - về mặt khái niệm, hoàn toàn chính xác khi nói rằng chương trình Haskell là một chức năng thuần túy đối với các tương tác của người dùng với chương trình đó (và trạng thái của trình tạo số ngẫu nhiên của hệ thống và độ trễ của mạng ngày nay và bất kỳ điều gì khác vốn có đầu vào phi chức năng mà chương trình đáp ứng), nhưng trong thực tế, đó là một sự khác biệt không có sự khác biệt.
jimwise

@jimwise Độ trong suốt tham chiếu là một sự khác biệt rất lớn.
thay thế

Ngoại trừ việc bạn không thực sự có nó, ít nhất là cho mục đích được thảo luận ở đây. Điểm của các hoạt động như IO, hoặc tạo số ngẫu nhiên, là chúng sẽ trả về một giá trị khác nhau mỗi lần chúng được gọi với cùng một đầu vào và điều này vốn hạn chế lý luận về chúng theo chức năng, cho cả lập trình viên hoặc trình biên dịch.
jimwise

1
@mathepic Có, tất nhiên, về mặt khái niệm bạn có thể xem tính ngẫu nhiên hoặc đầu vào của người dùng (hoặc độ trễ mạng hoặc tải hệ thống) dưới dạng luồng vô hạn hoặc chức năng từ trạng thái này sang trạng thái khác, nhưng đó không phải là quan điểm cho vay lý do hữu ích về hành vi chương trình bạn hoặc trình biên dịch của bạn - Bob Harper trình bày rõ về vấn đề này trong một bài đăng gần đây trên blog của anh ấy về chương trình giảng dạy CS đầu tiên về lập trình chức năng của CMU.
jimwise
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.