HList-0.5.0.0: examples/HListExample/Prism.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE QuasiQuotes #-} -- for pun
{-# LANGUAGE TemplateHaskell #-}
module HListExample.Prism where
import Test.Hspec
import Properties.Common
import Data.HList.CommonMain
import Data.HList.Labelable (hLens')
import Control.Lens
-- generate left = Label :: Label "left"
makeLabels6 (words "left right up down")
--- define the Labelable labels manually
left_ = hLens' left
right_ = hLens' right
up_ = hLens' up
down_ = hLens' down
-- this definition is needed to decide what order
-- to put the fields in, as well as their initial types
r = [pun|right left up|] where
left = 'a'
right = 2 :: Int
up = 2.3 :: Double
r2 = down_ .==. v .*. r
v = mkVariant left 'x' r
mainPrism = do
it "inspect v with hPrism" $ do
v ^? hPrism left `shouldShowTo` "Just 'x'"
v ^? hPrism right `shouldBe` Nothing
v ^? hPrism up `shouldBe` Nothing
v2 ^? hPrism left `shouldShowTo` "Just ()"
it "inspect v with hPrism through Labelable" $ do
v ^? left_ `shouldShowTo` "Just 'x'"
v ^? right_ `shouldBe` Nothing
v ^? up_ `shouldBe` Nothing
v2 ^? left_ `shouldShowTo` "Just ()"
it "Setting the missing tag does nothing" $ do
set right_ () v `shouldShowTo` "V{left='x'}"
set _Right () (Left 'x') -- prisms for Either do the same thing
`shouldShowTo` "Left 'x'"
it "compose prism" $ do
v3 ^? up_.up_ `shouldBe` Nothing
v3 ^? left_ `shouldShowTo` "Just 'x'"
v4 ^? left_.left_ `shouldShowTo` "Just \"leftleft\""
it "compose lens.prism" $ do
r2 ^? down_.left_ `shouldShowTo` "Just 'x'"
r2 ^? down_.right_ `shouldBe` Nothing
let du = down_.up_
r2 ^? du `shouldBe` Nothing
it "extension" $ do
v5 ^? down_ `shouldBe` Just "hi"
v6 ^? down_ `shouldBe` Just "hi"
v7 ^? down_ `shouldBe` Nothing
v7 ^? left_ `shouldBe` Just 'x'
it "show" $ do
vs `shouldShowTo`
"Record{v=V{left='x'},\
\v2=V{left=()},\
\v2'=V{left=()},\
\v3=V{left='x'},\
\v4=V{left=V{left=\"leftleft\"}},\
\v5=V{down=\"hi\"},\
\v6=V{down=\"hi\"},\
\v7=V{left='x'}}"
-- works in ghci. Probably need -XExtendedDefaultRules
-- wX `shouldShowTo` "V{x='a'}"
-- wY `shouldShowTo` "V{y=2.5}"
[wX,wY] `shouldShowTo` "[V{x='a'},V{y=2.5}]"
-- :t wX
-- > wX :: Variant '[Tagged "x" Char, Tagged "y" y]
--
-- > :t wY
-- > wY :: Variant '[Tagged "x" x, Tagged "y" Double]
--
-- ghc doesn't need to decide on a type for values that
-- have no influence on the final result
it "type partly defined" $ do
wX ^? hLens' (Label :: Label "x")
`shouldShowTo` "Just 'a'"
wY ^? hLens' (Label :: Label "y")
`shouldShowTo` "Just 2.5"
wX = mkVariant (Label :: Label "x") 'a' wProto
wY = mkVariant (Label :: Label "y") (2.5 :: Double) wProto
wProto = undefined :: Record
'[Tagged "x" x, Tagged "y" y]
vs = [pun| v v2 v2' v3 v4 v5 v6 v7 |]
-- note that we can change the type of the 'x' field
-- from Char to ()
v2 = set (hPrism left) () v
-- or with the "better" label
v2' = set left_ () v
v3 = v & up_ .~ v & up_.up_ .~ "upup"
v4 = v & left_ .~ v & left_.left_ .~ "leftleft"
v5 = down .=. Just "hi" .*. v
v6 = down_ .==. Just "hi" .*. v
v7 = down .=. (Nothing :: Maybe String) .*. v