Tôi không hiểu "nâng" là gì. Trước tiên tôi có nên hiểu các monads trước khi hiểu "thang máy" là gì? (Tôi hoàn toàn không biết gì về monads, quá :) Hoặc ai đó có thể giải thích cho tôi với những từ đơn giản?"Nâng" trong Haskell là gì?
Trả lời
Nâng cao có nhiều mẫu thiết kế hơn là khái niệm toán học (mặc dù tôi hy vọng một người nào đó quanh đây giờ đây sẽ bác bỏ tôi bằng cách hiển thị mức độ nâng hạng hoặc danh mục).
Thông thường bạn có một số loại dữ liệu có tham số. Một cái gì đó như
data Foo a = Foo { ...stuff here ...}
Giả sử bạn thấy rằng có rất nhiều công dụng của Foo
lấy loại số (Int
, Double
vv) và bạn tiếp tục phải viết mã mà unwraps những con số này, thêm hoặc nhân chúng, và sau đó kết thúc tốt đẹp chúng trở lại lên. Bạn có thể rút ngắn điều này bằng cách viết mã unwrap-and-wrap một lần. Chức năng này theo truyền thống được gọi là "nâng đỡ" bởi vì nó trông như thế này:
liftFoo2 :: (a -> b -> c) -> Foo a -> Foo b -> Foo c
Nói cách khác bạn có một chức năng mà phải mất một chức năng hai đối số (ví dụ như các nhà điều hành (+)
) và biến nó thành các chức năng tương đương cho Foos.
Vì vậy, bây giờ bạn có thể viết
addFoo = liftFoo2 (+)
Edit: thêm thông tin
Bạn có thể dĩ nhiên có liftFoo3
, liftFoo4
và vân vân. Tuy nhiên điều này thường không cần thiết.
Bắt đầu với các quan sát
liftFoo1 :: (a -> b) -> Foo a -> Foo b
Nhưng đó là chính xác giống như fmap
.Vì vậy, chứ không phải là liftFoo1
bạn sẽ viết
instance Functor Foo where
fmap foo = ...
Nếu bạn thực sự muốn đặn hoàn chỉnh sau đó bạn có thể nói
liftFoo1 = fmap
Nếu bạn có thể làm Foo
thành một functor, có lẽ bạn có thể làm cho nó trở thành một functor applicative. Trong thực tế, nếu bạn có thể viết liftFoo2
thì dụ applicative trông như thế này:
import Control.Applicative
instance Applicative Foo where
pure x = Foo $ ... -- Wrap 'x' inside a Foo.
(<*>) = liftFoo2 ($)
Các (<*>)
điều hành cho Foo có loại
(<*>) :: Foo (a -> b) -> Foo a -> Foo b
Nó áp dụng các chức năng bao bọc với giá trị gói. Vì vậy, nếu bạn có thể thực hiện liftFoo2
thì bạn có thể viết điều này về mặt nó. Hoặc bạn có thể thực hiện trực tiếp và không bận tâm với liftFoo2
, bởi vì các mô-đun Control.Applicative
bao gồm
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
và tương tự như vậy có liftA
và liftA3
. Nhưng bạn không thực sự sử dụng chúng rất thường xuyên vì có một nhà điều hành
(<$>) = fmap
này cho phép bạn viết:
result = myFunction <$> arg1 <*> arg2 <*> arg3 <*> arg4
Thuật ngữ myFunction <$> arg1
trả về một chức năng mới được bọc trong Foo. Điều này lần lượt có thể được áp dụng cho đối số tiếp theo bằng cách sử dụng (<*>)
, v.v. Vì vậy, bây giờ thay vì có một chức năng nâng cho tất cả các arity, bạn chỉ cần có một chuỗi daisy của các ứng dụng.
Có thể đáng nhắc nhở rằng thang máy phải tôn trọng luật tiêu chuẩn 'lift id == id' và' lift (f. G) == (lift f). (nâng g) '. –
Thang máy thực sự là "một loại hoặc một cái gì đó". Carlos đã chỉ liệt kê các luật Functor, trong đó 'id' và' .' là thành phần mũi tên và mũi tên của một số thể loại tương ứng. Thông thường khi nói về Haskell, danh mục được đề cập là "Hask", có mũi tên là hàm Haskell (nói cách khác, 'id' và' .' tham chiếu đến các hàm Haskell mà bạn biết và yêu thích). –
tôi thích cách bạn bắt đầu bằng cách đề cập đến một loại có tham số. Đây là ý tưởng quan trọng nhất về Monad. Tôi vẫn không thể tin rằng trong cuốn sách: thế giới thực haskell tác giả đã không giải thích rằng Monad chỉ đơn giản là một lớp loại (kiểm tra các chương về monads và monad lập trình trên cuốn sách đó) – osager
Lifting là một khái niệm mà cho phép bạn chuyển đổi một chức năng vào một chức năng tương ứng trong vòng một (thường là tổng quát hơn) thiết
hãy nhìn vào http://haskell.org/haskellwiki/Lifting
Vâng, nhưng trang đó bắt đầu "Chúng tôi thường bắt đầu bằng một hàm biến đổi (covariant) ...". Không chính xác người mới thân thiện. –
Nhưng "functor" được liên kết, do đó, newbie có thể chỉ cần nhấp vào đó để xem Functor là gì. Phải thừa nhận rằng, trang được liên kết không tốt lắm. Tôi cần phải có một tài khoản và sửa lỗi đó. – jrockway
Đó là vấn đề tôi đã thấy trên các trang lập trình chức năng khác; mỗi khái niệm được giải thích theo các khái niệm khác (không quen thuộc) cho đến khi newbie đi vòng tròn đầy đủ (và vòng uốn cong). Phải là một cái gì đó để làm với thích đệ quy. – DNA
Hãy bắt đầu với một ví dụ:
> replicate 3 'a'
"aaa"
> :t replicate
replicate :: Int -> a -> [a]
> :t liftA2 replicate
liftA2 replicate :: (Applicative f) => f Int -> f a -> f [a]
> (liftA2 replicate) [1,2,3] ['a','b','c']
["a","b","c","aa","bb","cc","aaa","bbb","ccc"]
> :t liftA2
liftA2 :: (Applicative f) => (a -> b -> c) -> (f a -> f b -> f c)
liftA2
chuyển đổi chức năng của các loại đồng bằng thành chức năng của các loại này được bọc trong Applicative
, chẳng hạn như danh sách, IO
, v.v ...
Mức tăng phổ biến khác là lift
từ Control.Monad.Trans
. Nó biến đổi một hành động đơn thuần của một đơn nguyên thành một hành động của một đơn nguyên được biến đổi.
Nói chung, nâng "nâng" chức năng/hành động thành loại "được bao bọc".
Cách tốt nhất để hiểu điều này, và monads vv và để hiểu lý do tại sao chúng hữu ích, có lẽ là để mã và sử dụng nó. Nếu có bất cứ điều gì bạn mã hóa trước đây mà bạn nghi ngờ có thể hưởng lợi từ điều này (tức là điều này sẽ làm cho mã đó ngắn hơn, vv), chỉ cần thử nó ra và bạn sẽ dễ dàng nắm bắt được khái niệm.
Paul và yairchu là cả hai giải thích tốt.
Tôi muốn thêm rằng chức năng đang được dỡ bỏ có thể có số lượng đối số tùy ý và chúng không nhất thiết phải cùng loại. Ví dụ, bạn cũng có thể định nghĩa một liftFoo1:
liftFoo1 :: (a -> b) -> Foo a -> Foo b
Nói chung, việc dỡ bỏ các chức năng mà phải mất 1 lập luận được thể hiện trong kiểu lớp Functor
, và các hoạt động nâng được gọi fmap
:
fmap :: Functor f => (a -> b) -> f a -> f b
Lưu ý sự giống nhau với loại của liftFoo1
. Trong thực tế, nếu bạn có liftFoo1
, bạn có thể làm Foo
một thể hiện của Functor
:
instance Functor Foo where
fmap = liftFoo1
Hơn nữa, tổng quát của nâng đến một số bất kỳ các đối số được gọi là applicative phong cách. Đừng bận tâm vào việc này cho đến khi bạn nắm bắt được việc nâng các hàm bằng một số đối số cố định. Nhưng khi bạn làm, Learn you a Haskell có một chương tốt về điều này. Typeclassopedia là một tài liệu hay khác mô tả Functor và Áp dụng (cũng như các loại lớp khác; cuộn xuống chương bên phải trong tài liệu đó).
Hy vọng điều này sẽ hữu ích!
Theo this shiny tutorial, một functor là một số container (như Maybe<a>
, List<a>
hoặc Tree<a>
có thể lưu trữ các yếu tố của một số loại khác, a
). Tôi đã sử dụng ký hiệu Generics Java, <a>
, cho loại phần tử a
và nghĩ về các phần tử như quả trên cây Tree<a>
. Có hàm fmap
, có chức năng chuyển đổi phần tử, a->b
và vùng chứa functor<a>
. Nó áp dụng a->b
cho mọi thành phần của vùng chứa có hiệu quả chuyển đổi nó thành functor<b>
. Khi chỉ đối số đầu tiên được cung cấp, a->b
, fmap
đợi cho số functor<a>
. Tức là, việc cung cấp a->b
một mình sẽ biến chức năng mức phần tử này thành hàm functor<a> -> functor<b>
hoạt động trên các vùng chứa. Điều này được gọi là nâng của hàm. Bởi vì các container cũng được gọi là một functor, các Functors hơn là Monads là một điều kiện tiên quyết cho việc nâng. Monads là loại "song song" để nâng. Cả hai đều dựa vào khái niệm Functor và làm f<a> -> f<b>
. Sự khác biệt là việc nâng sử dụng a->b
cho chuyển đổi trong khi Monad yêu cầu người dùng xác định a -> f<b>
.
Tôi đã cho bạn một nhãn hiệu xuống, bởi vì "một functor là một số container" là troll-hương vị ngọn lửa mồi. Ví dụ: các hàm từ một số 'r' thành một kiểu (hãy sử dụng' c' cho giống), là hàm Functors. Họ không "chứa" bất kỳ 'c'. Trong trường hợp này, fmap là thành phần hàm, lấy hàm 'a -> b' và một hàm« r -> a', để cung cấp cho bạn hàm mới, 'r -> b'. Vẫn không có container. Ngoài ra, nếu tôi có thể, tôi sẽ đánh dấu nó xuống một lần nữa cho câu cuối cùng. – BMeph
Ngoài ra, 'fmap' là một hàm, và không" chờ "bất cứ điều gì; Các "container" là một Functor là _the toàn bộ point_ của nâng. Ngoài ra, Monads là, nếu bất cứ điều gì, một ý tưởng kép để nâng: một Monad cho phép bạn sử dụng một cái gì đó đã được nâng lên một số lần tích cực, như thể nó chỉ được nâng lên một lần - điều này được gọi là _flattening_. – BMeph
@BMeph 'Để chờ',' để mong đợi', 'để dự đoán' là từ đồng nghĩa. Bằng cách nói "chức năng chờ đợi" tôi có nghĩa là "chức năng dự đoán". – Val
- 1. Nâng cao ParseError trong Haskell/Parsec
- 2. Nâng cao trong Python là gì?
- 3. Nâng cấp http là gì?
- 4. Ví dụ nâng cấp trong Haskell
- 5. apostrophe có nghĩa là gì trong Haskell?
- 6. Bí quyết showS trong Haskell là gì?
- 7. ': ..' có nghĩa là gì trong Haskell?
- 8. `~` có nghĩa là gì trong Haskell?
- 9. Cách nâng cấp Nền tảng Haskell
- 10. Haskell - Điều gì là Control.Applicative.Alternative tốt cho?
- 11. So khớp mẫu Haskell - nó là gì?
- 12. Cú pháp haskell này là gì?
- 13. Biểu tượng => có nghĩa là gì trong Haskell?
- 14. Trạng thái lập trình đa lõi trong Haskell là gì?
- 15. Những dấu ngoặc vuông này trong Haskell là gì?
- 16. Dấu chéo ngược kép \ nghĩa là gì trong Haskell?
- 17. Dữ liệu ... có nghĩa là gì trong Haskell?
- 18. ((->) t) có nghĩa là gì trong Haskell?
- 19. Tên ADT. `Trái a` là gì, và sau đó cái gì là` a`, trong Haskell?
- 20. Sự khác biệt giữa `nâng cao 'foo" `và` nâng cao ngoại lệ.new ("foo") `là gì?
- 21. Nhận xét Haskell bắt đầu bằng `{- |` có nghĩa là gì?
- 22. "|" là gì? cho một định nghĩa lớp Haskell?
- 23. Cách tốt để gỡ lỗi mã haskell là gì?
- 24. Sự khác biệt và điểm tương đồng của hệ thống kiểu Scala và Haskell là gì?
- 25. Trong delphi 7, là `try ... trừ nâng cao; kết thúc, `có ý nghĩa gì cả?
- 26. Trong Erlang, cách tốt nhất để nâng cấp hệ thống phân phối là gì?
- 27. Trong Java, điều gì là tự nhiên nhất tương tự như nâng cao một Python ValueError?
- 28. Toàn bộ hoặc chấm hoặc dấu chấm (.) Có nghĩa là gì trong Haskell?
- 29. Sự khác biệt giữa loại và loại dữ liệu trong Haskell là gì?
- 30. Ý nghĩa của phiên bản nghiêm ngặt trong haskell là gì?
Có thể hữu ích, có thể không: http://www.haskell.org/haskellwiki/Lifting – kennytm