Tình trạng triển khai Lập trình phản ứng chức năng hiện tại là gì?


90

Tôi đang cố gắng hình dung một số hệ thống vật lý tự động đơn giản (chẳng hạn như con lắc, cánh tay robot, v.v.) trong Haskell. Thường thì những hệ thống đó có thể được mô tả bằng các phương trình như

df/dt = c*f(t) + u(t)

nơi u(t)đại diện cho một số loại 'điều khiển thông minh'. Những hệ thống đó trông rất phù hợp trong mô hình Lập trình phản ứng chức năng.

Vì vậy, tôi lấy cuốn sách "Trường phái biểu hiện Haskell" của Paul Hudak và nhận thấy rằng ngôn ngữ cụ thể của miền "FAL" (dành cho Ngôn ngữ hoạt hình chức năng) được trình bày ở đó thực sự hoạt động khá dễ chịu đối với các hệ thống đồ chơi đơn giản của tôi (mặc dù một số chức năng, đáng chú ý là integrate, dường như hơi lười biếng để sử dụng hiệu quả, nhưng có thể sửa chữa dễ dàng).

Câu hỏi của tôi là, đâu là giải pháp thay thế hoàn thiện hơn, cập nhật, được duy trì tốt, được điều chỉnh hiệu suất cho các ứng dụng tiên tiến hơn hoặc thậm chí thực tế ngày nay?

Trang wiki này liệt kê một số tùy chọn cho Haskell, nhưng tôi không rõ về các khía cạnh sau:

  1. Trạng thái "phản ứng", dự án của Conal Eliott, (theo tôi hiểu), một trong những người phát minh ra mô hình lập trình này, trông hơi cũ. Tôi thích mã của anh ấy, nhưng có lẽ tôi nên thử các lựa chọn thay thế cập nhật hơn? Sự khác biệt chính giữa chúng là gì, về cú pháp / hiệu suất / thời gian chạy-ổn định?

  2. Trích dẫn từ một cuộc khảo sát vào năm 2011, Phần 6, " ... Việc triển khai FRP vẫn không đủ hiệu quả hoặc không đủ khả năng dự đoán về hiệu suất để được sử dụng hiệu quả trong các miền yêu cầu đảm bảo độ trễ ... ". Mặc dù cuộc khảo sát gợi ý một số cách tối ưu hóa thú vị có thể xảy ra, với thực tế là FRP đã tồn tại hơn 15 năm, tôi có ấn tượng rằng vấn đề hiệu suất này có thể là một thứ gì đó rất hoặc thậm chí vốn dĩ rất khó giải quyết ít nhất là trong vòng vài năm. Điều này có đúng không?

  3. Cùng một tác giả của cuộc khảo sát nói về "rò rỉ thời gian" trong blog của mình . Có phải vấn đề là duy nhất đối với FRP hay vấn đề mà chúng ta thường gặp phải khi lập trình bằng một ngôn ngữ thuần túy, không nghiêm ngặt? Bạn đã bao giờ thấy quá khó để ổn định một hệ thống dựa trên FRP theo thời gian, nếu không đủ hiệu quả?

  4. Đây vẫn là một dự án cấp độ nghiên cứu? Những người như kỹ sư nhà máy, kỹ sư người máy, kỹ sư tài chính, v.v. có thực sự sử dụng chúng (bằng ngôn ngữ khác phù hợp với nhu cầu của họ) không?

Mặc dù cá nhân tôi thích triển khai Haskell hơn, nhưng tôi sẵn sàng đón nhận các đề xuất khác. Ví dụ, sẽ đặc biệt thú vị nếu triển khai Erlang --- sau đó sẽ rất dễ dàng để có một quy trình máy chủ thông minh, thích ứng, tự học!

Câu trả lời:


82

Hiện tại chủ yếu có hai thư viện Haskell thực tế để lập trình phản ứng chức năng. Cả hai đều được duy trì bởi những người duy nhất, nhưng cũng đang nhận được đóng góp mã từ các lập trình viên Haskell khác:

  • Netwire tập trung vào hiệu quả, tính linh hoạt và khả năng dự đoán. Nó có mô hình sự kiện riêng và có thể được sử dụng trong các khu vực mà FRP truyền thống không hoạt động, bao gồm các dịch vụ mạng và mô phỏng phức tạp. Phong cách: ứng dụng và / hoặc mũi tên. Tác giả và người duy trì ban đầu: Ertugrul Söylemez (đây là tôi).

  • Reative-banana xây dựng dựa trên mô hình FRP truyền thống. Mặc dù nó là thực tế để sử dụng nó cũng là nền tảng cho nghiên cứu FRP cổ điển. Trọng tâm chính của nó là giao diện người dùng và có một giao diện làm sẵn cho wx. Phong cách: ứng dụng. Tác giả ban đầu và người duy trì: Heinrich Apfelmus.

Bạn nên thử cả hai, nhưng tùy thuộc vào ứng dụng của bạn, bạn có thể sẽ thấy cái này hoặc cái kia phù hợp hơn.

Đối với trò chơi, mạng, điều khiển robot và mô phỏng, bạn sẽ thấy Netwire rất hữu ích. Nó đi kèm với dây làm sẵn cho các ứng dụng đó, bao gồm các vi sai hữu ích khác nhau, tích phân và rất nhiều chức năng để xử lý sự kiện minh bạch. Để có hướng dẫn, hãy truy cập tài liệu của Control.Wiremô-đun trên trang tôi đã liên kết.

Đối với giao diện đồ họa người dùng hiện tại, lựa chọn tốt nhất của bạn là phản ứng-chuối. Nó đã có một giao diện wx (như một thư viện riêng biệt react-banana-wx) và Heinrich viết rất nhiều về FRP trong ngữ cảnh này bao gồm cả các mẫu mã.

Để trả lời các câu hỏi khác của bạn: FRP không phù hợp trong các trường hợp mà bạn cần khả năng dự đoán theo thời gian thực. Điều này phần lớn là do Haskell, nhưng tiếc là FRP rất khó thực hiện trong các ngôn ngữ cấp thấp hơn. Ngay khi bản thân Haskell trở nên sẵn sàng theo thời gian thực, FRP cũng sẽ đến đó. Về mặt khái niệm, Netwire đã sẵn sàng cho các ứng dụng thời gian thực.

Rò rỉ thời gian thực sự không còn là vấn đề nữa, bởi vì chúng chủ yếu liên quan đến khuôn khổ đơn nguyên. Các triển khai FRP thực tế chỉ đơn giản là không cung cấp giao diện đơn nguyên. Yampa đã bắt đầu điều này và Netwire và react-banana đều xây dựng trên đó.

Tôi không biết hiện tại không có dự án thương mại hoặc quy mô lớn nào sử dụng FRP. Các thư viện đã sẵn sàng, nhưng tôi nghĩ mọi người vẫn chưa - chưa.


Câu trả lời tuyệt vời, cảm ơn .. sẽ là một bài tập thú vị khi triển khai một số thuật toán học tăng cường trên đầu thư viện của bạn.
mnish

3
Đáng chú ý, một trò chơi indie gần đây được viết bằng Haskell ( Nikki and the Robots ) đã đưa ra quyết định không sử dụng FRP.
Alex R

23

Mặc dù đã có một số câu trả lời hay, nhưng tôi sẽ cố gắng trả lời các câu hỏi cụ thể của bạn.

  1. phản ứng không thể sử dụng cho các dự án nghiêm trọng, do vấn đề rò rỉ thời gian. (xem # 3). Thư viện hiện tại có thiết kế tương tự nhất là react-banana, được phát triển với phản ứng như một nguồn cảm hứng và đang thảo luận với Conal Elliott.

  2. Mặc dù bản thân Haskell không thích hợp cho các ứng dụng thời gian thực cứng, nhưng có thể sử dụng Haskell cho các ứng dụng thời gian thực mềm trong một số trường hợp. Tôi không quen với nghiên cứu hiện tại, nhưng tôi không tin rằng đây là một vấn đề không thể vượt qua. Tôi nghi ngờ rằng một trong hai hệ thống như Yampa hoặc hệ thống tạo mã như Atom, có thể là cách tiếp cận tốt nhất để giải quyết vấn đề này.

  3. "Rò rỉ thời gian" là một vấn đề cụ thể đối với FRP có thể chuyển đổi. Rò rỉ xảy ra khi một hệ thống không thể giải phóng các đối tượng cũ vì nó có thể cần chúng nếu một công tắc xảy ra vào một thời điểm nào đó trong tương lai. Ngoài tình trạng rò rỉ bộ nhớ (có thể khá nghiêm trọng), một hậu quả khác là khi xảy ra chuyển đổi, hệ thống phải tạm dừng trong khi chuỗi các đối tượng cũ được duyệt qua để tạo ra trạng thái hiện tại.

Các thư viện frp không thể chuyển đổi như Yampa và các phiên bản cũ hơn của react-banana không bị rò rỉ thời gian. Các thư viện frp có thể chuyển đổi thường sử dụng một trong hai lược đồ: hoặc chúng có một "đơn nguyên tạo" đặc biệt trong đó các giá trị FRP được tạo hoặc chúng sử dụng một tham số kiểu "lão hóa" để giới hạn các ngữ cảnh trong đó chuyển mạch có thể xảy ra. elerea (và có thể là netwire?) sử dụng loại trước, trong khi chuối và bưởi phản ứng gần đây sử dụng loại sau.

Bằng "switchable frp", ý tôi là một trong đó thực hiện chức năng của Conal switcher :: Behavior a -> Event (Behavior a) -> Behavior a, hoặc ngữ nghĩa giống hệt nhau. Điều này có nghĩa là hình dạng của mạng có thể tự động chuyển đổi khi nó chạy.

Điều này không thực sự mâu thuẫn với tuyên bố của @ ertes về các giao diện đơn nguyên: nó chỉ ra rằng việc cung cấp một Monadphiên bản cho một Eventthời gian có thể làm rò rỉ thời gian và với một trong hai cách tiếp cận ở trên, không còn có thể xác định các phiên bản Monad tương đương.

Cuối cùng, mặc dù vẫn còn rất nhiều việc phải làm với FRP, tôi nghĩ rằng một số nền tảng mới hơn (react-banana, elerea, netwire) đủ ổn định và trưởng thành để bạn có thể xây dựng mã đáng tin cậy từ chúng. Nhưng bạn có thể cần phải dành nhiều thời gian để tìm hiểu những điều cần biết để hiểu cách đạt được hiệu suất tốt.


2
Liên quan đến các thư viện dựa trên mũi tên (Yampa, netwire), chúng cũng có thể chuyển đổi được. Lý do là vì các mũi tên đã được tích hợp sẵn lão hóa, bạn thực sự không thể loại bỏ nó. (Là máy biến áp dòng, mũi tên là thuyết bất khả tri về thời gian bắt đầu của dòng đầu vào của họ.)
Heinrich Apfelmus


1
@HeinrichApfelmus: đó là một điểm thú vị. Nhìn chung, tôi không nghĩ về các thư viện dựa trên mũi tên có thể chuyển đổi theo cách giống như elerea / bưởi / current-react-banana. Tôi nghĩ việc chuyển đổi của họ gần hơn rất nhiều so với những gì được yêu cầu trong các phiên bản trước đây của react-banana. Mặc dù vậy, đây chỉ là một cảm giác ruột, tôi chưa đủ suy nghĩ để mô tả ý tôi muốn nói.
John L

2
@DanBurton cảm ơn, tôi đã cố gắng không thành công để nhớ tên đó. Tôi đồng ý rằng natri nên được coi là một thư viện FRP hiện đại, mặc dù nó không phổ biến như chuối phản ứng.
John L

Mặc dù cuộc thảo luận đang diễn ra hơi khó theo dõi, nhưng có vẻ như chỉ ra rằng hệ thống thời gian thực mềm thực sự có thể thực hiện được, miễn là thời gian GC có thể bị giới hạn theo một cách nào đó. Dù sao cảm ơn cho câu trả lời tuyệt vời của bạn.
mnish

20

Tôi sẽ liệt kê một vài mục trong không gian Mono và .Net và một mục từ không gian Haskell mà tôi đã tìm thấy cách đây không lâu. Tôi sẽ bắt đầu với Haskell.

Elm - liên kết

Mô tả của nó theo trang web của nó:

Elm nhằm mục đích làm cho việc phát triển web front-end trở nên dễ chịu hơn. Nó giới thiệu một cách tiếp cận mới đối với lập trình GUI để khắc phục các vấn đề hệ thống của HTML, CSS và JavaScript. Elm cho phép bạn nhanh chóng và dễ dàng làm việc với bố cục trực quan, sử dụng canvas, quản lý thông tin nhập liệu phức tạp của người dùng và thoát khỏi địa ngục gọi lại.

Nó có biến thể FRP riêng . Từ việc chơi với các ví dụ của nó, nó có vẻ khá thuần thục.

Tiện ích mở rộng phản ứng - liên kết

Mô tả từ trang đầu của nó:

Phần mở rộng phản ứng (Rx) là một thư viện để soạn các chương trình không đồng bộ và dựa trên sự kiện bằng cách sử dụng các trình tự có thể quan sát và toán tử truy vấn kiểu LINQ. Sử dụng Rx, các nhà phát triển đại diện cho các luồng dữ liệu không đồng bộ bằng Observables, truy vấn các luồng dữ liệu không đồng bộ bằng cách sử dụng toán tử LINQ và tham số hóa đồng thời trong các luồng dữ liệu không đồng bộ bằng Bộ lập lịch. Nói một cách đơn giản, Rx = Observables + LINQ + Schedulers.

Reactive Extensions đến từ MSFT và triển khai nhiều toán tử tuyệt vời giúp đơn giản hóa việc xử lý các sự kiện. Nó đã được mở nguồn chỉ vài ngày trước. Nó rất trưởng thành và được sử dụng trong sản xuất; theo ý kiến ​​của tôi, nó sẽ là một API đẹp hơn cho các API Windows 8 so với TPL-library cung cấp; bởi vì các đối tượng quan sát có thể vừa nóng vừa lạnh và được thử lại / hợp nhất, v.v., trong khi các tác vụ luôn thể hiện các tính toán nóng hoặc đã thực hiện đang chạy, bị lỗi hoặc đã hoàn thành.

Tôi đã viết mã phía máy chủ bằng cách sử dụng Rx cho không đồng bộ, nhưng tôi phải thừa nhận rằng việc viết theo chức năng trong C # có thể hơi khó chịu. F # có một số trình bao bọc, nhưng thật khó để theo dõi sự phát triển API, vì nhóm này tương đối kín và không được MSFT thúc đẩy như các dự án khác.

Nguồn mở của nó đi kèm với nguồn mở của trình biên dịch IL-to-JS, vì vậy nó có thể hoạt động tốt với JavaScript hoặc Elm.

Bạn có thể liên kết F # / C # / JS / Haskell với nhau rất tốt bằng cách sử dụng một trình môi giới tin nhắn, như RabbitMQ và SocksJS.

Bling UI Toolkit - liên kết

Mô tả từ trang đầu của nó:

Bling là một thư viện dựa trên C # để dễ dàng lập trình hình ảnh, hoạt ảnh, tương tác và trực quan trên WPF / .NET của Microsoft. Bling hướng tới các nhà công nghệ thiết kế, tức là các nhà thiết kế đôi khi lập trình, để hỗ trợ việc tạo mẫu nhanh chóng các ý tưởng thiết kế giao diện người dùng phong phú. Sinh viên, nghệ sĩ, nhà nghiên cứu và những người yêu thích cũng sẽ thấy Bling hữu ích như một công cụ để nhanh chóng thể hiện ý tưởng hoặc hình dung. Các API và cấu trúc của Bling được tối ưu hóa cho việc lập trình nhanh mã lệnh vứt bỏ thay vì lập trình cẩn thận mã sản xuất.

Bài báo LtU miễn phí .

Tôi đã thử nghiệm điều này, nhưng không làm việc với nó cho một dự án khách hàng. Nó trông tuyệt vời, có tính năng nạp chồng toán tử C # đẹp mắt tạo thành các ràng buộc giữa các giá trị. Nó sử dụng các thuộc tính phụ thuộc trong WPF / SL / (WinRT) làm nguồn sự kiện. Hình ảnh động 3D của nó hoạt động tốt trên phần cứng hợp lý. Tôi sẽ sử dụng điều này nếu tôi kết thúc một dự án cần hình dung; có thể chuyển nó sang Windows 8.

ReactiveUI - liên kết

Paul Betts, trước đây làm việc tại MSFT, bây giờ tại Github, đã viết khuôn khổ đó. Tôi đã làm việc với nó khá rộng rãi và thích mô hình. Nó được tách rời nhiều hơn Blink (về bản chất là sử dụng Rx và các phần trừu tượng của nó) - giúp dễ dàng hơn để đơn vị mã kiểm tra bằng cách sử dụng nó. Ứng dụng khách github git cho Windows được viết bằng này.

Bình luận

Mô hình phản ứng đủ hoạt động cho hầu hết các ứng dụng đòi hỏi hiệu suất. Nếu bạn đang nghĩ về thời gian thực khó, tôi cá rằng hầu hết các ngôn ngữ GC đều có vấn đề. Rx, ReactiveUI tạo ra một số đối tượng nhỏ cần được GCed, vì đó là cách các đăng ký được tạo / xử lý và các giá trị trung gian được tiến triển trong "đơn nguyên" phản ứng của các lệnh gọi lại. Nói chung trên .Net, tôi thích lập trình phản ứng hơn lập trình dựa trên tác vụ vì các lệnh gọi lại là tĩnh (được biết tại thời điểm biên dịch, không có cấp phát) trong khi các tác vụ được cấp phát động (không được biết, tất cả các cuộc gọi cần một phiên bản, được tạo rác) - và biên dịch lambdas thành các lớp do trình biên dịch tạo.

Rõ ràng C # và F # được đánh giá nghiêm ngặt, vì vậy rò rỉ thời gian không phải là vấn đề ở đây. Tương tự đối với JS. Tuy nhiên, nó có thể là một vấn đề với các quan sát có thể phát lại hoặc được lưu vào bộ nhớ cache.


Cảm ơn vì câu trả lời tuyệt vời. Một trong những điều tôi thích đối với việc triển khai Haskell FRP là chúng dường như cho phép tôi phân tách rõ ràng các tính toán cho điều khiển u(t)và mô phỏng f(t). Đó có phải là trường hợp triển khai F # không?
mnish

Tôi đoán bạn có thể nói rằng hai chức năng đó được tách rời theo thời gian, vâng. Mặc dù vậy, chúng có lẽ không được tách rời một cách hợp lý. ;)
Henrik

Theo như tôi biết, Tiện ích mở rộng phản ứng và các gói tập trung vào giao diện người dùng bóng bẩy hơn (và tất cả mọi thứ bên ngoài Haskell, trên thực tế) chỉ sử dụng các ngữ nghĩa sự kiện - có nghĩa là chúng có khái niệm về các sự kiện bạn có thể bật, nhưng không phải là khái niệm về các tín hiệu thời gian liên tục có thể tương tác một cách bình đẳng. Đối với việc xây dựng guis, điều này là tốt, tôi nghĩ. Tuy nhiên, đối với việc xây dựng mô phỏng và mô hình, điều này có thể không may.
sclv

Bạn có ngụ ý rằng tất cả các triển khai lib lập trình phản ứng chức năng cần mô hình hóa thời gian liên tục thay vì rời rạc không? Tôi đã tìm thấy một bài báo có tên "Đại số quy trình với thời gian: Thời gian thực và thời gian rời rạc" - đây có phải là điểm khởi đầu tốt để hiểu bạn đang nói về điều gì không?
Henrik

Tôi không nói rằng tất cả đều cần - một số làm, một số không. Nhưng những thứ phù hợp hơn với một số nhiệm vụ nhất định và những thứ không phù hợp hơn với những người khác ...
sclv 23/11/12
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.