Chính xác thì lập trình siêu hình là gì?


128

Tôi đang đọc một bài báo trên TheServerSide về lập trình ployglot trên nền tảng Java . Một số nhận xét trong bài viết đề cập đến lập trình siêu ứng dụng như khả năng tạo mã (có thể là đang bay).

Siêu lập trình có phải là khả năng tạo mã một cách nhanh chóng hay đó là khả năng đưa các phương thức và thuộc tính vào các đối tượng hiện có trong thời gian chạy (giống như những gì một số ngôn ngữ động như Python, Ruby và Groovy cho phép).


7
Bạn có thể quan tâm đến câu trả lời này stackoverflow.com/questions/2565572/…
ewernli

@ewernli: Câu trả lời đó thực sự tốt hơn bất kỳ câu trả lời nào ở đây!
JD

Câu trả lời:


100

Siêu lập trình đề cập đến nhiều cách khác nhau mà một chương trình có kiến ​​thức về chính nó hoặc có thể tự thao tác.

Trong các ngôn ngữ như C #, phản xạ là một dạng lập trình siêu hình vì chương trình có thể kiểm tra thông tin về chính nó. Ví dụ: trả về một danh sách tất cả các thuộc tính của một đối tượng.

Trong các ngôn ngữ như ActionScript, bạn có thể đánh giá các hàm trong thời gian chạy để tạo các chương trình mới như eval ("x" + i). DoSomething () sẽ ảnh hưởng đến một đối tượng được gọi là x1 khi tôi là 1 và x2 khi tôi là 2.

Cuối cùng, một hình thức phổ biến khác của siêu lập trình là khi chương trình có thể tự thay đổi theo kiểu không tầm thường. LISP nổi tiếng về điều này và là thứ mà Paul Graham đã vô địch khoảng một thập kỷ trước. Tôi sẽ phải tra cứu một số bài luận cụ thể của anh ấy. Nhưng ý tưởng là chương trình sẽ thay đổi một phần khác của chương trình dựa trên trạng thái của nó. Điều này cho phép một mức độ linh hoạt để đưa ra quyết định trong thời gian chạy vốn rất khó trong hầu hết các ngôn ngữ phổ biến hiện nay.

Cũng cần lưu ý rằng trong thời kỳ tốt đẹp của việc lập trình trong lắp ráp thẳng, các chương trình tự thay đổi trong thời gian chạy là cần thiết và rất phổ biến.

Từ bài luận của Paul Graham "Điều gì đã làm cho Lisp khác biệt" :

Nhiều ngôn ngữ có một thứ gọi là macro. Nhưng macro Lisp là duy nhất. Và bạn có tin hay không, những gì họ làm đều liên quan đến dấu ngoặc đơn. Các nhà thiết kế của Lisp đã không đặt tất cả các dấu ngoặc đơn đó trong ngôn ngữ chỉ để khác biệt. Đối với lập trình viên Blub, mã Lisp trông rất kỳ lạ. Nhưng những dấu ngoặc đơn đó là có lý do. Chúng là bằng chứng bên ngoài về sự khác biệt cơ bản giữa Lisp và các ngôn ngữ khác.

Mã Lisp được tạo ra từ các đối tượng dữ liệu Lisp. Và không phải theo nghĩa tầm thường mà các tệp nguồn chứa các ký tự và chuỗi là một trong những kiểu dữ liệu được ngôn ngữ hỗ trợ. Mã Lisp, sau khi được trình phân tích cú pháp đọc, được tạo ra từ các cấu trúc dữ liệu mà bạn có thể duyệt qua.

Nếu bạn hiểu cách thức hoạt động của các trình biên dịch, thì điều thực sự đang diễn ra không quá nhiều đến mức Lisp có cú pháp kỳ lạ vì Lisp không có cú pháp. Bạn viết chương trình trong cây phân tích cú pháp được tạo trong trình biên dịch khi các ngôn ngữ khác được phân tích cú pháp. Nhưng những cây phân tích cú pháp này hoàn toàn có thể truy cập được vào các chương trình của bạn. Bạn có thể viết các chương trình thao tác với chúng. Trong Lisp, các chương trình này được gọi là macro. Chúng là những chương trình viết chương trình.

Chương trình viết chương trình? Bao giờ bạn muốn làm điều đó? Không thường xuyên lắm, nếu bạn nghĩ trong Cobol. Mọi lúc, nếu bạn nghĩ trong Lisp. Sẽ rất tiện lợi ở đây nếu tôi có thể đưa ra một ví dụ về một macro mạnh mẽ và nói ở đó! làm thế nào về điều đó? Nhưng nếu tôi làm vậy, nó sẽ giống như vô nghĩa đối với một người không biết Lisp; ở đây không có chỗ để giải thích mọi thứ bạn cần biết để hiểu ý nghĩa của nó. Trong Ansi Common Lisp, tôi đã cố gắng di chuyển mọi thứ nhanh nhất có thể, và thậm chí vì vậy tôi không đến được macro cho đến trang 160.

Nhưng tôi nghĩ tôi có thể đưa ra một loại lập luận có thể thuyết phục. Mã nguồn của trình soạn thảo Viaweb có lẽ khoảng 20-25% macro. Macro khó viết hơn các hàm Lisp thông thường và việc sử dụng chúng khi không cần thiết được coi là một phong cách tồi. Vì vậy, mọi macro trong mã đó đều ở đó bởi vì nó phải có. Điều đó có nghĩa là ít nhất 20-25% mã trong chương trình này đang làm những việc mà bạn không thể dễ dàng thực hiện bằng bất kỳ ngôn ngữ nào khác. Tuy nhiên, lập trình viên Blub hoài nghi có thể về những tuyên bố của tôi đối với sức mạnh bí ẩn của Lisp, điều này hẳn khiến anh ta tò mò. Chúng tôi không viết mã này để giải trí cho riêng mình. Chúng tôi là một công ty khởi nghiệp nhỏ, lập trình hết sức có thể để tạo ra rào cản kỹ thuật giữa chúng tôi và các đối thủ cạnh tranh.

Một người khả nghi có thể bắt đầu tự hỏi liệu có mối tương quan nào đó ở đây không. Một phần lớn mã của chúng tôi đang làm những điều rất khó làm bằng các ngôn ngữ khác. Phần mềm kết quả đã làm được những điều mà phần mềm của đối thủ cạnh tranh của chúng tôi không làm được. Có thể có một số loại kết nối. Tôi khuyến khích bạn làm theo chủ đề đó. Có thể có nhiều điều ở ông lão tập tễnh trên đôi nạng hơn là nhìn thấy mắt.


6
Đừng quên về lập trình siêu mẫu trong C ++. Khả năng thực thi các biểu thức và đưa ra quyết định tại thời điểm biên dịch và kết quả được biên dịch tĩnh thành tệp thực thi cuối cùng.
Remy Lebeau

1
Tôi đã bị sốc bởi in order to put technical barriers between us and our competitorsvà điều này là chính xác.
Evan Hu

4
Các chương trình tự thao tác là một tập hợp con của tất cả các chương trình siêu hình. Metaprogramming nói chung chỉ có nghĩa là chương trình thao tác với chương trình.
JD

55

Câu hỏi tuyệt vời. Tôi rất tiếc khi thấy rằng không có câu trả lời nào hiện thực sự trả lời đúng câu hỏi của bạn. Có lẽ tôi có thể giúp ...

Định nghĩa của siêu chương trình thực sự khá đơn giản: nó có nghĩa là chương trình thao tác với chương trình.

Câu trả lời được chấp nhận của bạn cho biết các chương trình tự thao túng. Đó thực sự là những siêu chương trình nhưng chúng là một tập hợp con của tất cả các siêu chương trình.

Tất cả:

  • Trình phân tích cú pháp
  • Ngôn ngữ cụ thể của miền (DSL)
  • Các ngôn ngữ cụ thể của miền được nhúng (EDSL)
  • Trình biên dịch
  • Thông dịch viên
  • Người viết lại thuật ngữ
  • Trình duyệt định lý

là các chương trình siêu hình. Vì vậy, trình biên dịch GCC là một siêu chương trình, trình thông dịch CPython là một siêu chương trình, hệ thống đại số máy tính Mathematica là một siêu chương trình, câu tục ngữ định lý Coq là một siêu chương trình, v.v.

Các câu trả lời khác đã khẳng định rằng siêu chương trình là chương trình tạo ra các chương trình khác. Đó thực sự là những siêu chương trình nhưng, một lần nữa, chúng là một tập hợp con của tất cả các siêu chương trình. Các nhanh nhất Fourier Transform ở phương Tây (FFTW) thư viện là một ví dụ về metaprogram như vậy. Mã nguồn được viết chủ yếu bằng OCaml và nó tạo ra các bit của mã C (được gọi là codones) được kết hợp để tạo ra các quy trình Fast Fourier Transform hiệu suất cao được tối ưu hóa cho các máy cụ thể. Thư viện đó thực sự được sử dụng để cung cấp các quy trình FFT trong Matlab. Mọi người đã viết các chương trình để tạo ra các phương pháp số trong nhiều thập kỷ, kể từ những ngày đầu của FORTRAN .

Ngôn ngữ lập trình đầu tiên hỗ trợ tích hợp cho lập trình siêu mẫu là ngôn ngữ Bộ xử lý LISt (LISP) vào cuối những năm 1950. LISP 1.5 bao gồm một số tính năng giúp cho việc lập trình siêu ứng dụng trở nên dễ dàng hơn. Thứ nhất, kiểu dữ liệu cốt lõi của LISP là các danh sách lồng nhau, tức là dạng cây (a (b c) d), có nghĩa là bất kỳ mã LISP nào cũng có thể được thể hiện nguyên bản dưới dạng cấu trúc dữ liệu. Điều này được gọi là sự đồng nhất. Thứ hai, mã LISP có thể được chuyển đổi thành dữ liệu một cách dễ dàng bằng QUOTE. Ví dụ (+ 1 2 3)thêm 1 + 2 + 3 và (QUOTE (+ 1 2 3))tạo biểu thức thêm 1 + 2 + 3 khi được đánh giá. Thứ ba, LISP đã cung cấp trình đánh giá siêu vòng tròn cho phép bạn sử dụng trình thông dịch hoặc trình biên dịch máy chủ để đánh giá mã LISP tại thời điểm chạy, bao gồm mã LISP được tạo trong thời gian chạy. Con cháu của LISP bao gồm SchemeClojure. Trong tất cả các ngôn ngữ này, lập trình siêu chương thường thấy nhất ở dạng các chương trình tự sửa đổi, thường sử dụng macro.

Vào những năm 1970, Robin Milner đã phát triển một MetaLanguage (ML) phát triển thành họ ngôn ngữ lập trình ML bao gồm Standard MLOCaml và ảnh hưởng mạnh mẽ đến HaskellF # . Những ngôn ngữ này giúp bạn dễ dàng diễn đạt các ngôn ngữ khác. Trong các ngôn ngữ này, các siêu chương trình thường được nhìn thấy nhiều nhất ở dạng lexers, parser, thông dịch và biên dịch.

Năm 1994, Erwin Unruh phát hiện ra rằng hệ thống khuôn mẫu C ++ đã hoàn chỉnh và có thể được sử dụng để thực thi các chương trình tùy ý tại thời điểm biên dịch . Lập trình siêu chương trình theo mẫu C ++ đã mang siêu chương trình đến với những người chưa được rửa sạch, những người (ab) đã sử dụng nó cho nhiều việc khác nhau bao gồm việc tạo ra các phương thức số trong thư viện Blitz ++ .


33

Chà, siêu lập trình chỉ là lập trình, nhưng về cơ bản nó là "viết mã viết mã" .

Khả năng mà bạn đề cập, khi một chương trình có thể quan sát và sửa đổi cấu trúc cũng như hành vi của chính nó được gọi là phản xạ và đó là một kiểu lập trình siêu hình.

Các ngôn ngữ được nhập động, có các tính năng phản ánh thời gian chạy mạnh mẽ, được thực hiện nhờ bản chất thông dịch của các ngôn ngữ này ...

Các ngôn ngữ được định kiểu tĩnh cũng có các kỹ thuật lập trình siêu ứng dụng mạnh mẽ, ví dụ: lập trình siêu chương trình mẫu C ++ ...


14

Đây chỉ là ý kiến ​​cá nhân của tôi, có lẽ là định nghĩa tự do nhất về lập trình siêu hình.

Tôi nghĩ nó bao gồm:

  1. Biên dịch tạo mã hoặc tạo mã Thời gian chạy (hoặc cả hai)
  2. Tư duy định hướng theo khía cạnh hoặc lập trình định hướng theo khía cạnh
  3. Suy nghĩ KHÔ

Tôi nghĩ bạn có thể đạt được điều đó bằng cách sử dụng bất kỳ cái nào trong số này và kết hợp:

  1. Suy ngẫm
  2. DSL (Ngôn ngữ dành riêng cho miền)
  3. Thuộc tính (.NET) hoặc Chú thích (Java)
  4. Generics (.NET / Java)
  5. Mẫu (C ++)
  6. method_missing (Ruby)
  7. đóng cửa / hàm lớp đầu tiên / đại biểu
  8. AOP - Lập trình hướng theo khía cạnh

câu trả lời rất ngắn gọn và chu đáo. đã cho tôi một thực đơn tốt về những thứ cần điều tra. cảm ơn bạn!
swyx

6

Siêu lập trình là viết một chương trình xuất ra một chương trình khác. Đây là thứ mà các ngôn ngữ như Lisp thực sự giỏi. Việc thực hiện bằng ngôn ngữ hỗ trợ macro thực (không phải macro C ++ mà là những macro có thể thao tác mã mà chúng xuất ra) như Ruby, Lisp, Scheme, v.v. sẽ dễ dàng hơn nhiều so với ngôn ngữ như Java.

Một cách triển khai là tạo "ngôn ngữ dành riêng cho miền", đây là một cách nâng cao ngôn ngữ lập trình để hoàn thành một nhiệm vụ cụ thể. Nó có thể cực kỳ mạnh mẽ nếu được thực hiện đúng cách. Ruby on Rails là một ví dụ điển hình về kiểu lập trình này.

Nếu bạn muốn khám phá phương pháp này, hãy xem Cấu trúc và Diễn giải các Chương trình Máy tính , đây là một trong những cuốn sách chuyên sâu về chủ đề này.


5

Siêu lập trình là việc viết các chương trình máy tính viết hoặc thao tác các chương trình khác (hoặc chính chúng) dưới dạng dữ liệu của chúng hoặc thực hiện một phần công việc trong thời gian chạy mà nếu không sẽ được thực hiện tại thời điểm biên dịch. Trong nhiều trường hợp, điều này cho phép các lập trình viên hoàn thành nhiều việc hơn trong cùng một khoảng thời gian như họ sẽ viết tất cả mã theo cách thủ công hoặc nó cung cấp cho các chương trình sự linh hoạt hơn để xử lý hiệu quả các tình huống mới mà không cần biên dịch lại. ( Nguồn .)

Về cơ bản, nó viết mã tạo ra nhiều mã hơn, được chạy để hoàn thành một số mục tiêu. Điều này thường được thực hiện trong cùng một ngôn ngữ (sử dụng javascript để tạo chuỗi javascript, sau đó sử dụng evalnó) hoặc để phát ra một ngôn ngữ khác (sử dụng .NET để tạo tệp loạt cửa sổ).


4

wikipedia có một bài viết hay về chủ đề này. Người ta không phải sửa đổi thời gian chạy cho một thứ gì đó để đủ điều kiện là lập trình siêu ứng dụng. Ví dụ, nhiều người sử dụng các mẫu C ++ để thực hiện lập trình siêu ứng dụng tại thời điểm biên dịch.

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.