В этом случае вы можете использовать пакет newtypes
для более общего решения этой проблемы:
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
Вы могли бы даже иметь более общую версию, которая принимает Newtype n (Maybe String)
как
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
затем
> 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"
В качестве объяснения того, как это работает, функция ala'
использует оболочку newtype для определения используемого экземпляра Newtype
, функции, которой в данном случае мы хотим быть foldMap
:
foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
поскольку foldMap f
оказывается обобщенным mconcat . map f
над Foldable
типами, а не просто списками, то функция, используемая в качестве «препроцессора» для подключения к функции более высокого порядка, передается ala'
(foldMap
), тогда в этом случае некоторые Foldable t => t Node
для обработки . Если вам не нужен шаг предварительной обработки, вы просто используете ala
, который использует id
в качестве своего препроцессора. Использование этой функции иногда может быть затруднено из-за ее сложного типа, но, как показывают примеры в документации, foldMap
часто является хорошим выбором.
Сила этого в том, что если вы хотите написать свою собственную оболочку newtype
для 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
затем
> process' firstAsCaps input
Just "BAR"
person
bheklilr
schedule
05.05.2015
coerce
. - person Zeta   schedule 05.05.2015process
? Можно использовать пакетnewtype
, чтобы скрыть большую часть этого. Все, что я могу сделать, это то, чтоPick
должен принадлежать к рекурсивному типу, посколькуPick :: [a] -> PickType
иprocess :: PickType -> Maybe a
, ноFirst . process :: PickType -> First a
, значит,xs :: [PickType]
? - person bheklilr   schedule 05.05.2015