inline-r-0.10.3: src/Foreign/R/Type.hsc
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
#if __GLASGOW_HASKELL__ >= 710
{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}
#endif
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
-- |
-- Copyright: (C) 2013 Amgen, Inc.
--
-- Definition of 'SEXPTYPE', which classifies the possible forms of an
-- R expression (a 'SEXP'). It is normally not necessary to import this module
-- directly, since it is reexported by "Foreign.R".
--
-- This is done in a separate module because we want to use hsc2hs rather than
-- c2hs for discharging the boilerplate around 'SEXPTYPE'. This is because
-- 'SEXPTYPE' is nearly but not quite a true enumeration and c2hs has trouble
-- dealing with that.
--
-- This module also defines a singleton version of 'SEXPTYPE', called
-- 'SSEXPTYPE'. This is actually a family of types, one for each possible
-- 'SEXPTYPE'. Singleton types are a way of emulating dependent types in
-- a language that does not have true dependent type. They are useful in
-- functions whose result type depends on the value of one of its arguments. See
-- e.g. 'Foreign.R.allocVector'.
module Foreign.R.Type
( SEXPTYPE(..)
, SSEXPTYPE(..)
, Sing(..)
, Logical(..)
, PairList
, IsVector
, IsGenericVector
, IsList
, IsPairList
, IsExpression
) where
#include <Rinternals.h>
import Foreign.R.Constraints
import Internal.Error
import qualified Language.Haskell.TH.Syntax as Hs
import qualified Language.Haskell.TH.Lib as Hs
import Data.Singletons.TH
import Control.DeepSeq (NFData(..))
import Foreign.R.Context
-- | R \"type\". Note that what R calls a \"type\" is not what is usually meant
-- by the term: there is really only a single type, called 'SEXP', and an
-- R "type" in fact refers to the /class/ or /form/ of the expression.
--
-- To better illustrate the distinction, note that any sane type system normally
-- has the /subject reduction property/: that the type of an expression is
-- invariant under reduction. For example, @(\x -> x) 1@ has type 'Int', and so
-- does the value of this expression, @2@, have type 'Int'. Yet the /form/ of
-- the expression is an application of a function to a literal, while the form
-- of its reduct is an integer literal.
--
-- We introduce convenient Haskell-like names for forms because this datatype is
-- used to index 'SEXP' and other types through the @DataKinds@ extension.
--
data SEXPTYPE
= Nil
| Symbol
| List
| Closure
| Env
| Promise
| Lang
| Special
| Builtin
| Char
| Logical
| Int
| Real
| Complex
| String
| DotDotDot
| Any
| Vector
| Expr
| Bytecode
| ExtPtr
| WeakRef
| Raw
| S4
| New
| Free
| Fun
deriving (Eq, Ord, Show)
instance Enum SEXPTYPE where
fromEnum Nil = #const NILSXP
fromEnum Symbol = #const SYMSXP
fromEnum List = #const LISTSXP
fromEnum Closure = #const CLOSXP
fromEnum Env = #const ENVSXP
fromEnum Promise = #const PROMSXP
fromEnum Lang = #const LANGSXP
fromEnum Special = #const SPECIALSXP
fromEnum Builtin = #const BUILTINSXP
fromEnum Char = #const CHARSXP
fromEnum Logical = #const LGLSXP
fromEnum Int = #const INTSXP
fromEnum Real = #const REALSXP
fromEnum Complex = #const CPLXSXP
fromEnum String = #const STRSXP
fromEnum DotDotDot = #const DOTSXP
fromEnum Any = #const ANYSXP
fromEnum Vector = #const VECSXP
fromEnum Expr = #const EXPRSXP
fromEnum Bytecode = #const BCODESXP
fromEnum ExtPtr = #const EXTPTRSXP
fromEnum WeakRef = #const WEAKREFSXP
fromEnum Raw = #const RAWSXP
fromEnum S4 = #const S4SXP
fromEnum New = #const NEWSXP
fromEnum Free = #const FREESXP
fromEnum Fun = #const FUNSXP
toEnum (#const NILSXP) = Nil
toEnum (#const SYMSXP) = Symbol
toEnum (#const LISTSXP) = List
toEnum (#const CLOSXP) = Closure
toEnum (#const ENVSXP) = Env
toEnum (#const PROMSXP) = Promise
toEnum (#const LANGSXP) = Lang
toEnum (#const SPECIALSXP) = Special
toEnum (#const BUILTINSXP) = Builtin
toEnum (#const CHARSXP) = Char
toEnum (#const LGLSXP) = Logical
toEnum (#const INTSXP) = Int
toEnum (#const REALSXP) = Real
toEnum (#const CPLXSXP) = Complex
toEnum (#const STRSXP) = String
toEnum (#const DOTSXP) = DotDotDot
toEnum (#const ANYSXP) = Any
toEnum (#const VECSXP) = Vector
toEnum (#const EXPRSXP) = Expr
toEnum (#const BCODESXP) = Bytecode
toEnum (#const EXTPTRSXP) = ExtPtr
toEnum (#const WEAKREFSXP) = WeakRef
toEnum (#const RAWSXP) = Raw
toEnum (#const S4SXP) = S4
toEnum (#const NEWSXP) = New
toEnum (#const FREESXP) = Free
toEnum (#const FUNSXP) = Fun
toEnum _ = violation "toEnum" "Unknown R type."
instance NFData SEXPTYPE where
rnf = (`seq` ())
genSingletons [''SEXPTYPE]
instance Hs.Lift SEXPTYPE where
lift a = [| $(Hs.conE (Hs.mkName $ "Foreign.R.Type." ++ show a)) |]
-- | Used where the R documentation speaks of "pairlists", which are really just
-- regular lists.
type PairList = List
-- Use a macro to avoid having to define append at the type level.
#let VECTOR_FORMS = " 'Char \
': 'Logical \
': 'Int \
': 'Real \
': 'Complex \
': 'String \
': 'Vector \
': 'Expr \
': 'WeakRef \
': 'Raw"
-- | Constraint synonym grouping all vector forms into one class. @IsVector a@
-- holds iff R's @is.vector()@ returns @TRUE@.
type IsVector (a :: SEXPTYPE) = (SingI a, a :∈ #{VECTOR_FORMS} ': '[])
-- | Non-atomic vector forms. See @src\/main\/memory.c:SET_VECTOR_ELT@ in the
-- R source distribution.
type IsGenericVector (a :: SEXPTYPE) = (SingI a, a :∈ [Vector, Expr, WeakRef])
-- | @IsList a@ holds iff R's @is.list()@ returns @TRUE@.
type IsList (a :: SEXPTYPE) = (SingI a, a :∈ #{VECTOR_FORMS} ': List ': '[])
-- | @IsPairList a@ holds iff R's @is.pairlist()@ returns @TRUE@.
type IsPairList (a :: SEXPTYPE) = (SingI a, a :∈ [List, Nil])
-- | Constraint synonym grouping all expression forms into one class. According
-- to R internals, an expression is usually a 'Lang', but can sometimes also be
-- an 'Expr' or a 'Symbol'.
type IsExpression (a :: SEXPTYPE) = (SingI a, a :∈ [Lang, Expr, Symbol])