ideas-1.9.1: src/Ideas/Common/Rewriting/Term/Class.hs
-----------------------------------------------------------------------------
-- Copyright 2019, Ideas project team. This file is distributed under the
-- terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-- Generic terms
--
-----------------------------------------------------------------------------
module Ideas.Common.Rewriting.Term.Class
( -- * Terms
IsTerm(..), termView
, nothingSymbol, trueSymbol, falseSymbol
-- * Functions and symbols
, WithFunctions(..), isSymbol, isFunction
, unary, binary, ternary, isUnary, isBinary
-- * Variables
, WithVars(..), isVariable
, vars, varSet, hasVar, withoutVar
, hasSomeVar, hasNoVar, variableView
-- * Meta variables
, WithMetaVars(..), isMetaVar
, metaVars, metaVarSet, hasMetaVar, nextMetaVar
) where
import Data.Maybe
import Ideas.Common.Rewriting.Term.Data
import Ideas.Common.Rewriting.Term.Decoder
import Ideas.Common.Id
import Ideas.Common.View
import Ideas.Utils.Decoding
import Ideas.Utils.Prelude (ShowString(..))
import Ideas.Utils.Uniplate
import qualified Data.IntSet as IS
import qualified Data.Map as M
import qualified Data.Set as S
-----------------------------------------------------------
-- * Type class for conversion to/from terms
class IsTerm a where
toTerm :: a -> Term
toTermList :: [a] -> Term
fromTerm :: Term -> Maybe a
termDecoder :: TermDecoder a
termListDecoder :: TermDecoder [a]
{-# MINIMAL toTerm, termDecoder #-}
-- default implementation
toTermList = TList . map toTerm
fromTerm t = either (const Nothing) Just (evalDecoder termDecoder () [t])
termListDecoder = tListOf termDecoder
termView :: IsTerm a => View Term a
termView = makeView fromTerm toTerm
instance IsTerm Term where
toTerm = id
termDecoder = tFirst $ maybe (errorStr "not a term") return
instance IsTerm ShowString where
toTerm = TVar . fromShowString
termDecoder = ShowString <$> tVar
instance (IsTerm a, IsTerm b) => IsTerm (a, b) where
toTerm (a, b) = TList [toTerm a, toTerm b]
termDecoder = tList2 (,) termDecoder termDecoder
instance (IsTerm a, IsTerm b, IsTerm c) => IsTerm (a, b, c) where
toTerm (a, b, c) = TList [toTerm a, toTerm b, toTerm c]
termDecoder = tList3 (,,) termDecoder termDecoder termDecoder
instance (IsTerm a, IsTerm b) => IsTerm (Either a b) where
toTerm = either toTerm toTerm
termDecoder = Left <$> termDecoder <|> Right <$> termDecoder
instance IsTerm Int where
toTerm = TNum . fromIntegral
termDecoder = fromInteger <$> tInteger
instance IsTerm Integer where
toTerm = TNum
termDecoder = tInteger
instance IsTerm Double where
toTerm = TFloat
termDecoder = tDouble
instance IsTerm Float where
toTerm = TFloat . realToFrac
termDecoder = realToFrac <$> tDouble
instance IsTerm Char where
toTerm c = TVar [c]
toTermList = TVar
termDecoder = tChar
termListDecoder = tVar
instance IsTerm Bool where
toTerm True = symbol trueSymbol
toTerm False = symbol falseSymbol
termDecoder = True <$ tCon0 trueSymbol <|> False <$ tCon0 falseSymbol
instance IsTerm Id where
toTerm = toTerm . show
termDecoder = newId <$> tVar
instance IsTerm a => IsTerm [a] where
toTerm = toTermList
termDecoder = termListDecoder
instance (IsTerm a, Ord a) => IsTerm (S.Set a) where
toTerm = toTerm . S.toList
termDecoder = S.fromList <$> termDecoder
instance (IsTerm a, IsTerm b, Ord a) => IsTerm (M.Map a b) where
toTerm = toTerm . M.toList
termDecoder = M.fromList <$> termDecoder
trueSymbol, falseSymbol, nothingSymbol :: Symbol
trueSymbol = newSymbol "true"
falseSymbol = newSymbol "false"
nothingSymbol = newSymbol "Nothing"
instance IsTerm a => IsTerm (Maybe a) where
toTerm = maybe (symbol nothingSymbol) toTerm
termDecoder = Just <$> termDecoder <|> Nothing <$ tCon0 nothingSymbol
-----------------------------------------------------------
-- * Functions and symbols
class WithFunctions a where
-- constructing
symbol :: Symbol -> a
function :: Symbol -> [a] -> a
-- matching
getSymbol :: a -> Maybe Symbol
getFunction :: a -> Maybe (Symbol, [a])
-- default definition
symbol s = function s []
getSymbol a = fst <$> getFunction a
instance WithFunctions Term where
function = TCon
getFunction (TCon s xs) = Just (s, xs)
getFunction _ = Nothing
isSymbol :: WithFunctions a => Symbol -> a -> Bool
isSymbol s = (== Just s) . getSymbol
isFunction :: WithFunctions a => Symbol -> a -> Maybe [a]
isFunction s a =
case getFunction a of
Just (t, as) | s == t -> Just as
_ -> Nothing
unary :: WithFunctions a => Symbol -> a -> a
unary s a = function s [a]
binary :: WithFunctions a => Symbol -> a -> a -> a
binary s a b = function s [a, b]
ternary :: WithFunctions a => Symbol -> a -> a -> a -> a
ternary s a b c = function s [a, b, c]
isUnary :: WithFunctions a => Symbol -> a -> Maybe a
isUnary s a =
case isFunction s a of
Just [x] -> Just x
_ -> Nothing
isBinary :: WithFunctions a => Symbol -> a -> Maybe (a, a)
isBinary s a =
case isFunction s a of
Just [x, y] -> Just (x, y)
_ -> Nothing
-----------------------------------------------------------
-- * Variables
class WithVars a where
variable :: String -> a
getVariable :: a -> Maybe String
instance WithVars Term where
variable = TVar
getVariable (TVar s) = Just s
getVariable _ = Nothing
isVariable :: WithVars a => a -> Bool
isVariable = isJust . getVariable
vars :: (Uniplate a, WithVars a) => a -> [String]
vars = mapMaybe getVariable . universe
varSet :: (Uniplate a, WithVars a) => a -> S.Set String
varSet = S.fromList . vars
hasVar :: (Uniplate a, WithVars a) => String -> a -> Bool
hasVar i = (i `elem`) . vars
withoutVar :: (Uniplate a, WithVars a) => String -> a -> Bool
withoutVar i = not . hasVar i
hasSomeVar :: (Uniplate a, WithVars a) => a -> Bool
hasSomeVar = not . hasNoVar
hasNoVar :: (Uniplate a, WithVars a) => a -> Bool
hasNoVar = null . vars
variableView :: WithVars a => View a String
variableView = makeView getVariable variable
-----------------------------------------------------------
-- * Meta variables
class WithMetaVars a where
metaVar :: Int -> a
getMetaVar :: a -> Maybe Int
instance WithMetaVars Term where
metaVar = TMeta
getMetaVar (TMeta i) = Just i
getMetaVar _ = Nothing
isMetaVar :: WithMetaVars a => a -> Bool
isMetaVar = isJust . getMetaVar
metaVars :: (Uniplate a, WithMetaVars a) => a -> [Int]
metaVars = mapMaybe getMetaVar . universe
metaVarSet :: (Uniplate a, WithMetaVars a) => a -> IS.IntSet
metaVarSet = IS.fromList . metaVars
hasMetaVar :: (Uniplate a, WithMetaVars a) => Int -> a -> Bool
hasMetaVar i = (i `elem`) . metaVars
nextMetaVar :: (Uniplate a, WithMetaVars a) => a -> Int
nextMetaVar a
| null is = 0
| otherwise = maximum is + 1
where
is = metaVars a