module Decidable.Decidable

import Data.Rel
import Data.Fun

||| An n-ary relation is decidable if we can make a `Dec`
||| of its result type for each combination of inputs
public export
IsDecidable : (k : Nat) -> (ts : Vect k Type) -> Rel ts -> Type
IsDecidable k ts p = liftRel (the (Vect k Type) ts) (the (Rel ts) p) Dec

||| Interface for decidable n-ary Relations
public export
interface Decidable k ts p where
  total decide : IsDecidable k ts p

||| Given a `Decidable` n-ary relation, provides a decision procedure for
||| this relation.
decision : (ts : Vect k Type) -> (p : Rel ts) -> (Decidable k ts p) => liftRel ts p Dec
decision ts p = decide {ts} {p}

using (a : Type, x : a)
  public export
  data Given : Dec a -> Type where
    Always : Given (Yes x)

module Decidable.Decidable

import Data.Rel
import Data.Fun

public export
isNo : Dec a -> Bool
isNo (Yes _) = False
isNo (No _) = True

public export
isYes : Dec a -> Bool
isYes (Yes _) = True
isYes (No _) = False

||| Proof that some `Dec` is actually `Yes`
public export
data IsYes : Dec a -> Type where
  ItIsYes : IsYes (Yes prf)

public export
Uninhabited (IsYes (No contra)) where
  uninhabited ItIsYes impossible

||| Decide whether a 'Dec' is 'Yes'
public export
isItYes : (v : Dec a) -> Dec (IsYes v)
isItYes (Yes _) = Yes ItIsYes
isItYes (No _) = No absurd

||| An n-ary relation is decidable if we can make a `Dec`
||| of its result type for each combination of inputs
public export
IsDecidable : (k : Nat) -> (ts : Vect k Type) -> Rel ts -> Type
IsDecidable k ts p = liftRel (the (Vect k Type) ts) (the (Rel ts) p) Dec

||| Interface for decidable n-ary Relations
public export
interface Decidable k ts p where
  total decide : IsDecidable k ts p

||| Given a `Decidable` n-ary relation, provides a decision procedure for
||| this relation.
decision : (ts : Vect k Type) -> (p : Rel ts) -> (Decidable k ts p) => liftRel ts p Dec
decision ts p = decide {ts} {p}

using (a : Type, x : a)
  public export
  data Given : Dec a -> Type where
    Always : Given (Yes x)
