Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
IRTreeSpec.hs 2.47 KiB
{-# LANGUAGE BlockArguments #-}

module Control.Monad.IRTreeSpec where

import Control.Monad.IRTree
import qualified Control.Monad.IRTree as IRTree
import qualified Control.Monad.RTree as RTree
import Control.Monad.Writer.Strict
import Data.Bool
import Data.Expr as Expr
import Data.List.NonEmpty (nonEmpty)
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import Test.Hspec

spec :: Spec
spec = describe "examples" do
  handle "small-opr-expr" $
    Opr (Cnt 1) (Cnt 2)

  handle "small-let-expr" $
    Let "x" (Cnt 1) (Opr (Cnt 2) (Var "x"))

  handle "double-let-expr" $
    Let "x" (Cnt 1) (Let "y" (Cnt 2) (Opr (Var "x") (Var "y")))

  handle "double-overloading-let-expr" $
    Let "x" (Cnt 1) (Let "x" (Cnt 2) (Opr (Var "x") (Var "x")))
 where
  handle str e = describe (str <> " (" <> prettyExprS 0 e ")") do
    let me = runReaderT (Expr.rExpr e) Map.empty

    it "should extract" do
      IRTree.extract me `shouldBe` e

    let re = runReaderT (Expr.rExpr e) Map.empty

    let
      predicate :: Expr -> IO Bool
      predicate = pure . contains isOpr

    rex <- runIO $ RTree.reduce predicate re

    -- onGlitterWith
    --   ("test/expected/" <> str <> "-red")
    --   ( \fp () -> do
    --       (mex, result) <- runWriterT (IRTree.reduce (debugPredicate showString (prettyExprS 0) predicate) me)
    --       writeFile fp (appEndo result "")
    --       pure mex
    --   )
    --   do
    --     it "should produce the same results as the RTree" \mex -> do
    --       rex `shouldBe` mex

    it "should find an opr exponentially" do
      (mex, _) <- runWriterT (IRTree.reduceExp (debugPredicate showString (prettyExprS 0) predicate) me)
      rex `shouldBe` mex

    it "should find an opr fibonacci" do
      (mex, _) <- runWriterT (IRTree.reduceFib (debugPredicate showString (prettyExprS 0) predicate) me)
      rex `shouldBe` mex

    it "should reduce like iinputs" do
      forM_ (RTree.iinputs re) \(ii, e') -> do
        p <- toPredicate ii
        IRTree.reduce (const p) me `shouldReturn` Just e'

debugPredicate
  :: (Monad m)
  => (l -> ShowS)
  -> (i -> ShowS)
  -> (i -> m Bool)
  -> [(Bool, l)]
  -> i
  -> WriterT (Endo String) m Bool
debugPredicate ppl ppi predicate lst i = do
  x <- lift (predicate i)
  tell . Endo $
    showString (bool "0" "1" x)
      . showString ": "
      . ppi i
      . showString "\n"
      . case nonEmpty lst of
        Nothing -> showString "initial\n"
        Just lst' -> ppl (snd $ NE.last lst') . showString "\n"

  pure x