-- | Defines various NounPhrase-level combinators. These hold more information
-- than those of the Sentence level but may not necessarily have a conceptual link.
-- See the [Wiki](https://github.com/JacquesCarette/Drasil/wiki/Combinator-Documentation)
-- for more information and details about the naming process for combinators.
-- A summary of the function naming scheme is as follows:
--
--    * Combinators that conflict with haskell-native functions have an underscore appended.
--    * Default plural case for combinators will be first term singular, second term plural.
--    * @P@ and @S@ denote the plural case of the combinator when it does not follow the above default.
--    * @Gen@ denotes the general function case.
--
-- This module should be used as a qualified import (usually as @NP@),
-- as many function names clash with those in Concepts.hs and Sentence.hs.
module Drasil.NaturalLanguage.English.NounPhrase.Combinators (
  -- * General Combinator Helper Functions
  insertString, prependString, insertStringOp, insertStringGen,
  -- * Prepositions
  -- ** \"The\" Combinators
  the, theGen,
  -- ** \"A\" Combinators
  a_, a_Gen,
  -- * Conjunctions
  -- ** \"And\" Combinators
  and_, and_PS, and_Gen, andThe,
  -- ** \"The\" Combinators
  ofThe, ofThePS, ofTheGen, inThe, inThePS, inTheGen,
  the_ofThe, the_ofThePS, the_ofTheGen,
  -- ** \"For\" Combinators
  for, forPS, forGen,
  -- ** \"Of\" Combinators
  of_, of_PS, of_Gen,
  -- ** Other Combinators
  with, parensNP,
  -- re-exports
  npS, npP, (.+.)
) where

import Drasil.NaturalLanguage.English.NounPhrase
    ( NPG,
      CapitalizationRuleG(CapWords, CapFirst, CapNothing),
      NounPhrase(phraseNP, pluralNP),
      nounPhrase'', surroundNPStruct,
      npS, npP, (.+.), NPStructG)

--Maybe move these to a separate Drasil.NounPhrase section
-- | Helper function that places a 'String' in between two 'NPG's. Plural case is
-- @(phraseNP t1) :+: S s :+: (pluralNP t2)@.
insertString :: String -> NPG a -> NPG a -> NPG a
insertString :: forall a. String -> NPG a -> NPG a -> NPG a
insertString String
str NPG a
t1 NPG a
t2 = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t2) (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
pluralNP NPG a
t2) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapFirst CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapWords

-- | Helper function that places a 'String' in between two 'NPG's. Plural case is
-- @(pluralNP t1) :+: S s :+: (phraseNP t2)@, i.e. opposite of 'insertString'
insertStringOp :: String -> NPG a -> NPG a -> NPG a
insertStringOp :: forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
str NPG a
t1 NPG a
t2 = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t2) (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
pluralNP NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t2) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapFirst CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapWords

-- | Helper function that places a 'String' in between two 'NPG's. Plural case is
-- given by two generic functions.
insertStringGen :: String -> (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
insertStringGen :: forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
str NPG a -> NPStructG a
f1 NPG a -> NPStructG a
f2 NPG a
t1 NPG a
t2 = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t2) (NPG a -> NPStructG a
f1 NPG a
t1 NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
f2 NPG a
t2) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapFirst CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapWords

-- | Helper function that prepends a 'String' to a 'NPG'.
prependString :: String -> NPG a -> NPG a
prependString :: forall a. String -> NPG a -> NPG a
prependString String
str NPG a
t1 = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t1) (String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
pluralNP NPG a
t1) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapFirst CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapWords

-- | Prepends a 'String' to an 'NPG' and adjust the plural
prependStringGen :: String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
prependStringGen :: forall a. String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
prependStringGen String
str NPG a -> NPStructG a
f NPG a
t = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t) (String -> NPStructG a
forall a. String -> NPStructG a
npS String
str NPStructG a -> NPStructG a -> NPStructG a
forall a. NPStructG a -> NPStructG a -> NPStructG a
.+. NPG a -> NPStructG a
f NPG a
t) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapFirst CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapWords

-- surrounding something makes it no capitalizatble at all
surround :: String -> String -> NPG a -> NPG a
surround :: forall a. String -> String -> NPG a -> NPG a
surround String
l String
r NPG a
t = NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
forall a.
NPStructG a
-> NPStructG a
-> CapitalizationRuleG a
-> CapitalizationRuleG a
-> NPG a
nounPhrase'' (String -> String -> NPStructG a -> NPStructG a
forall a. String -> String -> NPStructG a -> NPStructG a
surroundNPStruct String
l String
r (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
phraseNP NPG a
t)) (String -> String -> NPStructG a -> NPStructG a
forall a. String -> String -> NPStructG a -> NPStructG a
surroundNPStruct String
l String
r (NPG a -> NPStructG a
forall n a. NounPhrase n a => n -> NPStructG a
pluralNP NPG a
t)) CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapNothing CapitalizationRuleG a
forall a. CapitalizationRuleG a
CapNothing

{-
-- | Helper function that places a 'Sentence' in between two 'NPG's. Plural case is
-- @(phraseNP t1) :+: s :+: (pluralNP t2)@.
insertSent :: Sentence -> NP -> NP -> NP
insertSent s t1 t2 = nounPhrase'' (phraseNP t1 :+: s :+: phraseNP t2) (phraseNP t1 :+: s :+: pluralNP t2) CapFirst CapWords

-- | Helper function that prepends a 'Sentence' to a 'NPG'.
prependSent :: Sentence -> NP -> NP
prependSent s t1 = nounPhrase'' (s :+: phraseNP t1) (s :+: pluralNP t1) CapFirst CapWords
-}

-- | Prepends "the" to a 'NPG'.
the :: NPG a -> NPG a
the :: forall a. NPG a -> NPG a
the = String -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a
prependString String
"the"
-- | Similar to 'the', but accepts a function that determines the plural case.
theGen :: (NPG a -> NPStructG a) -> NPG a -> NPG a
theGen :: forall a. (NPG a -> NPStructG a) -> NPG a -> NPG a
theGen = String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
forall a. String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
prependStringGen String
"the"

-- | Prepends "a" to a 'NPG'.
a_ :: NPG a -> NPG a
a_ :: forall a. NPG a -> NPG a
a_ = String -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a
prependString String
"a"
-- | Similar to 'a', but accepts a function that determines the plural case.
a_Gen :: (NPG a -> NPStructG a) -> NPG a -> NPG a
a_Gen :: forall a. (NPG a -> NPStructG a) -> NPG a -> NPG a
a_Gen = String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
forall a. String -> (NPG a -> NPStructG a) -> NPG a -> NPG a
prependStringGen String
"a"

-- | Inserts "of the" between two 'NPG's. Plural case is @(phraseNP t1) :+: "of the" :+: (pluralNP t2)@.
ofThe :: NPG a -> NPG a -> NPG a
ofThe :: forall a. NPG a -> NPG a -> NPG a
ofThe = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"of the"
-- | Similar to 'ofThe', but the plural case is now @(pluralNP t1) `ofThe` (phraseNP t2)@.
--
ofThePS :: NPG a -> NPG a -> NPG a
ofThePS :: forall a. NPG a -> NPG a -> NPG a
ofThePS = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
"of the"
-- | Similar to 'ofThe', but accepts two functions for the plural case.
ofTheGen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
ofTheGen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
ofTheGen = String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
"of the"

-- | Inserts "in the" between two 'NPG's. Plural case is @(phraseNP t1) :+: "in the" :+: (pluralNP t2)@.
inThe :: NPG a -> NPG a -> NPG a
inThe :: forall a. NPG a -> NPG a -> NPG a
inThe = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"in the"
-- | Similar to 'ofThe', but the plural case is now @(pluralNP t1) `inThe` (phraseNP t2)@.
inThePS :: NPG a -> NPG a -> NPG a
inThePS :: forall a. NPG a -> NPG a -> NPG a
inThePS = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
"in the"
-- | Similar to 'ofThe', but accepts two functions for the plural case.
inTheGen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
inTheGen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
inTheGen = String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
"in the"

-- | Prepends "the" and inserts "of the". Plural case is @"the" :+: (phraseNP t1) :+: "of the" :+: (pluralNP t2)@.
the_ofThe :: NPG a -> NPG a -> NPG a
the_ofThe :: forall a. NPG a -> NPG a -> NPG a
the_ofThe NPG a
t1 NPG a
t2 = NPG a -> NPG a
forall a. NPG a -> NPG a
the NPG a
t1 NPG a -> NPG a -> NPG a
forall a. NPG a -> NPG a -> NPG a
`ofThe` NPG a
t2
-- | Similar to 'the_ofThe', but the plural case is now @ S "the" :+: (pluralNP t1) `ofThe` (phraseNP t2)@.
the_ofThePS :: NPG a -> NPG a -> NPG a
the_ofThePS :: forall a. NPG a -> NPG a -> NPG a
the_ofThePS NPG a
t1 NPG a
t2 = NPG a -> NPG a
forall a. NPG a -> NPG a
the NPG a
t1 NPG a -> NPG a -> NPG a
forall a. NPG a -> NPG a -> NPG a
`ofThePS` NPG a
t2
-- | Similar to 'the_ofThe'', but takes two functions for the plural case.
the_ofTheGen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
the_ofTheGen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
the_ofTheGen NPG a -> NPStructG a
f1 NPG a -> NPStructG a
f2 NPG a
t1 = (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
ofTheGen NPG a -> NPStructG a
f1 NPG a -> NPStructG a
f2 (NPG a -> NPG a
forall a. NPG a -> NPG a
the NPG a
t1)

-- | Inserts "for" between two 'NPG's. Plural case is @(phraseNP t1) :+: "for" :+: (pluralNP t2)@.
for :: NPG a -> NPG a -> NPG a
for :: forall a. NPG a -> NPG a -> NPG a
for = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"for"
-- | Same as 'for', but plural case is now @(pluralNP t1) `for` (phraseNP t2)@.
forPS :: NPG a -> NPG a -> NPG a
forPS :: forall a. NPG a -> NPG a -> NPG a
forPS = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
"for"
-- | Same as 'for'', but takes two functions for the plural case.
forGen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
forGen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
forGen = String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
"for"

-- | Inserts "of" between two 'NPG's. Plural case is @(phraseNP t1) :+: "of" :+: (pluralNP t2)@.
of_ :: NPG a -> NPG a -> NPG a
of_ :: forall a. NPG a -> NPG a -> NPG a
of_ = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"of"
-- | Same as 'of_', but plural case is now @(pluralNP t1) `of_` (phraseNP t2)@.
of_PS :: NPG a -> NPG a -> NPG a
of_PS :: forall a. NPG a -> NPG a -> NPG a
of_PS = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
"of"
-- | Same as 'of_', but takes two functions for the plural case.
of_Gen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
of_Gen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
of_Gen = String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
"of"

-- | Inserts "with" between two 'NPG's. Plural case is @(phraseNP t1) :+: "with" :+: (pluralNP t2)@.
with :: NPG a -> NPG a -> NPG a
with :: forall a. NPG a -> NPG a -> NPG a
with = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"with"

-- | Inserts "and" between two 'NPG's. Plural case is @(phraseNP t1) :+: "and" :+: (pluralNP t2)@.
and_ :: NPG a -> NPG a -> NPG a
and_ :: forall a. NPG a -> NPG a -> NPG a
and_ = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"and"
-- | Same as 'and_', but plural case is now @(pluralNP t1) `and_` (phraseNP t2)@.
and_PS :: NPG a -> NPG a -> NPG a
and_PS :: forall a. NPG a -> NPG a -> NPG a
and_PS = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertStringOp String
"and"
-- | Same as 'and_', but takes two functions for the plural case.
and_Gen :: (NPG a -> NPStructG a) -> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
and_Gen :: forall a.
(NPG a -> NPStructG a)
-> (NPG a -> NPStructG a) -> NPG a -> NPG a -> NPG a
and_Gen = String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
forall a.
String
-> (NPG a -> NPStructG a)
-> (NPG a -> NPStructG a)
-> NPG a
-> NPG a
-> NPG a
insertStringGen String
"and"

-- | Inserts "and the" between two 'NPG's. Plural case is @(phraseNP t1) :+: "and the" :+: (pluralNP t2)@.
andThe :: NPG a -> NPG a -> NPG a
andThe :: forall a. NPG a -> NPG a -> NPG a
andThe = String -> NPG a -> NPG a -> NPG a
forall a. String -> NPG a -> NPG a -> NPG a
insertString String
"and the"

-- | Puts parentheses around a word; to be used as a kind of postfix qualifier
parensNP :: NPG a -> NPG a
parensNP :: forall a. NPG a -> NPG a
parensNP = String -> String -> NPG a -> NPG a
forall a. String -> String -> NPG a -> NPG a
surround String
"(" String
")"