countable-1.1: src/Data/Searchable.hs
{-# OPTIONS -fno-warn-orphans #-}
-- | This module also includes these orphan instances:
--
-- * @('Searchable' a,'Eq' b) => 'Eq' (a -> b)@ / /
--
-- * @('Finite' t) => 'Foldable' ((->) t)@ / /
--
-- * @('Finite' a) => 'Traversable' ((->) a)@ / /
--
-- * @('Show' a,'Finite' a,'Show' b) => 'Show' (a -> b)@ / /
module Data.Searchable
( Searchable(..)
, forsome
, forevery
, Finite(..)
, finiteSearch
, finiteCountPrevious
, finiteCountMaybeNext
) where
import Control.Applicative
import Data.Countable
import Data.Expression
import Data.Foldable hiding (find)
import Data.Int
import Data.List
import Data.Maybe
import Data.Monoid
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
instance (Searchable a, Eq b) => Eq (a -> b) where
p == q = forevery (\a -> p a == q a)
-- | 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'
instance (Finite t) => Foldable ((->) t) where
foldMap am ta = mconcat (fmap (am . ta) allValues)
instance (Finite a) => Traversable ((->) a) where
sequenceA = assemble
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))))
setpair :: (Eq a) => (a, b) -> (a -> b) -> (a -> b)
setpair (a', b') _ a
| a == a' = b'
setpair _ ab a = ab a
data IsoCountable x =
forall l. (Countable l) =>
MkIsoCountable (x -> l)
(l -> x)
isoCountableFn :: (Finite a, Countable b) => IsoCountable (a -> b)
isoCountableFn = makeFromList allValues
where
makeFromList :: (Eq a, Countable b) => [a] -> IsoCountable (a -> b)
makeFromList [] = MkIsoCountable (\_ -> ()) (\a -> seq a undefined)
makeFromList (a:as) =
case makeFromList as of
MkIsoCountable encode decode ->
MkIsoCountable (\ab -> (ab a, encode ab)) (\(b, l) -> setpair (a, b) (decode l))
instance (Finite a, Countable b) => Countable (a -> b) where
countPrevious =
case isoCountableFn of
MkIsoCountable encode decode -> (fmap decode) . countPrevious . encode
countMaybeNext =
case isoCountableFn of
MkIsoCountable encode decode -> (fmap decode) . countMaybeNext . (fmap encode)
instance (Finite a, AtLeastOneCountable b) => AtLeastOneCountable (a -> b) where
countFirst = \_ -> countFirst
data IsoInfiniteCountable x =
forall l. (InfiniteCountable l) =>
MkIsoInfiniteCountable (x -> l)
(l -> x)
isoInfiniteCountableFn :: (Finite a, AtLeastOneCountable a, InfiniteCountable b) => IsoInfiniteCountable (a -> b)
isoInfiniteCountableFn = makeFromList allValues
where
makeFromList :: (Eq a, InfiniteCountable b) => [a] -> IsoInfiniteCountable (a -> b)
makeFromList [] = undefined
makeFromList [a] = MkIsoInfiniteCountable (\ab -> ab a) (\b -> setpair (a, b) (\a' -> seq a' undefined))
makeFromList (a:as) =
case makeFromList as of
MkIsoInfiniteCountable encode decode ->
MkIsoInfiniteCountable (\ab -> (ab a, encode ab)) (\(b, l) -> setpair (a, b) (decode l))
instance (Finite a, AtLeastOneCountable a, InfiniteCountable b) => InfiniteCountable (a -> b) where
countNext =
case isoInfiniteCountableFn of
MkIsoInfiniteCountable encode decode -> decode . countNext . (fmap encode)
instance (Finite a, Finite b) => Finite (a -> b) where
allValues = sequenceA (\_ -> allValues)
assemble abfr =
runValueExpression
(Data.Foldable.foldr assemble1 (\ab -> ClosedExpression (abfr ab)) allValues (\_ -> error "missing value"))
where
-- assemble1 :: a -> ((a -> b) -> Expression a b f r) -> (a -> b) -> Expression a b f r
assemble1 a0 aber x =
OpenExpression
a0
(assemble
(\b0 ->
aber
(\a ->
if a == a0
then b0
else x a)))
instance (Show a, Finite a, Show b) => Show (a -> b) where
show f = "{" ++ (intercalate "," (fmap (\a -> (show a) ++ "->" ++ (show (f a))) allValues)) ++ "}"