Tworzenie pojedynczej funkcji na listach, ByteStrings i Texts (i być może innych podobnych reprezentacjach)
Piszę funkcję, która przeszukuje niektóre sekwencje dowolnych symboli. Chciałbym, aby była wystarczająco ogólna, aby działała na listach,Foldable
s równie dobrzeByteString
s iText
s. Uogólniając toFoldable
jest proste. Ale jak zawrzećByteString
s iText
s? Jasne, że mogę się nawrócićByteString
do listy, a następnie zadzwoń do mojej funkcji, ale stracę wszystkie zaletyByteString
s.
Aby mieć konkretny przykład, powiedzmy, że chcemy utworzyć funkcję histogramu:
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
Ale ponieważ żaden z nichByteString
ani Tekst nie może byćFoldable
(przechowuje tylkoWord8
s /Char
s, a nie dowolne elementy), utknąłem z tworzeniem większej liczby funkcji, które wyglądajądokładnie jak poprzednio, tylko z różnymi podpisami typów:
histogramBS :: B.ByteString -> Histogram Word8
histogramBS = B.foldl (flip histogramStep) empty
histogramText :: T.Text -> Histogram Char
histogramText = T.foldl (flip histogramStep) empty
To jest coś, czego nie można oczekiwać w języku funkcjonalnym, takim jak Haskell.
Jak sprawić, aby było ogólne, pisaćhistogram
raz i na zawsze?