2016-03-19 16 views
15

Tôi đang phải vật lộn với sự hiểu biết về chức năng đơn vị trong JavaScript. Đặc biệt là vì điều khiến tôi 'có được' monads (hoặc ít nhất tôi nghĩ) là đối tượng Promise, và cách then luôn trả về một Promise mới, bất kể chức năng nào bạn chuyển đến then, theo kiến ​​thức của tôi tương đương với bind hoặc >>= trong haskell. Điều này hoàn toàn có ý nghĩa đối với tôi, bởi vì nó đảm bảo rằng tất cả các chức năng của bạn được thực hiện trong 'vũ trụ đơn nguyên', để nói.JS Chức năng đơn vị đơn vị

Điều gì khiến tôi bận tâm là cuộc trò chuyện 'Monads và Gonads' của Douglas Crockford. Trong việc thực hiện của mình, bind trả về trực tiếp kết quả của hàm chuyển đổi, mà không kiểm tra nếu kết quả đó là một đơn nguyên. Điều này đụng độ với phương thức then của Promises, vì then LUÔN trả về một Lời hứa mới.

Một ý nghĩ là phương pháp nâng. Việc thực hiện của anh ta đảm bảo rằng 'nâng' sẽ luôn trả lại một đơn nguyên, và có lẽ then đã được nâng lên để Hứa hẹn. Tuy nhiên, điều này có nghĩa là then !== bind và lời hứa đó có liên kết nội bộ ở đâu đó.

Trực giác của tôi là ít nhất phải có loại kiểm tra nào đó trong chức năng liên kết để kiểm tra kết quả của phép biến đổi và cho phép một kết quả được thông qua, nhưng sẽ chặn không phải monads và chuyển chúng qua đơn vị một lần nữa, như 'lift'.

* EDIT
Ngoài ra, tôi có ấn tượng rằng then tương đương với bind, flatMap, >>= bởi vì nó có khả năng unwrap monads khác, kể cả những người khác nhau và những kiểu riêng của nó. Trong khi xem xét một số tham chiếu lý thuyết danh mục trong JavaScript, flatMap được sử dụng để ánh xạ trên một tập hợp các mảng lồng nhau và sau đó làm phẳng chúng theo một thứ nguyên. Điều này phù hợp với cách then sẽ chờ các lời hứa khác mà bạn đưa ra. Nhưng dường như không phù hợp với thực hiện ban đầu được đề cập ở trên. Tôi cảm thấy lạc lõng.

Bất kỳ ai có nhiều kinh nghiệm về FP đều làm sáng tỏ những gì tôi đang bỏ lỡ hoặc tôi chỉ là quá tắt và cần phải bắt đầu lại từ đầu?

Một số ví dụ mã ...

// Crockford's 'bind' 
monad.bind = function(transform) { 
    // value was passed in through the unit constructor 
    return transform(value); 
} 

khu vực rắc rối của tôi

// Set the 'isMonad' prop to be true, for all 
// monads made with the MONAD macroid 
monad.isMonad = true; 

// shouldn't this ALWAYS return a monad? 
monad.bind = function(transform) { 
    var res = transform(value); 
    return (res && res.isMonad) ? res : unit(res); 
} 

LƯU Ý Tôi biết tôi không sử dụng phiên bản chính thức thực hiện của mình trong đầy đủ, tôi chỉ tập trung vào phương pháp liên kết đặc biệt.

Việc thực hiện đầy đủ có thể được tìm thấy tại

https://github.com/douglascrockford/monad/blob/master/monad.js

Cập nhật

Sau khi thực hiện một số nghiên cứu nhiều hơn, >>= không cần phải quay trở lại một trường hợp đơn nguyên. Nhận xét của Bergi làm sáng tỏ cách Promise.prototype.then bị quá tải và hoạt động như một chức năng khác tùy thuộc vào những gì bạn giải quyết.

Ngoài ra, rất nhiều thứ bắt đầu nhấp vào khi tôi lùi lại một bước và xem cách Monads khác với các functors thông thường. Các chi tiết vẫn còn hơi mờ, nhưng tôi nghĩ tôi có được bức tranh lớn.

Một vài tài liệu tham khảo tốt đã giúp xóa các đám mây,

này ai khuyên cho một cái nhìn tổng quan cấp cao, nói cách con người
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
Đừng để những hình ảnh đánh lừa bạn, điều này giống như vàng cho tôi. Không phải trong JavaScript, nhưng vẫn rất thông tin về các khái niệm tổng thể.

Ngoài ra, hàng loạt YouTube này vào loại lý thuyết trong JavaScript
https://www.youtube.com/watch?v=-FkgOHvNAU8&list=PLwuUlC2HlHGe7vmItFmrdBLn6p0AS8ALX&index=1

loạt YouTube này gọi là 'Fun Fun Chức năng' là tuyệt vời, chủ nhà là một trong những giáo viên tốt nhất mà tôi đã tìm thấy trực tuyến. Video này giới thiệu về monads và được đề xuất bởi MrE.
Rất khuyến khích !.

https://www.youtube.com/watch?v=9QveBbn7t_c&app=desktop

Hai tài liệu tham khảo đó đã làm tôi ngạc nhiên. Hy vọng rằng sẽ giúp tất cả mọi người khác là tốt.

+14

Tôi thật sự khuyên bạn bỏ qua phần nói/mã Crockford này. Sự hiểu biết của bạn từ lời hứa là hợp lý. Bạn sẽ tìm thấy nó một chỉ báo * tốt * mà bạn thấy Crockford nói chuyện khó hiểu vì anh ta bối rối. –

+3

'then' là một sự thực thi khủng khiếp của một đơn nguyên. Nó kết hợp 'bind' /' chain'/'flatMap'/bất cứ cái gì bạn gọi nó với một' map' bình thường, và nó cũng chấp nhận bất kỳ giá trị nào là giá trị trả về. Trong Haskell, bạn hoàn toàn không cần 'isMonad', bởi vì trình biên dịch đã kiểm tra xem hàm bạn truyền vào có kiểu trả về đúng hay không. – Bergi

+4

Thêm một đề xuất khác cho "bỏ qua Crockford". – naomik

Trả lời

1

Tôi hoàn toàn không có được những gì câu hỏi của bạn là, nhưng tôi muốn thừa nhận cái gì đó như:

định nghĩa đúng của một đơn nguyên là gì và nó là hai phương pháp về JS?

Trong Haskell ngữ (lấy từ https://en.wikibooks.org/wiki/Haskell/Understanding_monads), nó đơn giản:

return :: a -> m a 
    (>>=) :: m a -> (a -> m b) -> m b 

    (>>) :: m a -> m b -> m b 

Đối Javascript điều khoản, lựa chọn nào tốt, câu trả lời ngắn gọn và đơn giản là ở đây https://github.com/fantasyland/fantasy-land#monad cùng với khác được kết nối Các định nghĩa FP.

Vài lời về các phương pháp:

  1. Một điều được unit (return trong Haskell) phải xuất trình một đơn nguyên (không chính xác đơn nguyên, nhưng vì lợi ích của các đối số ...), vì nó giống như một hàm tạo đặt một giá trị bên trong vùng chứa. Array.of() là một ví dụ, jQuery() là một ví dụ khác, và dĩ nhiên là new Promise().

    Trong Đặc điểm đất tưởng tượng đây là chức năng/phương pháp of().

  2. Điều thứ hai là quan trọng chỉ vì Haskell sử dụng một định nghĩa của đơn nguyên có unitbind khi những người khác (fmap, join) được suy ra thành họ.

    Các Haskell củabind được đặt tên chain trong Ảo đất Specificationbind là thách thức trên Function.prototype trong Javascript, để ai đó nghĩ chain sẽ là đủ gần.

    Và lý do tại sao bind tức là chain "phải" trả lại một đơn vị cùng loại là vì (>>=) :: m a -> (a -> m b) -> m b. Tóm lại, hàm của Haskell làbind chỉ phải chấp nhận hàm trả về một đơn nguyên (phần này là a -> m b), vì vậy bạn sẽ nhận được kết quả của nó.

  3. Các Haskell củathen

    là đơn thuần là một tiện nghi

    chuỗi hai hành động monadic khi hành động thứ hai không liên quan đến kết quả của sự đầu tiên, đó là phổ biến cho monads như IO.

Trong thực tế:

  1. Nó có thể irk bạn trong JS, vì không có thực thi loại nghiêm ngặt, bạn luôn có thể không tuân theo các quy tắc và trở về bất cứ điều gì bạn muốn từ một Promise , ví dụ, do đó phá vỡ chuỗi .then() của (các) lời hứa đã nói.

  2. Một số đơn vị như jQuery có chức năng "dỡ bỏ" làm phương pháp luôn trả về jQuery tức là cùng loại như vậy, "bảo vệ" khả năng chuỗi.