{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, TypeApplications, TypeFamilies #-}
module Main where
import Control.Algebra
import Control.Carrier.Reader
import Control.Carrier.State.Strict
import Lens.Micro
import Test.Hspec
import Control.Effect.Lens
data Context = Context
{ _amount :: Int
, _sweatshirt :: Bool
} deriving (Eq, Show)
amount :: Lens' Context Int
amount = lens _amount (\c a -> c { _amount = a })
sweatshirt :: Lens' Context Bool
sweatshirt = lens _sweatshirt (\c s -> c { _sweatshirt = s })
initial :: Context
initial = Context 0 False
stateTest :: (Has (State Context) sig m) => m Int
stateTest = do
initial <- use amount
assign amount (initial + 1)
assign sweatshirt True
use amount
class PolymorphicLens t a | t -> a where
wrapped :: Lens' t a
newtype Foo = Foo { _unFoo :: Int } deriving (Eq, Show)
instance PolymorphicLens Foo Int where
wrapped = lens _unFoo (\_ i -> Foo i)
newtype Bar = Bar { _unBar :: Float } deriving (Eq, Show)
instance PolymorphicLens Bar Float where
wrapped = lens _unBar (\_ i -> Bar i)
doubleStateTest :: (Has (State Bar) sig m, Has (State Foo) sig m) => m Int
doubleStateTest = do
assign @Foo wrapped 5
assign @Bar wrapped 30.5
pure 50
readerTest :: (Has (Reader Context) sig m) => m Int
readerTest = succ <$> view amount
spec :: Spec
spec = describe "use/assign" $ do
it "should modify stateful variables" $ do
let result = run $ runState initial stateTest
result `shouldBe` (Context 1 True, 1)
it "works in the presence of polymorphic lenses with -XTypeAnnotations" $ do
let result = run $ runState (Bar 5) $ runState (Foo 500) doubleStateTest
result `shouldBe` (Bar 30.5, (Foo 5, 50))
it "should read from an environment" $ do
let result = run $ runReader initial readerTest
result `shouldBe` 1
main :: IO ()
main = hspec $ describe "Control.Effect.Lens" spec