{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -O2 -fplugin Test.Inspection.Plugin #-} module Fusion ( tests ) where import Control.Algebra import Control.Carrier.Error.Either import Control.Carrier.State.Strict import Test.Inspection as Inspection import Test.Tasty import Test.Tasty.HUnit tests :: TestTree tests = testGroup "fusion" [ testCase "eliminates StateCs" $ failureOf $(inspectTest $ 'countDown `doesNotUse` ''StateC) @?= Nothing , testCase "eliminates nested StateCs" $ failureOf $(inspectTest $ 'countBoth `doesNotUse` ''StateC) @?= Nothing , testCase "eliminates catch and throw" $ failureOf $(inspectTest $ 'throwing `doesNotUse` ''ErrorC) @?= Nothing , testCase "eliminates calls to alg" $ failureOf $(inspectTest $ 'countDown `doesNotUse` 'alg) @?= Nothing ] failureOf :: Inspection.Result -> Maybe String failureOf (Success _) = Nothing failureOf (Failure f) = Just f countDown :: Int -> (Int, Int) countDown start = run . runState start $ go where go = get >>= \n -> if n <= 0 then pure n else modify @Int pred *> go countBoth :: Int -> (Int, (Float, ())) countBoth n = run . runState n . runState (fromIntegral n) $ go where go = do n <- get @Int if | n == 0 -> pure () | n `mod` 2 == 0 -> modify @Float (+ 1) *> modify @Int pred *> go | otherwise -> modify @Int pred *> go throwing :: Int -> Either Int String throwing n = run $ runError go where go = if n > 10 then throwError @Int 42 else pure "fine"