I needed to put together a Bayes classifier quickly to test an idea and did not want to pull in anything large from Hackage. If you ever find yourself in the same situation, here is the code:
module Bayes where
import Data.Map.Strict (Map(..), (!), elems)
newtype Classifier c s = Classifier { getClass :: Map c [s] }
count :: Eq a => a -> [a] -> Int
count y = foldl (\acc x -> if y == x then acc + 1 else acc) 0
classSize :: Ord c => Classifier c s -> c -> Int
classSize cl = length . (getClass cl !)
totalSize :: Classifier c s -> Int
totalSize = length . concat . elems . getClass
sampleCount :: Eq s => Classifier c s -> s -> Int
sampleCount cl s = count s . concat . elems . getClass $ cl
sampleCountInClass :: (Ord c, Eq s) => Classifier c s -> s -> c -> Int
sampleCountInClass cl s = count s . (getClass cl !)
-- P(C)
prior :: Ord c => Classifier c s -> c -> Double
prior cl c = if tot == 0 then 0 else tr / fromIntegral tot
where tr = fromIntegral $ classSize cl c
tot = totalSize cl
-- P(D|C)
likelihood :: (Ord c, Eq s) => Classifier c s -> s -> c -> Double
likelihood cl s c = if tr == 0 then 0 else ss / fromIntegral tr
where ss = fromIntegral $ sampleCountInClass cl s c
tr = classSize cl c
-- P (D)
evidance :: Eq s => Classifier c s -> s -> Double
evidance cl s = if tot == 0 then 0 else sam / fromIntegral tot
where sam = fromIntegral $ sampleCount cl s
tot = totalSize cl
-- P(C|D) = P(D|C) * P(C) / P(D)
posterior :: (Ord c, Eq s) => Classifier c s -> c -> s -> Double
posterior cl c s = l * p / e
where p = prior cl c
l = likelihood cl s c
e = evidance cl s
-- ln $ P(C|D) / P(not-C|D)
logLike :: (Ord c, Eq s) => Classifier c s -> c -> s -> Double
logLike cl c s = log $ p / (1 - p)
where p = posterior cl c s