packages feed

speculate-0.4.6: bench/trilean.hs

-- bench/trilean.hs -- Speculate example on trileans
--
-- Copyright (C) 2021  Rudy Matela
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
--
--
-- If used correctly,
-- Speculate deals with Trileans just fine producing correct equations.
--
--
-- The point of this example is to make Speculate produce incorrect equations
-- by failing to include all possible values on the 'Listable' enumeration.
--
-- Of the three possible trilean values (@M@, @F@ and @T@),
-- here we fail to enumerate @M@.  This ultimately causes Speculate print:
--
-- > p == M
--
-- How does that happen?
--
-- We first test to discover that:
--
-- > p &&& F == F
--
-- This is only true when x is F and T (the tested values)
-- but not true in general.
-- Speculate does not know this, then by consequence,
-- it infers:
--
-- > M &&& F == F
--
-- Which, using the correct equation @ M &&& p  ==  M @, rewrites to:
--
-- > M == F
--
-- Similarly we also get that:
--
-- > T == M
--
-- Ultimately arriving at:
--
-- > p == M
--
--
-- This illustrates why Speculate cannot consider equality between error values
-- using 'Test.LeanCheck.Error.errorToEither'
-- or    'Test.LeanCheck.Error.errorToNothing'.
--
-- You could also think now, to include error values in the generation,
-- however you will lose interesting equations if you do that
-- so it does not pay off.

{-# Language DeriveDataTypeable, StandaloneDeriving #-}  -- for GHC <= 7.8

import Test.Speculate hiding ((|||), (&&&))
import Test.Speculate.Function.A10
import Test.LeanCheck.Function.ShowFunction

data Tril = M | F | T deriving (Show, Eq, Ord)

deriving instance Typeable Tril  -- for GHC <= 7.8

instance Listable Tril where
  tiers  =  cons0 F
         \/ cons0 T
--       \/ cons0 M `ofWeight` 1
-- Here we intentionally fail to enumerate M.

instance ShowFunction Tril where bindtiers = bindtiersShow

instance Name Tril where
  name _  =  "p"

neg :: Tril -> Tril
neg T = F
neg F = T
neg M = M

unc :: Tril -> Tril
unc M = T
unc _ = F

(&&&) :: Tril -> Tril -> Tril
M &&& _  =  M
_ &&& M  =  M
T &&& T  =  T
_ &&& _  =  F

(|||) :: Tril -> Tril -> Tril
M ||| _  =  M
_ ||| M  =  M
F ||| F  =  F
_ ||| _  =  T

(===>) :: Tril -> Tril -> Tril
M ===> _  =  M
F ===> _  =  T
T ===> p  =  p

main :: IO ()
main = speculate args
  { constants =
      [ showConstant M
      , showConstant F
      , showConstant T
      , constant "neg" neg
      , constant "&&&" (&&&)
--    , constant "|||" (|||)
      ]
  , instances = [ reifyInstances (undefined :: Tril)
--              , reifyInstances (undefined :: Tril -> Tril -> Tril)
                ]
  }