Fazendo uma única função funcionar em listas, ByteStrings e Textos (e talvez outras representações similares)
Eu estou escrevendo uma função que faz alguma pesquisa em uma seqüência de símbolos arbitrários. Eu gostaria de torná-lo genérico o suficiente para que ele funcione em listas,Foldable
s bem emByteString
areiaText
s. Generalizando paraFoldable
é simples. Mas como incluirByteString
areiaText
s? Claro que eu poderia converterByteString
em uma lista e depois chamar minha função, mas eu perderia todas as vantagensByteString
s.
Para ter um exemplo concreto, digamos que queremos fazer uma função histograma:
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
Mas já que nenhum dos doisByteString
nem o texto pode serFoldable
(armazena apenasWord8
s /Char
s, não elementos arbitrários), eu estou preso com a criação de mais funções que parecemexatamente como o anterior, apenas com um tipo diferente de assinaturas:
histogramBS :: B.ByteString -> Histogram Word8
histogramBS = B.foldl (flip histogramStep) empty
histogramText :: T.Text -> Histogram Char
histogramText = T.foldl (flip histogramStep) empty
Isso é algo que não se espera em uma linguagem funcional como o Haskell.
Como tornar genérico, escreverhistogram
de uma vez por todas?