Я хочу использовать библиотеку линз от Kmett для доступа к элементу списка (ключ, значение) в конкретный ключ. Другими словами, я хотел бы заменить этот код чем-то более идиоматичным и, возможно, более коротким:
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 )
где функции поддержки определены следующим образом:
-- | 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 ( el@(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