La soluzione più semplice sarebbe quello di fare semplicemente due evalutations in modo indipendente:
catMaybesCount :: [Maybe a] -> ([a], Int)
catMaybesCount xs = (catMaybes xs, length $ filter isNothing xs)
Non so se GHC è in grado di ottimizzare questo correttamente, ma la soluzione per il conteggio length . filter p
Nothings
ha alcune peculiarità in ogni caso (vedi this SO post per una panoramica).
In teoria, questa soluzione potrebbe richiedere due passaggi sopra la lista, invece di quello
Si tratta di una soluzione ricorsiva risolvere questo problema mi si avvicinò con:
import Data.Maybe
-- | Equivalent to @[email protected], but additonally counts @[email protected] values
catMaybesCount :: [Maybe a] -> ([a], Int)
catMaybesCount xs = catMaybesCountWorker xs [] 0
-- | Worker function for @[email protected]
catMaybesCountWorker :: [Maybe a] -> [a] -> Int -> ([a], Int)
catMaybesCountWorker [] justs cnt = (justs, cnt)
catMaybesCountWorker (Nothing:xs) justs cnt =
catMaybesCountWorker xs justs (cnt + 1)
catMaybesCountWorker ((Just v):xs) justs cnt =
catMaybesCountWorker xs (justs ++ [v]) cnt
Come applicarlo a un elenco dovrebbe valutare la lista solo una volta, questo dovrebbe essere più efficiente.
Tuttavia, sono preoccupato per l'anti-idioma justs ++ [v]
, in quanto (:)
sarebbe più efficiente (vedere this discussion). Tuttavia, questo invertirà la lista risultante. Forse qualcuno con più conoscenze su questo argomento potrebbe dare un'occhiata a questo?
Si noti che questa funzione non terminerà per le liste infinite perché il conteggio Nothing
non potrà mai finire per valutare.
fonte
2014-08-27 18:37:53
Ancora un altro momento di usare [bella pieghevole] (http://squing.blogspot.com/2008/11 /beautiful-folding.html). –