hobbits-1.0: Data/Binding/Hobbits/SuperComb.hs
{-# LANGUAGE TemplateHaskell #-}
-- |
-- Module : Data.Binding.Hobbits.SuperComb
-- Copyright : (c) 2011 Edwin Westbrook, Nicolas Frisby, and Paul Brauner
--
-- License : BSD3
--
-- Maintainer : emw4@rice.edu
-- Stability : experimental
-- Portability : GHC
--
-- This module uses Template Haskell to distinguish super-combinators, so that
-- the library can trust such functions to not contain any @Name@ values in
-- their closure.
module Data.Binding.Hobbits.SuperComb (
-- * Abstract types
SuperComb(),
-- * Operators involving 'SuperComb'
superComb, mbToplevel,
) where
import Data.Binding.Hobbits.Internal (Mb(..))
import Language.Haskell.TH as TH
import qualified Data.Generics as SYB
import qualified Language.Haskell.TH.Syntax as TH
------------------------------------------------------------
-- applying top-level functions under binders
------------------------------------------------------------
{-|
The type @SuperComb a@ represents a super-combinator of type @a@,
i.e., an expression of type @a@ with no free (Haskell) variables.
Since this cannot be checked directly in the Haskell type system,
the @SuperComb@ data type is hidden, and the user can only create
super-combinators using Template Haskell, through the 'superComb'
operator.
-}
newtype SuperComb a = SuperComb { unSuperComb :: a }
-- | An quoted expression is a CAF if all of its names are bound globally or
-- within the quotation
isSuperComb :: Exp -> Bool
isSuperComb = SYB.everything (&&) (SYB.mkQ True nameOK) where
nameOK (TH.Name _ flav) = case flav of
TH.NameG {} -> True -- bound globally
TH.NameU {} -> True -- bound within this same quotation
_ -> False
-- | @superComb@ is used with Template Haskell to create super-combinators;
-- see documentation for 'mbToplevel' to see how it is used.
superComb :: Q Exp -> Q Exp
superComb m = do
e <- m
if isSuperComb e then return (TH.AppE (TH.ConE 'SuperComb) e) else fail ("not a super combinator:\n\t" ++ TH.pprint e)
-- | @mbToplevel@ @f@ @b@ applies super-combinator @f@ to the body of
-- multi-binding @b@. For example:
--
-- > mbToplevel $(superComb [| f |]) (nu $ \n -> n) = nu f
mbToplevel :: SuperComb (a -> b) -> Mb ctx a -> Mb ctx b
mbToplevel f (MkMb names i) = MkMb names (unSuperComb f i)