Tôi muốn nói rằng điều tốt nhất để hỏi không phải là chúng ta sẽ gọi nó như thế nào, mà là cách chúng ta phân tích một đoạn mã như vậy. Và câu hỏi quan trọng đầu tiên của tôi trong một phân tích như vậy sẽ là:
- Có tác dụng phụ phụ thuộc vào đối số cho chức năng, hoặc kết quả về tác dụng phụ?
- Không: "Hàm hiệu quả" có thể được tái cấu trúc thành một hàm thuần túy, một hành động hiệu quả và một cơ chế để kết hợp chúng.
- Có: "Hàm hiệu quả" là một hàm tạo ra kết quả đơn âm.
Điều này là đơn giản để minh họa trong Haskell (và câu này chỉ là một nửa trò đùa). Một ví dụ về trường hợp "không" sẽ giống như thế này:
double :: Num a => a -> IO a
double x = do
putStrLn "I'm doubling some number"
return (x*2)
Trong ví dụ này, hành động mà chúng ta thực hiện (in dòng "I'm doubling some number"
) không có tác động đến mối quan hệ giữa x
và kết quả. Điều này có nghĩa là chúng ta có thể cấu trúc lại nó theo cách này (sử dụng Applicative
lớp và *>
toán tử của nó ), điều này cho thấy hàm và hiệu ứng trên thực tế là trực giao:
double :: Num a => a -> IO a
double x = action *> pure (function x)
where
-- The pure function
function x = x*2
-- The side effect
action = putStrLn "I'm doubling some number"
Vì vậy, trong trường hợp này, cá nhân tôi, sẽ nói rằng đó là trường hợp bạn có thể tạo ra một hàm thuần túy. Rất nhiều chương trình của Haskell nói về việc học cách này để tìm ra các phần thuần túy từ mã hiệu quả.
Một ví dụ về loại "có", trong đó các phần nguyên chất và hiệu quả không trực giao:
double :: Num a => a -> IO a
double x = do
putStrLn ("I'm doubling the number " ++ show x)
return (x*2)
Bây giờ, chuỗi mà bạn in phụ thuộc vào giá trị của x
. Các chức năng phần (nhân x
bởi hai), tuy nhiên, không phụ thuộc vào ảnh hưởng chút nào, vì vậy chúng tôi vẫn có thể yếu tố nó ra:
logged :: (a -> b) -> (a -> IO x) -> IO b
logged function logger a = do
logger a
return (function a)
double x = logged function logger
where function = (*2)
logger x putStrLn ("I'm doubling the number " ++ show x)
Tôi có thể tiếp tục đánh vần các ví dụ khác, nhưng tôi hy vọng điều này đủ để minh họa điểm tôi đã bắt đầu: bạn không "gọi" nó một cái gì đó, bạn phân tích làm thế nào các phần tinh khiết và hiệu quả liên quan và đưa ra yếu tố khi nó là để lợi thế của bạn.
Đây là một trong những lý do Haskell sử dụng Monad
lớp học của nó rất nhiều. Monads là (trong số những thứ khác) là một công cụ để thực hiện loại phân tích và tái cấu trúc này.