{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE NoRebindableSyntax #-}

module PprRecordDotSyntax2 where

data Foo = Foo { foo :: Bar } deriving (Show, Eq)
data Bar = Bar { bar :: Baz } deriving (Show, Eq)
data Baz = Baz { baz :: Quux } deriving (Show, Eq)
data Quux = Quux { quux :: Int } deriving (Show, Eq)

main = do
  let a = Foo { foo = Bar{ bar = Baz { baz = Quux { quux = 42 } } } }

  -- A "selector" is an expression like '(.a)' or '(.a.b)'.
  putStrLn "-- selectors:"
  print $ (.foo) a  -- Bar { bar = Baz { baz = Quux { quux = 42 } } }
  print $ (.foo.bar) a -- Baz { baz = Quux { quux = 42 } }
  print $ (.foo.bar.baz) a -- Quux { quux = 42 }
  print $ (.foo.bar.baz.quux) a -- 42

  -- A "selection" is an expression like 'r.a' or '(f r).a.b'.
  putStrLn "-- selections:"
  print $ a.foo.bar.baz.quux -- 42
  print $ a.foo.bar.baz -- Quux { quux = 42 }
  print $ a.foo.bar -- Baz { baz = Quux { quux = 42 } }
  print $ a.foo -- Bar { bar = Baz { baz = Quux { quux = 42 } } }

  -- An "update" is an expression like 'r{ a.b = 12 }'.
  --
  -- We don't support these (in the case Rebindable Syntax is off) yet
  -- (waiting on HasField support).
  --
  -- Regular updates are fine though!
  print $ a{foo=(foo a){bar = (bar (foo a)){baz = (baz (bar (foo a))){quux = quux (baz (bar (foo a))) + 1}}}}
  print $ a{foo=(a.foo){bar = (a.foo.bar){baz = (a.foo.bar.baz){quux = a.foo.bar.baz.quux + 1}}}}
