2013-06-06 32 views
8

Tôi đang cố gắng giải thích một câu lệnh trong Haskell. Tôi đã tìm thấy một số ví dụ ở đây trên SO nhưng không thể áp dụng chúng cho trường hợp của tôi. Điều duy nhất tôi có thể nghĩ là một tuyên bố lồng nhau nặng nề, có vẻ khá xấu xí.Ký hiệu ghi chú Haskell để liên kết

Tuyên bố trong đó làm ký hiệu nên được thay thế bởi ràng buộc:

do num <- numberNode x 
    nt1 <- numberTree t1 
    nt2 <- numberTree t2 
    return (Node num nt1 nt2) 

Bất kỳ đầu vào được đánh giá cao =)

Trả lời

11
numberNode x >>= \num -> 
    numberTree t1 >>= \nt1 -> 
    numberTree t2 >>= \nt2 -> 
     return (Node num nt1 nt2) 

Lưu ý rằng đây là đơn giản hơn nếu bạn sử dụng Applicatives:

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 
+0

Cảm ơn bạn đã đẩy đầu vào tường này. Không biết tại sao, nhưng tôi chỉ không có giải pháp đơn giản này. – floAr

+0

Bạn được chào đón! –

7

Đây là trường hợp sử dụng tuyệt vời cho applicative style. Bạn có thể thay thế toàn bộ đoạn mã của bạn (sau khi nhập Control.Applicative) với

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 

Hãy suy nghĩ về phong cách applicative (sử dụng <$><*>) là "nâng" ứng dụng chức năng để nó hoạt động trên functors là tốt. Nếu bạn tinh thần bỏ qua <$><*>, nó trông khá giống ứng dụng chức năng bình thường!

Kiểu áp dụng rất hữu ích bất cứ khi nào bạn có hàm thuần túy và bạn muốn cho đối số không đúng (hoặc bất kỳ đối số functor nào) - về cơ bản khi bạn muốn thực hiện những gì bạn đã chỉ định trong câu hỏi của mình!


Các loại chữ ký của <$>

(<$>) :: Functor f => (a -> b) -> f a -> f b 

có nghĩa là nó có một chức năng tinh khiết (trong trường hợp này Node) và một giá trị functor (trong trường hợp này numberNode x) và nó tạo ra một chức năng mới bao bọc "bên trong" một hàm. Bạn có thể thêm lập luận hơn nữa để chức năng này với <*>, trong đó có các loại chữ ký

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

Như bạn có thể thấy, đây là rất giống với <$> chỉ nó hoạt động ngay cả khi hàm được bọc "bên trong" một functor.

+0

Cảm ơn bạn đã đề cập đến điều này, tôi không có kinh nghiệm với các ứng dụng nhưng khái niệm trông tuyệt vời. Nó chỉ là kiểu cách tốt đẹp để giải quyết vấn đề tôi thích về Haskell :) Khi tôi đang yêu cầu nhà điều hành liên kết, tôi sẽ chấp nhận câu trả lời của Gabriels, nhưng tôi chắc chắn sẽ xem xét kỹ hơn khái niệm này. Cảm ơn bạn rất nhiều vì đã chỉ ra điều này cho tôi =) – floAr

2

Tôi muốn bổ sung vào bài viết về applicative trên ..

Xét loại <$>:

(<$>) :: Functor f => (a -> b) -> f a -> f b 

nó trông giống như fmap:

fmap :: Functor f => (a -> b) -> f a -> f b 

đó là cũng rất giống Control.Monad.liftM:

liftM :: Monad m => (a -> b) -> m a -> m b 

Tôi nghĩ về điều này như "Tôi cần phải dỡ bỏ nhà xây dựng dữ liệu vào loại hình này"

Trên một lưu ý liên quan, nếu bạn thấy mình làm điều này:

action >>= return . f 

bạn thay vào đó có thể thực hiện việc này:

f `fmap` action 

Ví dụ đầu tiên là sử dụng liên kết để lấy giá trị ra khỏi bất kỳ hành động nào là, gọi f với nó, và sau đó repacking kết quả. Thay vào đó, chúng ta có thể nâng f để nó lấy kiểu hành động làm đối số của nó.

+0

Cảm ơn lời giải thích liên tục này =) – floAr

+1

'liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 - > m a3 -> mr' hoặc 'liftA3 :: Áp dụng f => (a -> b -> c -> d) -> fa -> fb -> fc -> fd' có sẵn bằng cách nhập' Control.Monad' hoặc 'Control.Applicative' và hữu ích hơn' fmap'/'liftM' đơn giản ở đây. Ví dụ, 'liftA3 Node (numberNode x) (numberTree t1) (numberTree t2)' sẽ thực hiện thủ thuật. – AndrewC

+0

Vì nó là viết tắt, điều này không actully trả lời câu hỏi. OP không thể sử dụng nó để giải quyết vấn đề họ có. Đó là lý do tại sao bạn cần liftM3 hoặc Applicative. – AndrewC

Các vấn đề liên quan