2014-05-07 12 views
6

Có thể áp dụng giảm eta trong trường hợp dưới đây không?Có thể giảm eta không?

let normalise = filter (\x -> Data.Char.isLetter x || Data.Char.isSpace x) 

Tôi đã chờ đợi một cái gì đó như thế này để có thể:

let normalise = filter (Data.Char.isLetter || Data.Char.isSpace) 

... nhưng nó không phải là

Trả lời

10

Giải pháp của bạn không hoạt động, bởi vì (||) hoạt động trên các giá trị BoolData.Char.isLetterData.Char.isSpace thuộc loại Char -> Bool.

pl mang đến cho bạn:

$ pl "f x = a x || b x" 
f = liftM2 (||) a b 

Giải thích: liftM2 thang máy (||) đến (->) r đơn nguyên, do đó, nó loại mới là (r -> Bool) -> (r -> Bool) -> (r -> Bool).

Vì vậy, trong trường hợp của bạn, chúng tôi sẽ nhận được:

import Control.Monad 
let normalise = filter (liftM2 (||) Data.Char.isLetter Data.Char.isSpace) 
+10

Một bổ sung thú vị cho điều này ([bị đánh cắp từ @JAbrahamson] (http://stackoverflow.com/questions/21026021/intrigued-by-as-instances-of-monad-and-functor/21026411#comment31608950_21026411)) là để xác định '(<||>) = liftM2 (||)', thì bạn có thể sử dụng nó làm 'bộ lọc' (isLetter <||> isSpace) ', và thậm chí tiếp tục kết hợp những bộ lọc này như 'filter (isLetter <||> isSpace <||> (==' 1 ')) '. Tôi thấy phong cách này đặc biệt dễ sử dụng và hấp dẫn. – bheklilr

2

Bạn có thể tận dụng lợi thế của Any monoid và dụ monoid cho các chức năng trở về giá trị monoid:

import Data.Monoid 
import Data.Char 

let normalise = filter (getAny . ((Any . isLetter) `mappend` (Any . isSpace))) 
7
import Control.Applicative 
let normalise = filter ((||) <$> Data.Char.isLetter <*> Data.Char.isSpace) 
5

Một giải pháp khác đáng được xem xét liên quan đến mũi tên!

import Control.Arrow 

normalize = filter $ uncurry (||) . (isLetter &&& isSpace) 

&&& lấy hai hàm (mũi tên thực sự) và nén kết quả của chúng vào một bộ. Chúng tôi sau đó chỉ cần uncurry || vì vậy nó là thời gian trở thành (Bool, Bool) -> Bool và chúng tôi đang làm tất cả!

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