Заставить одну функцию работать со списками, ByteStrings и Texts (и, возможно, другими подобными представлениями)

Я пишу функцию, которая выполняет поиск в последовательности произвольных символов. Я хотел бы сделать его достаточно общим, чтобы он работал со списками,Foldableа также наByteStringс иTexts. Обобщая этоFoldable это просто. Но как включитьByteStringс иTexts? Конечно, я мог бы преобразоватьByteString в список, а затем вызвать мою функцию, но я бы потерял все преимуществаByteStrings.

Чтобы получить конкретный пример, скажем, мы хотим сделать функцию гистограммы:

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

Но так как ниByteString ни текст не может бытьFoldable (это хранит толькоWord8s /Charс, а не произвольные элементы), я застрял с созданием большего количества функций, которые выглядятименно так как и раньше, только с другими типами подписей:

histogramBS :: B.ByteString -> Histogram Word8
histogramBS = B.foldl (flip histogramStep) empty

histogramText :: T.Text -> Histogram Char
histogramText = T.foldl (flip histogramStep) empty

Это то, чего никто не ожидает от функционального языка, такого как Haskell.

Как сделать это универсальным, чтобы написатьhistogram раз и навсегда?

Ответы на вопрос(4)

Ваш ответ на вопрос