{-# LANGUAGE TemplateHaskell #-} module Control.Operate ( opdo ) where import Control.Operate.Internal import Control.Operate.Types import Data.Semigroup import Language.Haskell.TH import Language.Haskell.TH.Quote -- | operate do notation -- -- Syntax: -- -- @ -- ::= ar { } (opdo expression) -- ::= -> -- ::= -- | ( ) (for section) -- ::= ... [;] (n >= 0) -- ::= ; -- | ; (empty statement) -- @ -- -- Sematics: -- -- @ -- [opdo| _ -> { e } |] = e -- @ -- -- * InfixL Operator: -- -- @ -- [opdo| op -> { stmts e } |] = op [opdo| op -> { stmts } |] e -- @ -- -- * InfixR Operator: -- -- @ -- [opdo| op -> { e; stmts } |] = op e [opdo| op -> { stmts } |] -- @ -- -- Examples: -- -- >>> [opdo| (.) -> { head; show; id } |] 1 -- '1' -- -- >>> [opdo| . -> { head; show; id } |] 1 -- '1' -- -- >>> [opdo| <*> -> { pure const; Just 1; Nothing } |] -- Nothing -- -- >>> :{ -- [opdo| const -> { -- "str"; -- 1 -- }|] -- :} -- "str" -- -- >>> :{ -- "show: " ++ [opdo| (.) -> -- \x -> -- tail x -- show -- |] 10 -- :} -- "show: 0" -- opdo :: QuasiQuoter opdo = QuasiQuoter { quoteExp = opdoExpQ , quotePat = nonsense "pattern" , quoteType = nonsense "type" , quoteDec = nonsense "declaration" } where nonsense context = fail $ "You can't use opdo in " <> context <> " context, that doesn't even make sense." opdoExpQ :: String -> ExpQ opdoExpQ s = runOpdo <$> parseOperateDoExp s