I'm writing a function that does some searching in a sequence of arbitrary symbols. I'd like to make it generic enough so that it works on lists, Foldable
s as well on ByteString
s and Text
s. Generalizing it to Foldable
is simple. But how to include ByteString
s and Text
s? Sure I could convert ByteString
into a list and then call my function, but I'd lose all the advantages ByteString
s.
To have a concrete example let's say we want to make a histogram function:
import Control.Monad.State
import qualified Data.Foldable as F
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Word
import qualified Data.ByteString as B
import qualified Data.Text as T
type Histogram a = Map a Int
empty :: (Ord a) => Histogram a
empty = Map.empty
histogramStep :: (Ord a) => a -> Histogram a -> Histogram a
histogramStep k = Map.insertWith (+) k 1
histogram :: (Ord a, F.Foldable t) => t a -> Histogram a
histogram = F.foldl (flip histogramStep) empty
But since neither ByteString
nor Text can be Foldable
(it stores just Word8
s/Char
s, not arbitrary elements), I'm stuck with creating more functions that look exactly like the one before, just with a different type signatures:
histogramBS :: B.ByteString -> Histogram Word8
histogramBS = B.foldl (flip histogramStep) empty
histogramText :: T.Text -> Histogram Char
histogramText = T.foldl (flip histogramStep) empty
This is something one does not expect in a functional language like Haskell.
How to make it generic, to write histogram
once and for all?