How about rewriting it as follows, first let's break out the pattern of composition into a separate function
compose :: [a -> a] -> a -> a
compose = foldr (.) id
You can visualize this as taking a list f : g : h : []
and replacing []
with id
and
:
with .
, leaving you with f . g . h . id
or f . g . h
.
Next let's use this to rewrite your example to make it a bit more legible
instance Show Bin where
showList = compose . map (showString . show)
Now this is a bit more legible than what you had even though it's functionally identical. In fact this may end up even compiling as the same thing since GHC may fuse it(?). we're transforming each item into a String -> String
or ShowS
, and then we're composing them all. Giving a name and type to compose
makes it much easier to see what's going on.
I suppose this could also be written
showList = appEndo . mconcat . map (Endo . showString . show)
This is identical to the above but relies on the fact that a -> a
forms a monoid and mconcat
generalizes the idea of combining a list of monoids to one. We need that Endo
bit because the monoid instance is actually defined for
newtype Endo a = End {appEndo :: a -> a}