I need to create an instance of Show of a somewhat complicated type that represents a C++ function. The serialization gives me a Haskell interpretation of the said function.It works as I wish but it looks utterly horrible, with the string concatenations, point-free conversions and nested let bindings.  How could I improve readability of the code?instance Show Function where    show (Function templateArgs returnT fname fArgs) =        let toLowerIfPolymorphic argName =               let lcArg = strToLower argName in                    if lcArg `elem` (map snd templateArgs)                    then lcArg                    else id argName in        concat [            fname,  :: (,            intercalate ,  (                filter (/=) . map (                \(concept, tIdent) ->                    if not $ elem concept [Any, typename, class]                    then concept ++   ++ strToLower tIdent                    else                 ) $ templateArgs                ), ) => ,            intercalate  ->  (                map toLowerIfPolymorphic . map (show . fst) $ fArgs            ),            (if not $ null fArgs then  ->  else ),            toLowerIfPolymorphic . show $ returnT        ]The Function is:data Function = Function {                    funcTemplateArgs :: [(Concept, Identifier)],                    funcReturnT      :: CppType,                    funcName         :: String,                    funcArgs         :: [(CppType, Identifier)]                }CppType is basically a sum-type representing Scalar and Parameterzied types. Just synonyms for tuples. Concept / Identifier is a String synonym. Everything is an instance of Show.Also I find the if condition then f else id very strange. Do nothing if false is somewhat silly.
Textual representation of a C++ function
haskell;formatting