packages feed

BinderAnn-0.1.0.0: test/Generic.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_GHC
  -fplugin     BinderAnn.Generic
  -fplugin-opt BinderAnn.Generic:manual
#-}

module Generic where

import Control.Monad.State
import Control.Monad.Except

import BinderAnn.Generic

----------------------------------------
-- Example 1: Arithmetic expressions
----------------------------------------

data EvalError =
  DivByZero (Maybe SrcInfo)
  deriving Show

type MonadEval m =
  ( MonadAnnotated           m
  , MonadError     EvalError m
  , MonadIO                  m
  )

type Eval = AnnotatedT (ExceptT EvalError IO)

runEval :: Eval a -> IO (Either EvalError a)
runEval = runExceptT . evalAnnotatedT

divByZeroError :: MonadEval m => a -> m b
divByZeroError x = lookupAnn x >>= throwError . DivByZero

-- the DSL

lit :: MonadEval m => Int -> m Int
lit = return

(|+|) :: MonadEval m => Int -> Int -> m Int
(|+|) x y = lit (x + y)

(|-|) :: MonadEval m => Int -> Int -> m Int
(|-|) x y = lit (x - y)

(|*|) :: MonadEval m => Int -> Int -> m Int
(|*|) x y = lit (x * y)

(|/|) :: MonadEval m => Int -> Int -> m Int
(|/|) x y | y == 0    = divByZeroError y
          | otherwise = lit (x `div` y)


-- some tests
{-# ANN test1 SrcInfo #-}
test1 :: MonadEval m => m Int
test1 = do
  zero <- lit 0
  one  <- lit 1
  false <- return False
  liftIO $ print (zero, one)
  one |/| zero

----------------------------------------
-- entry point
----------------------------------------

tests :: IO ()
tests = do
  putStrLn "test1:"
  runEval test1 >>= print