packages feed

express-1.0.14: test/canon.hs

-- Copyright (c) 2017-2024 Rudy Matela.
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
import Test

main :: IO ()
main  =  mainTest tests 5040

tests :: Int -> [Bool]
tests n  =
  [ True

  , canonicalize (xx -+- yy)
              == (xx -+- yy)
  , canonicalize (jj -+- (ii -+- ii))
              == (xx -+- (yy -+- yy))
  , canonicalize ((jj -+- ii) -+- (xx -+- xx))
              == ((xx -+- yy) -+- (zz -+- zz))

  -- these are just tests:
  -- canonicalizeWith expects the resulting list of the arg function to be infinite
  , canonicalizeWith (const ["i","j","k","l"]) (xx -+- yy)
                                            == (ii -+- jj)
  , canonicalizeWith (const ["i","j","k","l"]) (jj -+- (ii -+- ii))
                                            == (ii -+- (jj -+- jj))
  , canonicalizeWith (const ["i","j","k","l"]) ((jj -+- ii) -+- (xx -+- xx))
                                            == ((ii -+- jj) -+- (kk -+- kk))

  , canonicalize (xx -+- ord' cc) == (xx -+- ord' cc)
  , canonicalize (yy -+- ord' dd) == (xx -+- ord' cc)
  , canonicalize (ff xx -+- gg yy -+- ff yy) == (ff xx -+- gg yy -+- ff yy)
  , canonicalize (gg yy -+- ff xx -+- gg xx) == (ff xx -+- gg yy -+- ff yy)
  , canonicalizeWith (lookupNames $ reifyName (undefined :: Int -> Int -> Int) ++ preludeNameInstances)
      (zz -?- kk) == (var "f" (undefined :: Int -> Int -> Int) :$ xx :$ yy)

  -- canonicalizing holes --
  , canonicalize (hole (undefined :: Int       )) == xx
  , canonicalize (hole (undefined :: Bool      )) == pp
  , canonicalize (hole (undefined :: Char      )) == cc
  , canonicalize (hole (undefined :: [Int]     )) == xxs
  , canonicalize (hole (undefined :: [Char]    )) == ccs
  , canonicalize (hole (undefined :: ()        )) == var "u" ()
  , canonicalize (hole (undefined :: Integer   )) == var "x" (undefined :: Integer)
  , canonicalize (hole (undefined :: [Integer] )) == var "xs" (undefined :: [Integer])
  , canonicalize (hole (undefined :: Maybe Int )) == var "mx" (undefined :: Maybe Int)
  , canonicalize (hole (undefined :: (Int,Int) )) == var "xy" (undefined :: (Int,Int))

  , canonicalVariations (zero -+- xx) == [zero -+- xx]
  , canonicalVariations (zero -+- i_) == [zero -+- xx]
  , canonicalVariations (i_ -+- i_) == [xx -+- yy, xx -+- xx]
  , canonicalVariations (i_ -+- (i_ -+- ord' c_))
    == [ xx -+- (yy -+- ord' cc)
       , xx -+- (xx -+- ord' cc) ]

  , fastCanonicalVariations (ii -+- i_) == [ii -+- xx]
  , canonicalVariations ((i_ -+- i_) -+- (ord' c_ -+- ord' c_))
    == [ (xx -+- yy) -+- (ord' cc -+- ord' dd)
       , (xx -+- yy) -+- (ord' cc -+- ord' cc)
       , (xx -+- xx) -+- (ord' cc -+- ord' dd)
       , (xx -+- xx) -+- (ord' cc -+- ord' cc) ]

  , canonicalVariations (i_)
    == [ xx ]
  , canonicalVariations (i_ -+- i_)
    == [ xx -+- yy
       , xx -+- xx ]
  , canonicalVariations (i_ -+- i_ -+- i_)
    == [ xx -+- yy -+- zz
       , xx -+- yy -+- xx
       , xx -+- yy -+- yy
       , xx -+- xx -+- yy
       , xx -+- xx -+- xx
       ]
  , canonicalVariations (i_ -+- i_ -+- i_ -+- i_)
    == [ xx -+- yy -+- zz -+- xx'
       , xx -+- yy -+- zz -+- xx
       , xx -+- yy -+- zz -+- yy
       , xx -+- yy -+- zz -+- zz
       , xx -+- yy -+- xx -+- zz
       , xx -+- yy -+- xx -+- xx
       , xx -+- yy -+- xx -+- yy
       , xx -+- yy -+- yy -+- zz
       , xx -+- yy -+- yy -+- xx
       , xx -+- yy -+- yy -+- yy
       , xx -+- xx -+- yy -+- zz
       , xx -+- xx -+- yy -+- xx
       , xx -+- xx -+- yy -+- yy
       , xx -+- xx -+- xx -+- yy
       , xx -+- xx -+- xx -+- xx
       ]
  , canonicalVariations (i_ -+- ii -+- jj -+- i_)
    == [ xx -+- ii -+- jj -+- yy
       , xx -+- ii -+- jj -+- xx ]
  , canonicalVariations (i_ -+- xx -+- yy -+- i_)
    == [ zz -+- xx -+- yy -+- xx'
       , zz -+- xx -+- yy -+- zz ]


  , holds n $ \e -> let xs = map (length . nubVars) $ canonicalVariations e
                    in (head xs >) `all` tail xs
                    && (last xs <) `all` init xs
  , holds n $ \e -> all isHole (vars e)
                ==> isNub (vars (head (canonicalVariations e)))
  , holds n $ \e -> let es = canonicalVariations e
                    in (`isInstanceOf` head es) `all` tail es
                    && (last es `isInstanceOf`) `all` init es
  , holds n $ \e -> let es = canonicalVariations e
                    in length (nub (sort es)) == length es
  , holds n $ \e -> length (canonicalVariations e)
                 == product (map (bell . snd) . counts $ holes e)

  , holds n $ \e -> head (canonicalVariations e) == mostGeneralCanonicalVariation e
  , holds n $ \e -> last (canonicalVariations e) == mostSpecificCanonicalVariation e


  -- Behaviour on unhandled types --
  , map show (canonicalVariations a_)
    == ["x :: A"]

  , map show (canonicalVariations (faa_ :$ a_ :$ a_))
    == [ "f x y :: A"
       , "f x x :: A"
       ]

  , map show (canonicalVariations as_)
    == ["xs :: [A]"]

  , map show (canonicalVariations (appendA :$ as_ :$ as_))
    == [ "xs ++ ys :: [A]"
       , "xs ++ xs :: [A]"
       ]
  ]

a_ :: Expr
a_  =  hole (undefined :: A)

as_ :: Expr
as_  =  hole (undefined :: [A])

faa_ :: Expr
faa_  =  hole (undefined :: A -> A -> A)

appendA :: Expr
appendA  =  value "++" ((++) :: [A] -> [A] -> [A])

-- O(1) bell number implementation
-- only works up to 8
-- but this is enough for testing.
bell :: Int -> Int
bell 0  =  1
bell 1  =  1
bell 2  =  2
bell 3  =  5
bell 4  =  15
bell 5  =  52
bell 6  =  203
bell 7  =  877
bell 8  =  4140
bell _  =  error "bell: argument > 8, implement me!"