Đến với (.) . (.)
thực sự là khá đơn giản, đó là trực giác đằng sau những gì nó làm đó là khá khó hiểu.
(.)
giúp bạn rất xa khi viết lại biểu thức thành các tính toán kiểu "đường ống" (nghĩ về |
trong vỏ). Tuy nhiên, nó trở nên khó xử khi sử dụng khi bạn cố gắng soạn một hàm nhận nhiều đối số với hàm chỉ mất một đối số. Như một ví dụ, chúng ta hãy có một định nghĩa về concatMap
:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Bắt thoát khỏi xs
chỉ là một hoạt động tiêu chuẩn:
concatMap f = concat . map f
Tuy nhiên, không có "đẹp" cách loại bỏ f
. Điều này là do thực tế, rằng map
có hai đối số và chúng tôi muốn áp dụng concat
về kết quả cuối cùng của nó.
Bạn có thể dĩ nhiên áp dụng một số thủ thuật pointfree và nhận được ngay với chỉ (.)
:
concatMap f = (.) concat (map f)
concatMap f = (.) concat . map $ f
concatMap = (.) concat . map
concatMap = (concat .) . map
Nhưng than ôi, khả năng đọc của mã này chủ yếu đi.Thay vào đó, chúng tôi giới thiệu một bộ kết hợp mới, thực hiện chính xác những gì chúng tôi cần: áp dụng hàm thứ hai cho kết quả cuối cùng kết quả cuối cùng của kết quả đầu tiên.
-- .: is fairly standard name for this combinator
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(f .: g) x y = f (g x y)
concatMap = concat .: map
Tốt, đó là động lực. Hãy đến với công việc kinh doanh vô cùng đơn giản.
(.:) = \f g x y -> f (g x y)
= \f g x y -> f ((g x) y)
= \f g x y -> f . g x $ y
= \f g x -> f . g x
Bây giờ, đây là phần thú vị. Đây là một thủ thuật vô nghĩa khác thường hữu ích khi bạn gặp khó khăn: chúng tôi viết lại .
vào mẫu tiền tố của nó và cố gắng tiếp tục từ đó.
= \f g x -> (.) f (g x)
= \f g x -> (.) f . g $ x
= \f g -> (.) f . g
= \f g -> (.) ((.) f) g
= \f -> (.) ((.) f)
= \f -> (.) . (.) $ f
= (.) . (.)
Đối với trực giác, có very nice article mà bạn nên đọc. Tôi sẽ diễn giải một phần về (.)
:
Hãy suy nghĩ lại về những gì combinator của chúng tôi nên làm gì: nó nên áp dụng f
đến kết quả của kết quả của g
(Tôi đã sử dụng kết quả cuối cùng trong một phần trước khi có mục đích, nó thực sự là những gì bạn nhận được khi bạn áp dụng đầy đủ - modulo hợp nhất các biến kiểu với một kiểu hàm khác - hàm g
, kết quả ở đây chỉ là ứng dụng g x
cho một số x
).
Điều gì có nghĩa là chúng tôi áp dụng f
cho kết quả của g
? Vâng, khi chúng tôi áp dụng g
cho một số giá trị, chúng tôi sẽ lấy kết quả và áp dụng f
cho nó. Nghe có vẻ quen thuộc: đó là những gì (.)
làm.
result :: (b -> c) -> ((a -> b) -> (a -> c))
result = (.)
Bây giờ, nó chỉ ra rằng thành phần (của chúng tôi của từ) của những combinators chỉ là một hàm hợp, đó là:
(.:) = result . result -- the result of result
@lordlupine một nút mũi anh chàng tròn và sáng mắt với kính? –
@Will Ness Bạn nói đúng ..: P –
@WillNess: Bộ kết hợp Owl-With-Glasses – amindfv