Idris2/libs/contrib/Search/HDecidable.idr

147 lines
3.8 KiB
Idris

||| The content of this module is based on the paper
||| Applications of Applicative Proof Search
||| by Liam O'Connor
module Search.HDecidable
import Data.List.Lazy
import Data.List.Lazy.Quantifiers
import Data.List.Quantifiers
import Data.So
import Search.Negation
%default total
------------------------------------------------------------------------
-- Type, basic functions, and interface
||| Half a decider: when the search succeeds we bother building the proof
public export
record HDec (a : Type) where
constructor MkHDec
isTrue : Bool
evidence : So isTrue -> a
||| Happy path: we have found a proof!
public export
yes : a -> HDec a
yes = MkHDec True . const
||| Giving up
public export
no : HDec a
no = MkHDec False absurd
public export
fromDec : Dec a -> HDec a
fromDec (Yes p) = yes p
fromDec (No _) = no
public export
fromMaybe : Maybe a -> HDec a
fromMaybe = maybe no yes
public export
toMaybe : HDec a -> Maybe a
toMaybe (MkHDec True p) = Just (p Oh)
toMaybe (MkHDec False _) = Nothing
||| A type constructor satisfying AnHdec is morally an HDec i.e. we can
||| turn values of this type constructor into half deciders
||| It may be more powerful (like Dec) or more basic (like Maybe).
public export
interface AnHDec (0 t : Type -> Type) where
toHDec : t a -> HDec a
public export AnHDec Dec where toHDec = fromDec
public export AnHDec HDec where toHDec = id
public export AnHDec Maybe where toHDec = fromMaybe
------------------------------------------------------------------------
-- Implementations
public export
Functor HDec where
map f (MkHDec b prf) = MkHDec b (f . prf)
public export
Applicative HDec where
pure = yes
MkHDec False prff <*> _ = MkHDec False absurd
_ <*> MkHDec False _ = MkHDec False absurd
MkHDec True prff <*> MkHDec True prfx
= yes (prff Oh (prfx Oh))
||| Lazy in the second argument
public export
Alternative HDec where
empty = no
p@(MkHDec True _) <|> _ = p
_ <|> q = q
public export
Monad HDec where
MkHDec True x >>= f = f (x Oh)
_ >>= _ = no
public export
Show f => Show (HDec f) where
show (MkHDec True p) = "True: " ++ show (p Oh)
show _ = "False"
------------------------------------------------------------------------
-- Combinators
||| Half deciders are closed under product
public export
(&&) : (AnHDec l, AnHDec r) => l a -> r b -> HDec (a, b)
p && q = [| (toHDec p, toHDec q) |]
||| Half deciders are closed under sum
public export
(||) : (AnHDec l, AnHDec r) => l a -> r b -> HDec (Either a b)
p || q = [| Left (toHDec p) |] <|> [| Right (toHDec q) |]
||| Half deciders are closed negation. Here we use the `Negates` interface
||| so that we end up looking for *positive* evidence of something which is
||| much easier to find than negative one.
public export
not : (AnHDec l, Negates na a) => l na -> HDec (Not a)
not p = [| toNegation (toHDec p) |]
infixr 3 ==>
||| Half deciders are closed under implication
public export
(==>) : (AnHDec l, AnHDec r, Negates na a) => l na -> r b -> HDec (a -> b)
p ==> q = [| contra (not p) |] <|> [| const (toHDec q) |] where
contra : Not a -> a -> b
contra na a = void (na a)
namespace List
||| Half deciders are closed under the list quantifier any
public export
any : AnHDec l => (xs : List a) -> ((x : a) -> l (p x)) -> HDec (Any p xs)
any [] p = no
any (x :: xs) p = [| Here (toHDec (p x)) |] <|> [| There (any xs p) |]
||| Half deciders are closed under the list quantifier all
public export
all : AnHDec l => (xs : List a) -> ((x : a) -> l (p x)) -> HDec (All p xs)
all [] p = yes []
all (x :: xs) p = [| toHDec (p x) :: all xs p |]
namespace LazyList
||| Half deciders are closed under the lazy list quantifier any
public export
any : AnHDec l => (xs : LazyList a) -> ((x : a) -> l (p x)) -> HDec (Any p xs)
any [] p = no
any (x :: xs) p = [| Here (toHDec (p x)) |] <|> [| There (any xs p) |]