packages feed

cg-0.0.9.0: CG/Parser.hs

{-# LANGUAGE TupleSections, RecordWildCards #-}
module CG.Parser (parse) where


import           Prelude hiding (lex)
import           CG.Base
import           Control.Arrow (first)
import           Control.Parallel.Strategies
import           Data.List (nub)
import           Data.Map (Map)
import qualified Data.Map as M
import           Data.Void (Void)



-- * Parsing

-- |Create all possible structures from a list of formulas, joining
--  them with the binary structural connective @·⊗·@, and then find
--  all proofs for each of these structures, returning a list of
--  structures paired with their proofs.
--  Note: the resulting list may contain pairs for structures for
--  which no proofs were found.
parse :: System ConId                 -- ^ Inference system
       -> Int                          -- ^ Search depth
       -> Map String (Term ConId Void) -- ^ Lexicon
       -> String                       -- ^ Sentence
       -> Term ConId Void              -- ^ Goal formula
       -> [(Term ConId Void,Term RuleId Void)]
parse sys@System{..} d lex sent g =
  solve sys d judgements `using` parList rdeepseq
  where
    -- read the entries from the lexicon, wrapping them in a
    -- down constructor if the logic is structural
    entries = lookupAll lex (words sent)
    entries'
      | structural = map (unary Down) entries
      | otherwise  = entries

    -- construct the left-hand sides using the @brackets@ function
    leftHandSides = brackets (unary <$> unaryOp) (binary (unsafeBinaryOp sys)) entries'

    -- construct all possible judgements by combining them with
    -- the sequent and the goal formula
    sequent    = if structural then JFocusR else JAlgebr
    judgements = map (flip (binary sequent) g) leftHandSides



-- |Look up all words in a given list of words in a lexicon.
lookupAll :: Map String (Term ConId Void) -- ^ Lexicon
          -> [String]                     -- ^ Sentence
          -> [Term ConId Void]
lookupAll _   [    ] = []
lookupAll lex (w:ws) = case M.lookup w lex of
  Just tm -> tm : lookupAll lex ws
  Nothing -> error ("Cannot find `"++w++"' in the lexicon.")



-- |Generate all binary trees with n nodes, formed by applications of
--  a given binary operator, with at most one application of a given
--  unary operator at every node.
brackets :: (Eq a) => Maybe (a -> a) -> (a -> a -> a) -> [a] -> [a]
brackets mbPre op = nub . brack where

  brack [ ] = [ ]
  brack [x] = [x]
  brack lst = maybe (go id) (\pre -> go id ++ go pre) mbPre
    where
      go f = [ f (l `op` r) | (ls,rs) <- split lst, l <- brack ls, r <- brack rs ]

  split [_]    = []
  split (x:xs) = ([x],xs) : map (first (x:)) (split xs)


-- |Retrieve the single binary connective from the system, or throw an error.
unsafeBinaryOp :: System c -> c
unsafeBinaryOp System{..} = case binaryOp of
  [   ] -> error "Must set at least one binary operator to parse."
  [ f ] -> f
  (_:_) -> error "Parsing with multiple binary operators is not implemented."