packages feed

atp-0.1.0.0: test/Property/Modifiers/AlphaEquivalent.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}

{-|
Module       : Property.Modifiers.AlphaEquivalent
Description  : QuickCheck generators of alpha-equivalent and alpha-inequivalent
               first-order expressions.
Copyright    : (c) Evgenii Kotelnikov, 2019-2021
License      : GPL-3
Maintainer   : evgeny.kotelnikov@gmail.com
Stability    : experimental
-}

module Property.Modifiers.AlphaEquivalent (
  genAlphaEquivalent,
  genAlphaInequivalent
) where

import Control.Monad.Trans (lift)

import Test.QuickCheck (Arbitrary(..), Gen, suchThat, elements)

import ATP.FOL


-- * Alpha-equivalent first-order expressions.

genAlphaEquivalent :: FirstOrder e => e -> Gen e
genAlphaEquivalent = getAlphaEquivalence . evalAlphaT . alpha

newtype AlphaEquivalence m a = AlphaEquivalence { getAlphaEquivalence :: m a }
  deriving (Functor, Applicative, Monad)

instance MonadAlpha (AlphaEquivalence Gen) where
  binding _  = fresh
  occurrence = return


-- * Alpha-inequivalent first-order expressions.

genAlphaInequivalent :: FirstOrder e => e -> Gen e
genAlphaInequivalent = getAlphaInequivalence . evalAlphaT . alpha

newtype AlphaInequivalence m a = AlphaInequivalence { getAlphaInequivalence :: m a }
  deriving (Functor, Applicative, Monad)

instance MonadAlpha (AlphaInequivalence Gen) where
  binding _  = stale
  occurrence = anythingBut


-- * Helper functions

fresh :: AlphaT (AlphaEquivalence Gen) Var
fresh = do
  vs <- scope
  lift . AlphaEquivalence $ arbitrary `suchThat` (`notElem` vs)

stale :: AlphaT (AlphaInequivalence Gen) Var
stale = do
  vs <- scope
  lift . AlphaInequivalence $ if null vs then arbitrary else elements vs

anythingBut :: Var -> AlphaT (AlphaInequivalence Gen) Var
anythingBut v = lift . AlphaInequivalence $ arbitrary `suchThat` (/= v)