2012-03-17 23 views
10

Tôi đang giúp một người bạn học Haskell và gần đây ông đã tạo mã như thế này, loại này kiểm tra và tạo ra một vòng lặp CPU-cháy khi chạy. Tôi hoàn toàn bối rối bởi điều này.Tại sao nhập Control.Applicative cho phép mã này xấu gõ kiểm tra?

import Control.Monad 
import Control.Applicative 

main = forever putStrLn "Hello, infinity" 

Đó không phải là loại séc, nhưng có. Phiên bản đúng sẽ là rõ ràng:

main = forever $ putStrLn "Hello, infinity" 

Có gì kỳ lạ và đáng ngạc nhiên đối với tôi là bạn có được kết quả khác nhau có và không có nhập khẩu Control.Applicative. Nếu không nhập nó, nó không gõ kiểm tra:

Prelude Control.Monad> forever putStrLn "Hello, infinity" 

<interactive>:1:1: 
    No instance for (Monad ((->) String)) 
     arising from a use of `forever' 
    Possible fix: add an instance declaration for (Monad ((->) String)) 
    In the expression: forever putStrLn "Hello, infinity" 
    In an equation for `it': it = forever putStrLn "Hello, infinity" 

Tôi không thấy một ví dụ đơn nguyên cho ((->) String trong nguồn cho Control.Applicative, vì vậy tôi đoán điều gì đó kỳ lạ đang xảy ra do việc sử dụng các Control.Category hoặc Control.Arrow, nhưng tôi không biết. Vì vậy, tôi đoán tôi có hai câu hỏi:

  1. Điều gì sẽ xảy ra với việc nhập Control Control.Applicative cho phép điều này xảy ra?
  2. Điều gì sẽ xảy ra khi nó đi vào vòng lặp vô hạn? Haskell thực sự đang cố gắng thực hiện trong trường hợp đó là gì?

Cảm ơn,

Trả lời

13

Có không phải là một ví dụ cho (->) String, nhưng có một thể hiện cho (->) e ... và ví dụ đó là rất, rất hữu ích trong nhiều tình huống. Đối với câu hỏi thứ hai, chúng ta phải có một cái nhìn tại forever và dụ lớp cho các chức năng:

instance Monad ((->) e) where 
    return x = \e -> x 
    m >>= f = \e -> f (m e) e 

forever m = m >> forever m = m >>= \_ -> forever m 

Bây giờ, những gì hiện forever putStrLn làm gì?

forever putStrLn 
    = putStrLn >>= \_ -> forever putStrLn 
    = \e -> (\_ -> forever putStrLn) (putStrLn e) e 
    = \e -> (forever putStrLn) e 
    = forever putStrLn 

... nó chỉ là vòng lặp vô hạn thuần túy, về cơ bản giống hệt với loop = loop.

Để nhận được một số trực giác cho những gì đang xảy ra với các đơn nguyên đầu đọc (vì nó được biết đến), hãy nhìn vào the documentation, All About Monads section on Reader, và có một số gợi ý rắc khắp Typeclassopedia mà có thể giúp đỡ.

+0

Bạn có thể giải thích về ví dụ cho '(->) e' nào hữu ích không? –

+4

@DanielLyons Rất hữu ích khi bạn có nhiều chức năng mà tất cả đều cần quyền truy cập vào một số thông tin cấu hình được chia sẻ. Sau đó, bạn có thể viết (ví dụ) 'foo >> = bar >> = baz' thay vì lặp lại môi trường ở khắp mọi nơi như trong' \ e -> let x = foo e; y = bar x e; z = baz y e trong y'. –

6

Control.Applicative nhập Control.Monad.Instances và do đó tái xuất các phiên bản từ Control.Monad.Instances. Điều này bao gồm FunctorMonad trường hợp cho ((->) r).

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