{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}

module Ivory.Stdlib.Operators where

import Ivory.Language

-- | Infix structure field access and dereference.
-- This is a shorthand for 'deref $ s~>x'.
(~>*) :: (IvoryVar a, IvoryStruct sym, IvoryRef ref, IvoryStore a,
          IvoryExpr (ref s ('Stored a)),
          IvoryExpr (ref s ('Struct sym))) =>
            ref s ('Struct sym) -> Label sym ('Stored a) -> Ivory eff a
struct ~>* label = deref (struct~>label)
infixl 8 ~>*


-- | Modify the value stored at a reference by a function.
(%=) :: IvoryStore a =>
     Ref s ('Stored a) -> (a -> a) -> Ivory eff ()
ref %= f = do
  val <- deref ref
  store ref (f val)

-- | Modify the value stored at a reference by a function that returns
-- a value in the Ivory monad
(%=!) :: IvoryStore a =>
         Ref s ('Stored a) -> (a -> Ivory eff a) -> Ivory eff ()
ref %=! mf = do
  val  <- deref ref
  val' <- mf val
  store ref val'

-- | Increment the value stored at a reference.
(+=) :: (Num a, IvoryStore a) =>
        Ref s ('Stored a) -> a -> Ivory eff ()
ref += x = ref %= (+ x)