packages feed

funcons-tools-0.1.0.0: src/Funcons/Types.hs

{-# LANGUAGE OverloadedStrings, TupleSections #-}

module Funcons.Types where

import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.MultiSet as MS
import qualified Data.Vector as V
import qualified Data.BitVector as BV
import Data.Text (Text)
import Data.Maybe (isJust)
import Data.Ratio

type MetaVar = String
type Name = Text

-- | 
-- Internal representation of funcon terms.
-- The generic constructors 'FName' and 'FApp' use names to represent
-- nullary funcons and applications of funcons to other terms. 
-- Funcon terms are easily created using 'applyFuncon' or via
-- the smart constructors exported by "Funcons.Core".
data Funcons    = FName Name
                | FApp Name Funcons
                | FTuple [Funcons]
                | FList [Funcons]
                | FSet [Funcons]
                | FMap [Funcons]
                | FValue Values
                | FSortSeq Funcons SeqSortOp
                | FSortUnion Funcons Funcons
                | FSortComputes Funcons
                | FSortComputesFrom Funcons Funcons
                deriving (Eq, Ord, Show)

-- |
-- Build funcon terms by applying a funcon name to `zero or more' funcon terms.
-- This function is useful for defining smart constructors, e,g,
--
-- > handle_thrown_ :: [Funcons] -> Funcons
-- > handle_thrown_ = applyFuncon "handle-thrown"
--
-- or alternatively,
--
-- > handle_thrown_ :: Funcons -> Funcons -> Funcons
-- > handle_thrown_ x y = applyFuncon "handle-thrown" [x,y]
applyFuncon :: Name -> [Funcons] -> Funcons
applyFuncon str args    | null args = FName str
                        | otherwise = FApp str (FTuple args)

-- | Creates a list of funcon terms.
list_ :: [Funcons] -> Funcons
list_ = FList

-- | Creates a set of funcon terms.
set_ :: [Funcons] -> Funcons
set_ = FSet


-- | Funcon term representation identical to 'Funcons', 
-- but with meta-variables. 
data FTerm  = TVar MetaVar
            | TName Name
            | TApp Name FTerm
            | TTuple [FTerm]
            | TList [FTerm]
            | TSet  [FTerm]
            | TMap  [FTerm]
            | TFuncon Funcons
            | TSortSeq FTerm SeqSortOp
            | TSortUnion FTerm FTerm
            | TSortComputes FTerm
            | TSortComputesFrom FTerm FTerm
            deriving (Eq, Ord, Show)

-- | 
-- This datatype provides a number of builtin value types. 
-- Composite values are only built up out of other values.
-- The only exception is 'Thunk' which stores a thunked computation
-- (funcon term).
data Values     = ADTVal Name [Values]
                | Ascii Int
                | Atom String
                | Bit BV.BitVector
                | Char Char
                | ComputationType ComputationTypes
                | Float Float
                | IEEE_Float_32 Float
                | IEEE_Float_64 Double
                | Int Integer
                | List [Values]
                | Map Map
                | Multiset (MS.MultiSet Values)
                | Nat Integer
                | Rational Rational
                | Set Set
                | String String
                | Thunk Funcons
                | EmptyTuple -- | Tuples are split in 'EmptyTuple' and 'NonEmptyTuple' to avoid singleton tuples. Tuples should be constructed by applications of 'tuple_'. 
                | NonEmptyTuple Values Values [Values]
                | Vector Vectors
        deriving (Eq,Ord,Show)

type Map        = M.Map Values Values
type Set        = S.Set Values
type Vectors    = V.Vector Values

-- | Postfix operators for specifying sequences.
data SeqSortOp = StarOp | PlusOp | QuestionMarkOp
                deriving (Show, Eq, Ord)

-- | Computation type /S=>T/ reflects a type of term
-- whose given value is of type /S/ and result is of type /T/.
data ComputationTypes = Type Types -- | /=>T/
                      | ComputesType Types -- | /S=>T/
                      | ComputesFromType Types Types
                      deriving (Ord,Eq,Show)

-- | Representation of builtin types.
data Types  = ADTs
            | ADT Name [Types]
            | AsciiCharacters
            | Atoms
            | Bits Int
            | BoundedIntegers Integer Integer
            | ComputationTypes
            | EmptyType
            | IEEEFloats IEEEFormats
            | Integers
            | Lists Types
            | Maps Types Types
            | Multisets Types
            | Naturals
            | Rationals
            | Sets Types
            | Strings
            | Thunks ComputationTypes -- | Types optionally attached to 'SeqSortOp'.
            | Tuples [TTParam]
            | Types
            | UnicodeCharacters
            | Union Types Types
            | Values
            | Vectors Types
              deriving (Ord,Eq,Show)

type TTParam = (Types,Maybe SeqSortOp)

data IEEEFormats = Binary32 | Binary64
        deriving (Enum,Show,Eq,Ord)

binary32 :: Values
binary32 = ADTVal "binary32" []

binary64 :: Values
binary64 = ADTVal "binary64" []

adtval :: Name -> Values -> Values
adtval nm = ADTVal nm . tuple_unval

nullaryTypes :: [(Name,Types)]
nullaryTypes =
  [ ("algebraic-datatypes", ADTs)
  , ("atoms",               Atoms)
  , ("computation-types",   ComputationTypes)
  , ("empty-type",          EmptyType)
  , ("integers",            Integers)
  , ("naturals",            Naturals)
  , ("rationals",           Rationals)
  , ("strings",             Strings)
  , ("types",               Types)
  , ("unicode-characters",  UnicodeCharacters)
  , ("values",              Values)
  ]

unaryTypes :: [(Name,Types->Types)]
unaryTypes =
  [ ("lists",     Lists)
  , ("multisets", Multisets)
  , ("sets",      Sets)
  , ("vectors",   Vectors)
  ]

binaryTypes :: [(Name,Types->Types->Types)]
binaryTypes =
  [ ("maps", Maps)
  ]

boundedIntegerTypes :: [(Name, Integer -> Integer -> Types)]
boundedIntegerTypes = [("bounded-integers", BoundedIntegers)]

floatTypes :: [(Name, IEEEFormats -> Types)]
floatTypes = [("ieee-floats", IEEEFloats)]

bitsTypes :: [(Name, Int -> Types)]
bitsTypes = [("bits", Bits)]

-- type environment

-- | The typing environment maps datatype names to their definitions.
type TypeEnv = M.Map Name DataTypeMembers

-- | A type parameter is of the form X:T where the name of the parameter,/X/, is optional.
-- When present, /X/ can be used to specify the type of constructors.
type TypeParam = (Maybe MetaVar,FTerm)
-- | A datatype has `zero or more' type parameters and
-- `zero or more' alternatives.
data DataTypeMembers = DataTypeMembers [TypeParam] [DataTypeAlt]

-- | An alternative is either a datatype constructor or the inclusion
-- of some other type. The types are arbitrary funcon terms (with possible
-- variables) that may require evaluation to be resolved to a 'Types'.
data DataTypeAlt = DataTypeInclusion FTerm
                 | DataTypeConstructor Name FTerm

-- | Lookup the definition of a datatype in the typing environment.
typeLookup :: Name -> TypeEnv -> Maybe DataTypeMembers
typeLookup = M.lookup

-- | The empty 'TypeEnv'.
emptyTypeEnv :: TypeEnv
emptyTypeEnv = M.empty

-- | Unites a list of 'TypeEnv's.
typeEnvUnions :: [TypeEnv] -> TypeEnv
typeEnvUnions = foldr typeEnvUnion emptyTypeEnv

-- | Unites two 'TypeEnv's.
typeEnvUnion :: TypeEnv -> TypeEnv -> TypeEnv
typeEnvUnion = M.unionWith (\_ _ -> error "duplicate type-name")

-- | Creates a `TypeEnv' from a list.
typeEnvFromList :: [(Name, DataTypeMembers)] -> TypeEnv
typeEnvFromList = M.fromList

{-
-- I think this is no longer needed.
-- Ids
newtype ID = ID' Values
    deriving (Eq)

instance Ord ID where
    (ID' v1) `compare` (ID' v2) = idCompare v1 v2

idCompare :: Values -> Values -> Ordering
(Int i1)    `idCompare` (Int i2)     = compare i1 i2
(Int _)     `idCompare` _            = LT
_           `idCompare` (Int _)     = GT
(String s)  `idCompare` (String s2) = compare s s2
_           `idCompare` _           = error "comparing non-atomic ids"
-}

-- Values should be atoms: Ints,Booleans,Strings,Tuples? etc

-- Ids are just `strings` now.
{-
id_ :: Funcons -> Funcons
id_ (FValue v@(Int _))    = FValue (ID (ID' v))
id_ (FValue v@(String _)) = FValue (ID (ID' v))
id_ v = error $ "id supplied with non-atomic value"
-}

--- smart constructors for values

-- | Creates an integer 'literal'.
int_ :: Int -> Funcons
int_ = FValue . mk_integers . toInteger

-- | Creates a natural 'literal'.
nat_ :: Int -> Funcons 
nat_ i | i < 0      = int_ i
       | otherwise  = FValue $ mk_naturals $ toInteger i

-- | Creates an atom from a 'String'. 
atom_ :: String -> Funcons
atom_ = FValue . Atom

-- | Creates a rational literal.
rational_ :: Rational -> Funcons
rational_ = FValue . mk_rationals

-- | Creates a string literal.
string_ :: String -> Funcons
string_ = FValue . String

-- | Creates an empty tuple as a 'Values'.
empty_tuple_ :: Funcons 
empty_tuple_ = FValue EmptyTuple

-- | The empty map as a 'Funcons'.
empty_map_,map_empty_ :: Funcons
empty_map_ = FValue (Map M.empty)
map_empty_ = empty_map_

-- | The empty set as a 'Funcons'.
empty_set_ :: Funcons
empty_set_ = FValue (Set S.empty)

-- | Creates a tuple of funcon terms.
tuple_ :: [Funcons] -> Funcons
tuple_ = FTuple

tuple_val_ :: [Values] -> Funcons
tuple_val_ = FValue . safe_tuple_val

type_ :: Types -> Funcons
type_ = FValue . typeVal

vec :: V.Vector (Values) -> Funcons
vec = FValue . Vector

-- idval :: Values -> Values
-- idval = ID . ID'

typeVal :: Types -> Values
typeVal = ComputationType . Type

safe_tuple_val :: [Values] -> Values
safe_tuple_val []         = EmptyTuple
safe_tuple_val [v]        = v
safe_tuple_val (v1:v2:vs) = NonEmptyTuple v1 v2 vs

tuple_unval :: Values -> [Values]
tuple_unval EmptyTuple               = []
tuple_unval (NonEmptyTuple v1 v2 vs) = v1:v2:vs
tuple_unval v                        = [v]

types_unval :: Types -> [Types]
types_unval (Tuples ts)
    | any (isJust . snd) ts = [Tuples ts]
    | otherwise             = map fst ts
types_unval t = [t]


fvalues :: [Values] -> [Funcons]
fvalues = map FValue

listval :: [Values] -> Funcons
listval = FValue . List

setval :: [Values] -> Funcons
setval = FValue . setval_

setval_ = Set . S.fromList

mapval :: [Values] -> Funcons
mapval = FValue . mapval_

mapval_ = Map . M.fromList . map toKeyValue
 where  toKeyValue (NonEmptyTuple k v []) = (k,v)
        toKeyValue _ = error "mapval"

-- subtyping rationals
mk_rationals :: Rational -> Values
mk_rationals r  | denominator r == 1 = mk_integers (numerator r)
                | otherwise             = Rational r

mk_integers :: Integer -> Values
mk_integers i   | i >= 0    = mk_naturals i
                | otherwise = Int i

mk_naturals :: Integer -> Values
mk_naturals = Nat

-- | Returns the /rational/ representation of a value if it is a subtype.
-- Otherwise it returns the original value.
upcastRationals :: Values -> Values
upcastRationals (Nat n) = Rational (toRational n)
upcastRationals (Int i) = Rational (toRational i)
upcastRationals v       = v

-- | Returns the /integer/ representation of a value if it is a subtype.
-- Otherwise it returns the original value.
upcastIntegers :: Values -> Values
upcastIntegers (Nat n)  = Int n
upcastIntegers v        = v

-- | Returns the /natural/ representation of a value if it is a subtype.
-- Otherwise it returns the original value.
upcastNaturals :: Values -> Values
upcastNaturals v = v

-- | Returns the /unicode/ representation of an assci value.
-- Otherwise it returns the original value.
upcastUnicode :: Values -> Values
upcastUnicode (Ascii c) = Char (toEnum c)
upcastUnicode v = v

castType :: Values -> Maybe Types
castType (ComputationType (Type ty)) = Just ty
castType EmptyTuple                  = Just (Tuples [])
castType (NonEmptyTuple t1 t2 ts)    = Tuples <$> mapM (fmap (,Nothing) . castType) (t1:t2:ts)
castType _                           = Nothing

--- Value specific

-- | Attempt to downcast a funcon term to a value.
downcastValue :: Funcons -> Values
downcastValue (FValue v) = v
downcastValue _ = error "downcasting to value failed"

-- | Attempt to downcast a funcon term to a type.
downcastType :: Funcons -> Types
downcastType (FValue (ComputationType (Type ty))) = ty
downcastType _ = error "downcasting to type failed"

-- | Attempt to downcast a value to a type.
downcastValueType :: Values -> Types
downcastValueType (ComputationType (Type t)) = t
downcastValueType _ = error "valueType: not a type"

recursiveFunconValue :: Funcons -> Maybe Values
recursiveFunconValue (FValue v) = Just v
recursiveFunconValue (FList fs) = List <$> mapM recursiveFunconValue fs
recursiveFunconValue (FSet fs)  = Set . S.fromList <$> mapM recursiveFunconValue fs
recursiveFunconValue (FMap fs)  = Map . M.fromList <$> mapM unFTuple fs
 where  unFTuple (FTuple [k,v]) = (,) <$> recursiveFunconValue k <*> recursiveFunconValue v
        unFTuple _ = Nothing
recursiveFunconValue _ = Nothing

(===) :: Values -> Values -> Bool
v1 === v2 = isGround v1 && isGround v2 && (v1 == v2)

(=/=) :: Values -> Values -> Bool
v1 =/= v2 = isGround v1 && isGround v2 && (v1 /= v2)

isGround :: Values -> Bool
isGround (ADTVal _ mv)            = all isGround mv
isGround (Ascii _)                = True
isGround (Atom _)                 = True
isGround (Bit _)                  = True
isGround (Char _)                 = True
isGround (ComputationType _)      = True
isGround (EmptyTuple)             = True
isGround (Float _)                = True
isGround (IEEE_Float_32 _)        = True
isGround (IEEE_Float_64 _)        = True
isGround (Int _)                  = True
isGround (List vs)                = all isGround vs
isGround (Map m)                  = all isGround (M.elems m)
isGround (Multiset ms)            = all isGround ms
isGround (Nat _)                  = True
isGround (NonEmptyTuple v1 v2 vs) = all isGround (v1:v2:vs)
isGround (Rational _)             = True
isGround (Set s)                  = all isGround (S.toList s)
isGround (String _)               = True
isGround (Thunk _)                = False
isGround (Vector v)               = all isGround (V.toList v)

-- functions that check simple properties of funcons
-- TODO: these may not be needed any longer
isAscii (FValue (Ascii _))      = True
isAscii _                       = False
isChar (FValue (Char _))         = True
isChar _                        = False
isId = isString -- TODO: is this needed any more?
isNat (FValue (Int _))          = True
isNat _                         = False
isInt (FValue (Int _))           = True
isInt _                         = False
isList (FValue (List _))         = True
isList _                        = False
isEnv f                         = isMap f
isMap (FValue (Map _))           = True
isMap _                         = False
isSet (FValue (Set _))           = True
isSet _                         = False
isString (FValue v)              = isString_ v
isString _                      = False
isString_ (String _)            = True
isString_ _                     = False
isThunk (FValue (Thunk _))       = True
isThunk _                       = False
isTup (FValue EmptyTuple)       = True
isTup (FValue (NonEmptyTuple _ _ _)) = True
isTup _                         = False
isType (FValue (ComputationType (Type _))) = True
isType _                        = False
isVal (FValue _)                 = True
isVal _                         = False
isVec (FValue (Vector _))        = True
isVec _                         = False
isType_ (ComputationType (Type _)) = True
isType_ _                       = False

integers_,strings_,values_,unicode_characters_ :: Funcons
integers_ = type_ Integers
unicode_characters_  = type_ UnicodeCharacters
strings_ = type_ Strings
values_ = type_ Values