Desidero utilizzare Kmett's lens library per accedere a un elemento di un elenco (chiave, valore) sotto una chiave specifica. In altre parole, vorrei sostituire questo codice con qualcosa di più idiomatica e, forse, più corta:Utilizzare un obiettivo per sostituire un elemento specifico di un elenco (chiave, valore)
type Headers = [ (ByteString, ByteString) ]
headerLens ::
Functor f =>
ByteString ->
(Maybe ByteString -> f (Maybe ByteString)) ->
Headers ->
f Headers
headerLens header_name f headers
| old_header_value <- fetchHeader headers header_name = fmap
(\ new_header_value ->
replaceHeaderValue
headers
header_name
new_header_value
)
(f old_header_value)
in cui le funzioni di supporto sono definiti come di seguito:
-- | Looks for a given header and returns the value, if any
fetchHeader :: Headers -> ByteString -> Maybe ByteString
fetchHeader headers header_name =
snd <$> find (\ x -> fst x == header_name) headers
-- | replaceHeaderValue headers header_name maybe_header_value looks for
-- header_name. If header_name is found and maybe_header_value is nothing, it
-- returns a new headers list with the header deleted. If header_name is found
-- and header_value is Just new_value, it returns a new list with the header
-- containing the new value. If header_name is not in headers and maybe_header_value
-- is Nothing, it returns the original headers list. If header_name is not in headers
-- and maybe_header_value is Just new_value, it returns a new list where the last element
-- is (header_name, new_value)
replaceHeaderValue :: Headers -> ByteString -> Maybe ByteString -> Headers
replaceHeaderValue headers header_name maybe_header_value =
disect id headers
where
disect builder [] = case maybe_header_value of
Nothing -> headers
Just new_value -> builder $ (header_name, new_value):[]
disect builder ([email protected](hn,hv) : rest)
| hn /= header_name =
disect
(\ constructed_list -> builder $ el:constructed_list)
rest
| otherwise = case maybe_header_value of
Nothing -> builder rest
Just new_value -> builder $ (hn, new_value):rest
Grazie @bheklilr. Hai ragione sul fatto che l'ordine è importante, e in generale mi sono astenuto dall'ottimizzazione prima della profilazione. – dsign
@dsign Se questo è il caso, usa semplicemente il tipo 'Headers', sostituisci' M.lookup' con 'Prelude.lookup' e reimplementa [' Data.Map.alter'] (http: //hackage.haskell. org/package/containers-0.5.6.3/docs/src/Data-Map-Base.html # alter) per gli elenchi di associazioni, che saranno un po 'complicati. Oppure puoi sfogliare Hackage per un po 'cercando di scoprire se qualcuno lo ha già fatto, perché probabilmente lo hanno fatto. – bheklilr
Buon punto. Un piccolo dettaglio sgradevole che ho appena realizzato è che non posso obbedire alle leggi dell'obiettivo nella mia configurazione attuale .... quindi sì, penso di aver bisogno di passare a una mappa e ordinare i tasti con una funzione personalizzata (non è lessicografico, ma c'è un ordine * corretto *). Grazie! – dsign