Trong trường hợp này, bạn thực sự có thể sử dụng gói newtypes
để giải quyết vấn đề này quát hơn:
process :: Node -> Maybe String
process (Pick xs) = ala' First foldMap process xs
process (Join xs) = liftM os_path_join (mapM process xs)
process (Name x) = Just x
process (Given x) = x
Bạn thậm chí có thể có một phiên bản chung chung hơn mà phải mất một Newtype n (Maybe String)
như
process'
:: (Newtype n (Maybe String), Monoid n)
=> (Maybe String -> n) -> Node -> Maybe String
process' wrapper (Pick xs) = ala' wrapper foldMap (process' wrapper) xs
process' wrapper (Join xs) = liftM os_path_join (mapM (process' wrapper) xs)
process' wrapper (Name x) = Just x
process' wrapper (Given x) = x
Sau đó,
> let processFirst = process' First
> let processLast = process' Last
> let input = Pick [Given Nothing, Name "bar", Given (Just "foo"), Given Nothing]
> processFirst input
Just "bar"
> ProcessLast input
Just "foo"
Như một lời giải thích cho cách làm này, các ala'
chức năng phải mất một wrapper Newtype để xác định trường hợp của Newtype
sử dụng, một chức năng mà trong trường hợp này, chúng tôi muốn trở thành foldMap
:
foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
từ foldMap f
kết thúc là tổng quát mconcat . map f
trên Foldable
loại thay vì chỉ danh sách, sau đó một hàm để sử dụng làm "bộ tiền xử lý" để gắn vào hàm bậc cao hơn được chuyển đến ala'
(foldMap
), trong trường hợp này, một số Foldable t => t Node
để xử lý. Nếu bạn không muốn bước tiền xử lý bạn chỉ sử dụng ala
, sử dụng id
cho bộ tiền xử lý của nó. Sử dụng chức năng này đôi khi có thể khó khăn do loại phức tạp của nó, nhưng như các ví dụ trong tài liệu hiển thị foldMap
thường là một lựa chọn tốt.
Sức mạnh của việc này là nếu bạn muốn viết newtype
wrapper của riêng bạn cho Maybe String
:
newtype FirstAsCaps = FirstAsCaps { getFirstAsCaps :: Maybe String }
firstAsCaps :: Maybe String -> FirstAsCaps
firstAsCaps = FirstAsCaps . fmap (fmap toUpper)
instance Monoid FirstAsCaps where
mempty = firstAsCaps Nothing
mappend (FirstAsCaps f) (FirstAsCaps g)
= FirstAsCaps $ ala First (uncurry . on (<>)) (f, g)
instance Newtype FirstAsCaps (Maybe String) where
pack = firstAsCaps
unpack = getFirstAsCaps
Sau đó
> process' firstAsCaps input
Just "BAR"
Âm thanh như 'coerce'. – Zeta
Loại 'process' được cho là gì? Có thể sử dụng gói 'newtype' để ẩn hầu hết những điều này. Tất cả tôi có thể làm cho nó là 'Pick' phải thuộc về một loại đệ quy, kể từ' Chọn :: [a] -> PickType', và 'process :: PickType -> Có thể a', nhưng' Đầu tiên. process :: PickType -> First a', vì vậy 'xs :: [PickType]'? – bheklilr
Nó chỉ là một ví dụ đồ chơi, nhưng tôi sẽ thêm nó vào OP. – NioBium