Tại sao `print <$> (in bản hello hello)` in bản hello hello?


14

Khi tính toán IO (IO ()), cả hai (IO ())()được tính toán, vậy tại sao

main :: IO (IO ())
main = print <$> (print "Hello, World!")

in

"Hello, World!"

không phải

IO "Hello, World!" -- ??
"Hello, World!"

3
Về cơ bản fmap print (print "Hello World")áp dụng tham số đầu tiên của nó, printhàm, cho kết quả của print "Hello World". Điều đó chỉ đơn giản là tương đương với việc gọi print ()sau khi print "Hello World"hành động được thực hiện.
Redu

@Redu Điều đó là chính xác, nhưng lưu ý rằng việc gọi print ()không bao giờ được đánh giá, cũng như hành động của nó được thực hiện (sẽ in ()trên thiết bị xuất chuẩn). Vì vậy, "gọi print ()sau ..." là một chút sai lệch (IMO).
chi

Câu trả lời:


21
main :: IO (IO ())
main = print <$> (print "Hello, World!")

là tương đương, nhờ vào luật đơn nguyên, để

main :: IO (IO ())
main = do 
   result <- print "Hello, World!"
   return (print result)

Bây giờ, printluôn trả về ()kết quả, vì vậy toàn bộ mã tương đương với

main :: IO (IO ())
main = do 
   _ <- print "Hello, World!"
   return (print ())

Cuối cùng, kết quả của mainchỉ đơn giản là bị loại bỏ. Đó là, dòng cuối cùng có thể return (putStrLn "this is ignored")và có tác dụng tương tự.

Do đó mã sẽ chỉ thực hiện đầu tiên print "Hello, World!".

Tôi muốn giới thiệu rằng bạn luôn luôn xác định main :: IO (). Haskell cho phép chúng tôi khai báo main :: IO AnyTypeHere, nhưng điều này (IMO) khó hiểu.

Tôi cũng khuyên bạn nên sử dụng putStrLnvà không printin chuỗi, vì chuỗi sau sẽ trích dẫn và thoát khỏi toàn bộ chuỗi.


5
Tôi muốn nói thêm rằng đó f <$> a ≡ a >>= \r -> return $ f rkhông chỉ là một điều cụ thể cho tình huống này, mà còn thực sự đúng với bất kỳ đơn nguyên nào.
leftaroundabout
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.