Mappatura di un elenco di valori facoltativi in un elenco di valori facoltativo

2

Ho incontrato il seguente schema durante la programmazione in Haskell (ma lo schema potrebbe verificarsi in qualsiasi lingua che supporta elenchi, tipi di opzioni e mappatura di una funzione su un elenco). Ho tipi a e b e una funzione

f :: a -> Maybe b

Ora voglio definire una funzione che mappa f in un elenco di tipo [a] , ma non mi interessa avere un risultato di tipo [Maybe b] . Piuttosto, voglio avere Just [y1, ..., yn] , se [f(x1), ..., f(xn)] == [Just y1, ..., Just yn] e Nothing altrimenti (cioè se f(xi) == Nothing per almeno un i). Quindi il risultato deve essere di tipo Maybe [b] .

Ho risolto questo problema utilizzando la seguente funzione di supporto:

combine :: Maybe b -> Maybe [b] -> Maybe [b]
combine me ml = do
                   l <- ml
                   e <- me
                   Just (e : l) 

e poi

g :: (a -> Maybe b) -> [a] -> Maybe [b]
g f xs = foldr combine (Just []) (map f xs)

Quindi, ad esempio, se ho

f x = if x > 0 then Just x else Nothing
xs0 = [1, 2, 3, 4]
xs1 = [-1, -2, 3, 4]
xs2 = [-1, -2, -3, -4]

poi

map f xs0 = [Just 1, Just 2, Just 3, Just 4]
g f xs0   = Just [1, 2, 3, 4]
map f xs1 = [Nothing, Nothing, Just 3, Just 4]
g f xs1   = Nothing
map f xs2 = [Nothing, Nothing, Nothing, Nothing]
g f xs2   = Nothing

La soluzione con combine e foldr funziona, ma volevo chiederti se sei a conoscenza di una soluzione più compatta per trasformare una [Maybe a] in una Maybe [a] come descritto sopra.

    
posta Giorgio 03.02.2014 - 22:35
fonte

2 risposte

6

Vuoi una funzione con questa firma:

(a -> Maybe b) -> [a] -> Maybe [b]

Inserimento di questo in hoogle offre questa possibilità:

Prelude mapM :: Monad m => (a -> m b) -> [a] -> m [b]

Uno sguardo alla documentazione di Hackage per mapM dice che è lo stesso di:

mapM f = sequence . map f

e che la definizione di sequence è:

sequence       :: Monad m => [m a] -> m [a] 
sequence ms = foldr k (return []) ms
            where
              k m m' = do { x <- m; xs <- m'; return (x:xs) }

che è praticamente la tua soluzione foldr .

    
risposta data 03.02.2014 - 22:51
fonte
5

Il modo migliore per avvicinarti a questo è andare a Hoeting di FP Complete e digitare la firma che stai cercando,% codice%. Il primo hit è una funzione chiamata (a -> Maybe b) -> [a] -> Maybe [b] che è esattamente quello che stai cercando. Infatti funziona per tutti mapM s, non solo Monad . (Se vuoi essere ancora più generale, puoi usare Maybe )

    
risposta data 03.02.2014 - 22:49
fonte

Leggi altre domande sui tag