In diesem Fall können Sie tatsächlich die newtypes
Paket, um dieses Problem allgemeiner zu lösen:
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
Sie auch eine generische Version haben könnte, die eine Newtype n (Maybe String)
wie
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
nimmt
Dann
> 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"
Als Erklärung dafür, wie das funktioniert, nimmt die ala'
Funktion eine newtype Wrapper die Instanz von Newtype
zu verwenden, eine Funktion, die wir in diesem Fall foldMap
sein wollen, um zu bestimmen:
foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
seit foldMap f
endet Da eine verallgemeinerte mconcat . map f
über Foldable
Typen statt nur Listen ist, dann eine Funktion die als "Präprozessor" zum Einhängen in die übergeordnete Funktion verwendet werden soll, übergeben an ala'
(foldMap
), dann in diesem Fall etwas Foldable t => t Node
zu verarbeiten. Wenn Sie den Vorverarbeitungsschritt nicht möchten, verwenden Sie einfach ala
, der id
für seinen Präprozessor verwendet. Die Verwendung dieser Funktion kann aufgrund ihres komplexen Typs manchmal schwierig sein, aber wie die Beispiele in der Dokumentation zeigen, ist foldMap
oft eine gute Wahl.
Die Macht ist, wenn Sie für Maybe String
Ihre eigenen newtype
Wrapper schreiben wollen:
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
Dann
> process' firstAsCaps input
Just "BAR"
Klingt wie 'erzwingen'. – Zeta
Wie soll der Prozess aussehen? Es könnte möglich sein, das 'newtype'-Paket zu verwenden, um das meiste davon zu verbergen. Alles was ich daraus machen kann, ist, dass 'Pick' zu einem rekursiven Typ gehören muss, da' Pick :: [a] -> PickType' und 'process :: PickType -> Maybe a', aber' First. process :: PickType -> Erste a', also 'xs :: [PickType]'? – bheklilr
Es ist nur ein Spielzeugbeispiel, aber ich werde es dem OP hinzufügen. – NioBium