Dynamic field access in Haskell I have to transform a response into the internal Coordinate record, some of the fields are lists and I need to handle empty lists case.

Records:

newtype GeoResponse =
  GeoResponse
    { results :: [ResultResponse]
    }
  deriving (Eq, Show, Generic)

newtype ResultResponse =
  ResultResponse
    { locations :: [LocationResponse]
    }
  deriving (Eq, Show, Generic)

newtype LocationResponse =
  LocationResponse
    { latLng :: CoordinateResponse
    }
  deriving (Eq, Show, Generic)

data CoordinateResponse =
  CoordinateResponse
    { lat :: !Double
    , lng :: !Double
    }
  deriving (Eq, Show, Generic)


Mapper function:

toCoordinate :: GeoResponse -&gt; Coordinate
toCoordinate (GeoResponse (ResultResponse [LocationResponse (CoordinateResponse lat lng)]:_)) =
  Coordinate lat lng
toCoordinate _ = Coordinate 0 0


So I didn't find a better way to get Coordinate without pattern match, but it looks a bit ugly to me.

Do you have any suggestion to improve my code?
Note that, if you just remove the tag Response from all your types (including unifying the types CoordinateResponse and Coordinate which seem like they ought to be a single type), it's already a lot more readable:

toCoordinate :: Geo -&gt; Coordinate
toCoordinate (Geo (Result [Location coord]:_)) = coord
toCoordinate _ = Coordinate 0 0


Also, the Location newtype doesn't seem to be serving any purpose, so maybe Location and Coordinate should just be the same type, too, which would remove a level.

Otherwise, what you've written is pretty idiomatic.  It's possible to use coerce to "cut through" all of the newtypes, so you could write:

import Data.Coerce

toCoordinate' :: GeoResponse -&gt; Coordinate
toCoordinate' gr = case coerce gr of
  [CoordinateResponse lat lng]:_ -&gt; Coordinate lat lng
  _                              -&gt; Coordinate 0 0


or if CoordinateResponse and Coordinate were the same type:

toCoordinate' :: Geo -&gt; Coordinate
toCoordinate' gr = case coerce gr of
  [coord]:_ -&gt; coord
  _         -&gt; Coordinate 0 0


That's obviously shorter, though it may hide what you're doing.  It seems important that you are pattern matching against the first of (possibly many) ResultResponse values but requiring that response to consist of a single LocationResponse, and that's not so obvious from this version.