packages feed

huff-0.1.0.0: src/Huff/Compile.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Huff.Compile (
    compileOperators,
    compileProblem,
    extractPlan,
    module Huff.Compile.AST,
  ) where

import           Huff.Compile.AST
import           Huff.Compile.Operators
import           Huff.Compile.Problem
import qualified Huff.Input as I

import           Data.Maybe (mapMaybe)
import qualified Data.Set as Set
import qualified Data.Text as T


-- | Compile operators, but leave off the negation removal step, which must be
-- done in the presence of the problem. The benefit to doing things this way, is
-- that this step can be done at compile time with template-haskell, and the
-- less-complicated negation removal step can be done at runtime, once the
-- problem is known.
compileOperators :: ([Name] -> a -> b) -> TypeMap Name -> [Operator a] -> [Operator b]
compileOperators adjust types ops =
  do op             <- ops
     (env,args,op') <- expandActions types op
     let op'' = op' { opVal = adjust args `fmap` opVal op' }
     removeDisjunction (removeQuantifiers types env op'')


-- | Compile a problem, in the context of the domain.
compileProblem :: TypeMap Name -> [Operator a] -> Problem -> (I.Problem,I.Domain a)
compileProblem types ops prob = (transProblem prob'', I.Domain (map transOperator ops'))
  where
  (prob',goalOp) = genProblemOperators prob
  (negs,ops')    = removeNegation (compileOperators adjust types [goalOp] ++ ops)
  prob''         = addNegativePreconditions negs prob'

  adjust _ _ = undefined


extractPlan :: [I.Operator a] -> [a]
extractPlan  = mapMaybe I.opVal

transProblem :: Problem -> I.Problem
transProblem Problem { .. } =
  I.Problem { I.probInit = [ transAtom a | LAtom a <- probInit ]
            , I.probGoal = transPre probGoal
            }

transDomain :: Domain a -> I.Domain a
transDomain Domain { .. } =
  I.Domain { I.domOperators = map transOperator domOperators }

transOperator :: Operator a -> I.Operator a
transOperator op @ Operator { .. } =
  I.Operator { I.opName    = opName
             , I.opPre     = transPre opPrecond
             , I.opEffects = transEff opEffects
             , I.opVal     = opVal
             }

transPre :: Term -> [I.Fact]
transPre (TAnd ts)        = concatMap transPre ts
transPre (TLit (LAtom a)) = [transAtom a]
transPre _                = error "transTerm"

transEff :: Effect -> [I.Effect]
transEff eff = simple ++ conditional
  where
  (lits,conds) = splitEffs eff

  simple | null lits = []
         | otherwise = [ foldl addEffect emptyEffect lits ]

  conditional =
    [ foldl addEffect eff' q | (p,q) <- conds
                             , let eff' = emptyEffect { I.ePre = transPre p } ]

  emptyEffect = I.Effect { I.ePre = [], I.eAdd = [], I.eDel = [] }

  addEffect e (LAtom a) = e { I.eAdd = transAtom a : I.eAdd e }
  addEffect e (LNot  a) = e { I.eDel = transAtom a : I.eDel e }

-- | Partition an effect into its simple, and conditional effects.
splitEffs :: Effect -> ([Literal],[(Term,[Literal])])
splitEffs eff = go [] [] (elimEAnd eff)
  where
  go ls cs (EWhen p q : rest) = go    ls ((p,q):cs) rest
  go ls cs (ELit l    : rest) = go (l:ls)       cs  rest
  go ls cs []                 = (ls,cs)
  go _  _  _                  = error "splitEffs"

transAtom :: Atom -> I.Fact
transAtom (Atom a as) = I.Fact a (map transArg as)

transArg :: Arg -> T.Text
transArg (AName n) = n
transArg _         = error "transArg"