-- | Utility functions
module Peras.Util where

open import Haskell.Prelude hiding (_<_; _>_)
open import Haskell.Extra.Dec
open import Haskell.Extra.Refinement
open import Haskell.Law.Eq.Def
open import Haskell.Law.Eq.Instances

import Data.Bool
open import Data.Nat using (; NonZero; _≤_; _<_; _≥_; _>_; z≤n; s≤s; z<s; s<s)

{-# FOREIGN AGDA2HS
  {-# OPTIONS_GHC -fno-warn-missing-pattern-synonym-signatures #-}
  {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
  {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
  {-# OPTIONS_GHC -fno-warn-type-defaults #-}
  {-# OPTIONS_GHC -fno-warn-unused-imports #-}
  {-# OPTIONS_GHC -fno-warn-unused-matches #-}
  import GHC.Integer
#-}

uneraseNonZero :  {n}  @0 NonZero n  NonZero n
uneraseNonZero {zero} ()
uneraseNonZero {suc n} _ = _

maybeToList : Maybe a  List a
maybeToList Nothing = []
maybeToList (Just x) = x  []

{-# COMPILE AGDA2HS maybeToList #-}

listToMaybe : List a  Maybe a
listToMaybe [] = Nothing
listToMaybe (x  _) = Just x

{-# COMPILE AGDA2HS listToMaybe #-}

maximumBy : {a : Set}  a  (a  a  Ordering)  List a  a
maximumBy candidate _ [] = candidate
maximumBy {a} candidate f (x  xs) =
  case f candidate x of λ where
    GT  maximumBy candidate f xs
    _  maximumBy x f xs
{-# COMPILE AGDA2HS maximumBy #-}

comparing :  Ord b   (a  b)  a  a  Ordering
comparing f x y = compare (f x) (f y)
{-# COMPILE AGDA2HS comparing #-}

mapMaybe : {a b : Set}  (a  Maybe b)  List a  List b
mapMaybe p []       = []
mapMaybe p (x  xs) with p x
... | Just y  = y  mapMaybe p xs
... | Nothing =     mapMaybe p xs

-- mapMaybe is exported in rewrites.yaml

isYes :  {A : Set}  Dec A  Bool
isYes (True  _ ) = True
isYes (False  _ ) = False

{-# COMPILE AGDA2HS isYes #-}

TTrue :  {A : Set}  Dec A  Set
TTrue a = Data.Bool.T (isYes a)

toTT :  {A : Set}  {a : Dec A}  value a  True  TTrue {A} a
toTT refl = tt

@0 isYes≡True⇒TTrue :  {A : Set}  {a : Dec A}  isYes a  True  TTrue {A} a
isYes≡True⇒TTrue x = toTT (isYes≡True⇒value≡True x)
  where
    isYes≡True⇒value≡True :  {A : Set}  {a : Dec A}  isYes a  True  value a  True
    isYes≡True⇒value≡True {a = True  _ } _ = refl

@0 toWitness :  {A : Set} {a : Dec A}  TTrue a  A
toWitness {a = True  prf } _ = prf

_×-reflects_ :  {a b} {A B : Set}  Reflects A a  Reflects B b  Reflects (A × B) (a && b)
_×-reflects_ {True} {True} x y = x , y
_×-reflects_ {True} {False} _ y = y  snd
_×-reflects_ {False} {True} x _ = x  fst
_×-reflects_ {False} {False} x _ = x  fst

decP :  {A B : Set}  Dec A  Dec B  Dec (A × B)
decP (va  pa ) (vb  pb ) = (va && vb )  pa ×-reflects pb 

{-# COMPILE AGDA2HS decP #-}

_⊎-reflects_ :  {a b} {A B : Set}  Reflects A a  Reflects B b  Reflects (Either A B) (a || b)
_⊎-reflects_ {True} {True} x _ = Left x
_⊎-reflects_ {True} {False} x _ = Left x
_⊎-reflects_ {False} {True} _ y = Right y
_⊎-reflects_ {False} {False} x y = either x y

decS :  {A B : Set}  Dec A  Dec B  Dec (Either A B)
decS (va  pa ) (vb  pb ) = (va || vb )  pa ⊎-reflects pb 

{-# COMPILE AGDA2HS decS #-}

eqDec :  (x y : Nat)  Dec (x  y)
eqDec x y = (x == y)  isEquality x y 

{-# COMPILE AGDA2HS eqDec #-}

postulate
  eq :  (x y : )  Dec (x  y)
  ge :  (x y : )  Dec (x  y)
  gt :  (x y : )  Dec (x > y)

{-# FOREIGN AGDA2HS
  eq :: Integer -> Integer -> Bool
  eq = (==)

  gt :: Integer -> Integer -> Bool
  gt = gtInteger

  ge :: Integer -> Integer -> Bool
  ge = geInteger
#-}