È possibile assemblare questa funzione da pezzi che sono standard o dovrebbero essere. La risposta accettata ha il giusto indizio sulle chiusure lampo. La mia risposta about differentiation and comonads fornisce un trattamento generale delle operazioni pertinenti, ma vorrei essere specifico qui.
ho definire il tipo di "liste con un foro elemento" come segue:
data Bwd x = B0 | Bwd x :< x deriving Show
type HoleyList x = (Bwd x, [x])
A rigor di termini, non ho bisogno di presentare le liste arretrate per farlo, ma ho così facilmente confuso se io devo invertire le cose nella mia testa. (Accade così che HoleyList
è la derivata formale []
.)
ora posso definire ciò che significa essere un elemento di lista nel suo contesto.
type InContext x = (HoleyList x, x)
L'idea è che il secondo componente della coppia appartenga tra la lista a ritroso e quella in avanti. Posso definire la funzione che si inserisce l'elenco di nuovo insieme (chiamato upF
nel trattamento generico.)
plug :: InContext x -> [x]
plug ((B0, xs), y) = y : xs
plug ((xz :< x, xs), y) = plug ((xz, y : xs), x)
posso definire anche la funzione che dà tutti i modi per fare una lista a parte (downF
genericamente).
selections :: [x] -> [InContext x]
selections = go B0 where
go xz [] = []
go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
Nota che
map snd (selections xs) = xs
map plug (selections xs) = map (const xs) xs
e ora siamo bene seguire la ricetta di Bartek.
selectModify :: (a -> Bool) -> (a -> a) -> [a] -> [[a]]
selectModify p f = map (plug . (id *** f)) . filter (p . snd) . selections
Cioè: filtrare le selezioni dal test, applicare la funzione all'elemento a fuoco, ricollegarlo insieme. Se si ha a che fare con l'attrezzatura per cerniere, si tratta di una fodera singola, e dovrebbe funzionare per qualsiasi functor differenziabile, non solo per le liste! Lavoro fatto!
> selectModify ((1 ==) . (`mod` 2)) (2*) [1..10]
[[2,2,3,4,5,6,7,8,9,10]
,[1,2,6,4,5,6,7,8,9,10]
,[1,2,3,4,10,6,7,8,9,10]
,[1,2,3,4,5,6,14,8,9,10]
,[1,2,3,4,5,6,7,8,18,10]]
Che cos'è un dito? – aochagavia
Una lente di movimento può anche essere vista come un dito. –
L'ultimo suggerimento 'zip' è essenzialmente l'idioma che avrei usato per scrivere rapidamente questo, ma aggiungerò semplicemente una nota che non è necessario la parte' init $' - l'ultima coppia viene automaticamente filtrata da il modello '(a, (x: b))'. –