Я пишу функцию, которая выполняет поиск в последовательности произвольных символов. Я хотел бы сделать его достаточно общим, чтобы он работал со списками, Foldable
, а также с ByteString
и Text
. Обобщить его до Foldable
просто. Но как включить ByteString
s и Text
s? Конечно, я мог бы преобразовать ByteString
в список, а затем вызвать свою функцию, но я потерял бы все преимущества ByteString
s.
Чтобы иметь конкретный пример, скажем, мы хотим сделать функцию гистограммы:
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
, ни Text не могут быть Foldable
(он хранит только Word8
s/Char
s, а не произвольные элементы), я застрял в создании дополнительных функций, которые выглядят точно как предыдущая, только с другим типом подписи:
histogramBS :: B.ByteString -> Histogram Word8
histogramBS = B.foldl (flip histogramStep) empty
histogramText :: T.Text -> Histogram Char
histogramText = T.foldl (flip histogramStep) empty
Это то, чего нельзя ожидать от функционального языка, такого как Haskell.
Как сделать его общим, написать histogram
раз и навсегда?