countable-1.2: src/Data/Searchable.hs
module Data.Searchable
( Searchable(..)
, forsome
, forevery
, Finite(..)
, finiteSearch
, finiteCountPrevious
, finiteCountMaybeNext
) where
import Control.Applicative
import Data.Countable
import Data.Int
import Data.List
import Data.Maybe
import Data.Traversable
import Data.Void
import Data.Word
import Prelude
-- | It turns out there are 'Searchable' instances that are not 'Finite'.
-- The @(c -> s)@ instance is based on the algorithm at
-- <http://math.andrej.com/2007/09/28/seemingly-impossible-functional-programs/>.
class Searchable a where
search :: (a -> Maybe b) -> Maybe b
forsome :: (Searchable a) => (a -> Bool) -> Bool
forsome =
isJust .
search .
(\ab a ->
if ab a
then Just ()
else Nothing)
forevery :: (Searchable a) => (a -> Bool) -> Bool
forevery p = not (forsome (not . p))
instance (Searchable a) => Searchable (Maybe a) where
search mamb =
case mamb Nothing of
Just b -> Just b
Nothing -> search (mamb . Just)
instance (Searchable a, Searchable b) => Searchable (Either a b) where
search eabb =
case search (eabb . Left) of
Just b -> Just b
_ -> search (eabb . Right)
instance (Searchable a, Searchable b) => Searchable (a, b) where
search abb = search (\a -> search (\b -> abb (a, b)))
instance (Countable c, Searchable s) => Searchable (c -> s) where
search csmx =
case search Just of
Just def -> let
prepend s cs c =
case countPrevious c of
Just c' -> cs c'
Nothing -> s
-- | prepend :: s -> (c -> s) -> c -> s
-- | findcs :: ((c -> s) -> Maybe x) -> c -> s
findcs csm = let
mx =
search
(\s' -> do
_ <- search (csm . (prepend s'))
return s')
s =
case mx of
Just s' -> s'
_ -> def
in prepend s (findcs (csm . (prepend s)))
in csmx (findcs csmx)
Nothing -> Nothing
-- | There are a finite number of values (possibly zero).
class (Searchable a, Countable a) => Finite a where
-- | Not necessarily in counting order.
allValues :: [a]
assemble ::
forall b f. (Applicative f)
=> (a -> f b)
-> f (a -> b)
assemble afb = fmap listLookup (traverse (\a -> fmap (\b -> (a, b)) (afb a)) allValues)
where
-- listLookup :: [(a,b)] -> a -> b;
listLookup [] _ = error "missing value" -- this should never happen
listLookup ((a, b):_) a'
| a == a' = b
listLookup (_:l) a' = listLookup l a'
firstJust :: [Maybe a] -> Maybe a
firstJust [] = Nothing
firstJust ((Just a):_) = Just a
firstJust (Nothing:mas) = firstJust mas
finiteSearch :: (Finite a) => (a -> Maybe b) -> Maybe b
finiteSearch p = firstJust (fmap p allValues)
finiteCountPrevious :: (Finite a) => a -> Maybe a
finiteCountPrevious x = findp Nothing allValues
where
findp ma (a:_)
| a == x = ma
findp _ (a:as) = findp (Just a) as
findp _ [] = seq x (error "missing value")
firstItem :: [a] -> Maybe a
firstItem [] = Nothing
firstItem (a:_) = Just a
finiteCountMaybeNext :: (Finite a) => Maybe a -> Maybe a
finiteCountMaybeNext Nothing = firstItem allValues
finiteCountMaybeNext (Just x) = findmn allValues
where
findmn (a:as)
| x == a = firstItem as
findmn (_:as) = findmn as
findmn [] = seq x (error "missing value")
instance Searchable Void where
search = finiteSearch
instance Finite Void where
allValues = []
assemble _ = pure absurd
instance Searchable () where
search = finiteSearch
instance Finite () where
allValues = [()]
assemble afb = liftA (\v _ -> v) (afb ())
instance Searchable Bool where
search = finiteSearch
instance Finite Bool where
allValues = [False, True]
assemble afb =
liftA2
(\f t x ->
if x
then t
else f)
(afb False)
(afb True)
instance Searchable Word8 where
search = finiteSearch
instance Finite Word8 where
allValues = enumFrom minBound
instance Searchable Word16 where
search = finiteSearch
instance Finite Word16 where
allValues = enumFrom minBound
instance Searchable Word32 where
search = finiteSearch
instance Finite Word32 where
allValues = enumFrom minBound
instance Searchable Word64 where
search = finiteSearch
instance Finite Word64 where
allValues = enumFrom minBound
instance Searchable Int8 where
search = finiteSearch
instance Finite Int8 where
allValues = enumFrom minBound
instance Searchable Int16 where
search = finiteSearch
instance Finite Int16 where
allValues = enumFrom minBound
instance Searchable Int32 where
search = finiteSearch
instance Finite Int32 where
allValues = enumFrom minBound
instance Searchable Int64 where
search = finiteSearch
instance Finite Int64 where
allValues = enumFrom minBound
instance (Finite a) => Finite (Maybe a) where
allValues = Nothing : (fmap Just allValues)
assemble mafb = liftA2 maybe (mafb Nothing) (assemble (mafb . Just))
instance (Finite a, Finite b) => Finite (Either a b) where
allValues = (fmap Left allValues) ++ (fmap Right allValues)
assemble eabfr = liftA2 either (assemble (eabfr . Left)) (assemble (eabfr . Right))
instance (Finite a, Finite b) => Finite (a, b) where
allValues = liftA2 (,) allValues allValues
assemble abfr = fmap (\abr (a, b) -> abr a b) (assemble (\a -> assemble (\b -> abfr (a, b))))