-- | Defines various chunk combinators. The full naming scheme can be found
-- in the [Wiki](https://github.com/JacquesCarette/Drasil/wiki/Combinator-Documentation).
-- For convenience, here is a summary:
--
--    * Combinators that conflict with haskell-native functions have an underscore appended.
--    * Default pluralNP case for combinators will be first term singular, second term plural.
--    * @P@ and @S@ denote the pluralNP case of the combinator when it does not follow the above default.
--    * @Gen@ denotes the general function case.
--    * Although this should eventually be phased out, @T@ denotes a combinator meant for use with titles.
--    * @NI@ and @NP@ denote whether something must be a part of the 'NamedIdea' or 'NounPhrase' class.
module Language.Drasil.Chunk.Concept.NamedCombinators (
  -- * Prepositions
  -- ** \"The\" Combinators
  the, theGen,
  -- ** \"A\" Combinators
  a_, a_Gen,
  -- * Conjunctions
  -- ** \"And\" Combinators
  and_, and_PS, and_PP, and_TGen,
  andIts, andThe,
  -- ** \"Of\" Combinators
  of_, of_NINP, of_PSNPNI, of_PS, ofA, ofAPS, ofThe, ofThePS,
  -- ** \"The\" Combinators
  the_ofThe, the_ofThePS, onThe, onThePS, onThePP,
  inThe, inThePS, inThePP, isThe, toThe,
  -- ** \"For\" Combinators
  for, forTGen,
  -- ** \"In\" Combinators
  in_, in_PS, inA,
  -- ** Other Combinators
  is, with,
  -- * Direct Term Combinators
  -- | Some are specific to 'IdeaDict's.
  compoundNC, compoundNCPP, compoundNCGen,
  compoundNCPS, compoundNCPSPP, compoundNCGenP,
  combineNINP, combineNINI) where

import Language.Drasil.Chunk.NamedIdea ( IdeaDict, ncUID )
import Language.Drasil.Classes ( Idea, NamedIdea(..) )
import Language.Drasil.NounPhrase
    ( NP,
      CapitalizationRule(CapWords, Replace, CapFirst),
      NounPhrase(phraseNP, pluralNP),
      nounPhrase'',
      compoundPhrase,
      compoundPhrase'',
      compoundPhrase''' )
import Language.Drasil.NounPhrase.Core (NPStruct(S,(:+:)))
import Drasil.Database.UID ( (+++!) )
import qualified Language.Drasil.NounPhrase as D
    ( NounPhrase(pluralNP, phraseNP) )
import Control.Lens ((^.))

import qualified Language.Drasil.NounPhrase.Combinators as NP (
  insertString, insertStringOp, insertStringGen)

-- not exported
phrase, plural :: NamedIdea n => n -> NPStruct
phrase :: forall n. NamedIdea n => n -> NPStruct
phrase n
k = NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
phraseNP (NP -> NPStruct) -> NP -> NPStruct
forall a b. (a -> b) -> a -> b
$ n
k n -> Getting NP n NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP n NP
forall c. NamedIdea c => Lens' c NP
Lens' n NP
term
plural :: forall n. NamedIdea n => n -> NPStruct
plural n
k = NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP (NP -> NPStruct) -> NP -> NPStruct
forall a b. (a -> b) -> a -> b
$ n
k n -> Getting NP n NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP n NP
forall c. NamedIdea c => Lens' c NP
Lens' n NP
term

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "and" between
-- their terms. Plural case is @(phraseNP t1) "and" (pluralNP t2)@.
and_ :: (NamedIdea c, NamedIdea d) => c -> d -> NP
and_ :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
and_ c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"and" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "and" between
-- their terms. Plural case is @(pluralNP t1) "and" (phraseNP t2)@.
and_PS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
and_PS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
and_PS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"and" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "and" between
-- their terms. Plural case is @(pluralNP t1) "and" (pluralNP t2)@.
and_PP :: (NamedIdea c, NamedIdea d) => c -> d -> NP
and_PP :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
and_PP c
t1 d
t2 = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase''
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"and" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase d
t2)
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"and" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural d
t2)
  CapitalizationRule
CapFirst
  CapitalizationRule
CapWords

-- | Customizable `and_` combinator (takes two title case capitalization rules and two 'NamedIdeas').
and_TGen :: (NamedIdea c, NamedIdea d) =>
  (c -> NPStruct) -> (d -> NPStruct) -> c -> d -> NP
and_TGen :: forall c d.
(NamedIdea c, NamedIdea d) =>
(c -> NPStruct) -> (d -> NPStruct) -> c -> d -> NP
and_TGen c -> NPStruct
f1 d -> NPStruct
f2 c
t1 d
t2 = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase''
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"and" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase d
t2)
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"and" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural d
t2)
  CapitalizationRule
CapFirst
  (NPStruct -> CapitalizationRule
Replace (c -> NPStruct
f1 c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"and" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
f2 d
t2))

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "and its" between
-- their terms. Plural case is @(phraseNP t1) "and its" (pluralNP t2)@.
andIts :: (NamedIdea a, NamedIdea b) => a -> b -> NP
andIts :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
andIts a
t1 b
t2 = String -> NP -> NP -> NP
NP.insertString String
"and its" (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "and the" between
-- their terms. Plural case is @(phraseNP t1) "and the" (pluralNP t2)@.
andThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
andThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
andThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"and the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Case with "T1s with T2", as opposed to "T1 with T2", i.e.
-- singular case is @(pluralNP t1) "with" (phraseNP t2)@ while the pluralNP case pluralizes the first.
with :: (NamedIdea c, NamedIdea d) => c -> d -> NP
with :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
with c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"with" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "of" between
-- their terms. Plural case is @(phraseNP t1) "of" (pluralNP t2)@.
of_ :: (NamedIdea c, NamedIdea d) => c -> d -> NP
of_ :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
of_ c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"of" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'of_' but second argument is NP.
of_NINP :: (NamedIdea c) => c -> NP -> NP
of_NINP :: forall c. NamedIdea c => c -> NP -> NP
of_NINP c
t1 = String -> NP -> NP -> NP
NP.insertString String
"of" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term)

-- | Same as 'of_' but first argument is a `NounPhrase`
-- and pluralNP case is @(pluralNP t1) "of" (phraseNP t2)@.
of_PSNPNI :: (NamedIdea d) => NP -> d -> NP
of_PSNPNI :: forall d. NamedIdea d => NP -> d -> NP
of_PSNPNI NP
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of" NP
t1 (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'of_', except pluralNP case is @(pluralNP t1) "of" (phraseNP t2)@.
of_PS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
of_PS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
of_PS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'of_PS', except combining 'NPStruct piece is "of a".
ofA :: (NamedIdea c, NamedIdea d) => c -> d -> NP
ofA :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
ofA c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of a" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

--- | Same as 'ofA', except phrase case is @(plural t1) "of a" (phrase t2)@.
ofAPS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
ofAPS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
ofAPS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of a" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'of_', except combining 'NPStruct piece is "of the". Plural case is @(phraseNP t1) `NP.ofThe` (pluralNP t2)@.
ofThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
ofThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
ofThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"of the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'ofThe', except pluralNP case is @(pluralNP t1) `NP.ofThe` (phraseNP t2)@.
ofThePS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
ofThePS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
ofThePS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'ofThe', except prepends "the".
the_ofThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
the_ofThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
the_ofThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"of the" (c -> NP
forall t. NamedIdea t => t -> NP
the c
t1) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'the_ofThe', except pluralNP case is @(pluralNP t1) `NP.the_ofThe` (phraseNP t2)@
the_ofThePS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
the_ofThePS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
the_ofThePS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"of the" (c -> NP
forall t. NamedIdea t => t -> NP
the c
t1) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'of_', except combining NPStruct piece is "on the".
onThe :: (NamedIdea a, NamedIdea b) => a -> b -> NP
onThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
onThe a
t1 b
t2 = String -> NP -> NP -> NP
NP.insertString String
"on the" (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term)

-- | Same as 'onThe', except pluralNP case is (pluralNP t1) NP.onThe (phraseNP t2)
onThePS :: (NamedIdea a, NamedIdea b) => a -> b -> NP
onThePS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
onThePS a
t1 b
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"on the" (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term)

-- | Same as 'onThe', except pluralNP case is (pluralNP t1) NP.onThe (pluralNP t2)
onThePP :: (NamedIdea c, NamedIdea d) => c -> d -> NP
onThePP :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
onThePP c
t1 d
t2 = String -> (NP -> NPStruct) -> (NP -> NPStruct) -> NP -> NP -> NP
NP.insertStringGen String
"on the" NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "in the" between
-- their terms. Plural case is @(phraseNP t1) "in the" (pluralNP t2)@.
inThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
inThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
inThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"in the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "in the" between
-- their terms. Plural case is @(pluralNP t1) "in the" (phraseNP t2)@.
inThePS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
inThePS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
inThePS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"in the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "in the" between
-- their terms. Plural case is @(pluralNP t1) "in the" (pluralNP t2)@.
inThePP :: (NamedIdea c, NamedIdea d) => c -> d -> NP
inThePP :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
inThePP c
t1 d
t2 = String -> (NP -> NPStruct) -> (NP -> NPStruct) -> NP -> NP -> NP
NP.insertStringGen String
"in the" NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "is the" between
-- their terms. Plural case is @(phraseNP t1) "is the" (pluralNP t2)@.
isThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
isThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
isThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"is the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "to the" between
-- their terms. Plural case is @(phraseNP t1) "to the" (pluralNP t2)@.
toThe :: (NamedIdea c, NamedIdea d) => c -> d -> NP
toThe :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
toThe c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"to the" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

--FIXME: As mentioned in issue #487, the following should be re-examined later,
--       as they may embody a deeper idea in some cases.

-- we might want to eventually restrict the use of these via
-- some kind of type system, which asserts that:
-- 1. t1 `for` t2 means that t1 is a view of part of the reason behind t2
-- 2. t1 `of_` t2 means that t1 is a view of part of the structure of t2

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "for" between
-- their terms. Plural case is @(phraseNP t1) "for" (pluralNP t2)@.
for :: (NamedIdea c, NamedIdea d) => c -> d -> NP
for :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
for c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"for" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Similar to 'for', but takes two functions that determine the 'titleCase'.
forTGen :: (NamedIdea c, Idea d) => (c -> NPStruct) -> (d -> NPStruct) -> c -> d -> NP
forTGen :: forall c d.
(NamedIdea c, Idea d) =>
(c -> NPStruct) -> (d -> NPStruct) -> c -> d -> NP
forTGen c -> NPStruct
f1 d -> NPStruct
f2 c
t1 d
t2 = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase''
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"for" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase d
t2)
  (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"for" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase d
t2)
  CapitalizationRule
CapFirst
  (NPStruct -> CapitalizationRule
Replace (c -> NPStruct
f1 c
t1 NPStruct -> NPStruct -> NPStruct
:+: String -> NPStruct
S String
"for" NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
f2 d
t2))

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "in" between
-- their terms. Plural case is @(phraseNP t1) "in" (pluralNP t2)@.
in_ :: (NamedIdea c, NamedIdea d) => c -> d -> NP
in_ :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
in_ c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"in" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Same as 'in_', except pluralNP case is @(pluralNP t1) "in" (phraseNP t2)@.
in_PS :: (NamedIdea c, NamedIdea d) => c -> d -> NP
in_PS :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
in_PS c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertStringOp String
"in" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the words "in a" between
-- their terms. Plural case is @(phraseNP t1) "in a" (pluralNP t2)@.
inA :: (NamedIdea c, NamedIdea d) => c -> d -> NP
inA :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
inA c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"in a" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Creates a 'NP' by combining two 'NamedIdea's with the word "is" between
-- their terms. Plural case is @(phraseNP t1) "is" (pluralNP t2)@.
is :: (NamedIdea c, NamedIdea d) => c -> d -> NP
is :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
is c
t1 d
t2 = String -> NP -> NP -> NP
NP.insertString String
"is" (c
t1 c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
Lens' c NP
term) (d
t2 d -> Getting NP d NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP d NP
forall c. NamedIdea c => Lens' c NP
Lens' d NP
term)

-- | Prepends "the" to a 'NamedIdea'.
the :: (NamedIdea t) => t -> NP
the :: forall t. NamedIdea t => t -> NP
the t
t = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (String -> NPStruct
S String
"the" NPStruct -> NPStruct -> NPStruct
:+: t -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase t
t) (String -> NPStruct
S String
"the" NPStruct -> NPStruct -> NPStruct
:+: t -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural t
t) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | A customizable version of 'the'. The given function is applied to both singular and pluralNP cases.
theGen :: (t -> NPStruct) -> t -> NP
theGen :: forall t. (t -> NPStruct) -> t -> NP
theGen t -> NPStruct
f t
t = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (String -> NPStruct
S String
"the" NPStruct -> NPStruct -> NPStruct
:+: t -> NPStruct
f t
t) (String -> NPStruct
S String
"the" NPStruct -> NPStruct -> NPStruct
:+: t -> NPStruct
f t
t) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Prepends "a" to a 'NamedIdea' (similar to 'the').
a_ :: (NamedIdea c) => c -> NP
a_ :: forall t. NamedIdea t => t -> NP
a_ c
t = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (String -> NPStruct
S String
"a" NPStruct -> NPStruct -> NPStruct
:+: c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t) (String -> NPStruct
S String
"a" NPStruct -> NPStruct -> NPStruct
:+: c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural c
t) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Customizable version of 'a'.
a_Gen :: (c -> NPStruct) -> c -> NP
a_Gen :: forall t. (t -> NPStruct) -> t -> NP
a_Gen c -> NPStruct
f c
t = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (String -> NPStruct
S String
"a" NPStruct -> NPStruct -> NPStruct
:+: c -> NPStruct
f c
t) (String -> NPStruct
S String
"a" NPStruct -> NPStruct -> NPStruct
:+: c -> NPStruct
f c
t) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Combinator for combining two 'NamedIdeas's into a 'IdeaDict'.
-- Plural case only makes second term plural.
-- See 'compoundPhrase' for more on pluralNP behaviour.
-- /Does not preserve abbreviations/.
compoundNC :: (NamedIdea a, NamedIdea b) => a -> b -> IdeaDict
compoundNC :: forall a b. (NamedIdea a, NamedIdea b) => a -> b -> IdeaDict
compoundNC a
t1 b
t2 = UID -> NP -> IdeaDict
ncUID
  (a
t1 a -> b -> UID
forall a b. (HasUID a, HasUID b) => a -> b -> UID
+++! b
t2) (NP -> NP -> NP
forall a b. (NounPhrase a, NounPhrase b) => a -> b -> NP
compoundPhrase (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term))

-- | Similar to 'compoundNC' but both terms are pluralized for pluralNP case.
compoundNCPP :: (NamedIdea a, NamedIdea b) => a -> b -> IdeaDict
compoundNCPP :: forall a b. (NamedIdea a, NamedIdea b) => a -> b -> IdeaDict
compoundNCPP a
t1 b
t2 = UID -> NP -> IdeaDict
ncUID
  (a
t1 a -> b -> UID
forall a b. (HasUID a, HasUID b) => a -> b -> UID
+++! b
t2) ((NP -> NPStruct) -> (NP -> NPStruct) -> NP -> NP -> NP
compoundPhrase'' NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
D.pluralNP NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
D.pluralNP (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term))

-- | Similar to 'compoundNC', except pluralNP cases are customizable.
compoundNCGen :: (NamedIdea a, NamedIdea b) =>
  (NP -> NPStruct) -> (NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGen :: forall a b.
(NamedIdea a, NamedIdea b) =>
(NP -> NPStruct) -> (NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGen NP -> NPStruct
f1 NP -> NPStruct
f2 a
t1 b
t2 = UID -> NP -> IdeaDict
ncUID
  (a
t1 a -> b -> UID
forall a b. (HasUID a, HasUID b) => a -> b -> UID
+++! b
t2)
  ((NP -> NPStruct) -> (NP -> NPStruct) -> NP -> NP -> NP
compoundPhrase'' NP -> NPStruct
f1 NP -> NPStruct
f2 (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term))

-- | Similar to 'compoundNC', except for pluralNP case, where first parameter gets pluralized while second one stays singular.
compoundNCPS :: IdeaDict -> IdeaDict -> IdeaDict
compoundNCPS :: IdeaDict -> IdeaDict -> IdeaDict
compoundNCPS = (NP -> NPStruct)
-> (NP -> NPStruct) -> IdeaDict -> IdeaDict -> IdeaDict
forall a b.
(NamedIdea a, NamedIdea b) =>
(NP -> NPStruct) -> (NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGen NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
D.pluralNP NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
D.phraseNP

-- hack for Solution Characteristics Specification, calling upon pluralNP will pluralize
-- Characteristics as it is the end of the first term (solutionCharacteristic)
-- | Similar to 'compoundNC', but takes a function that is applied to the first term (eg. 'short' or 'plural').
compoundNCGenP :: (NamedIdea a, NamedIdea b) => (NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGenP :: forall a b.
(NamedIdea a, NamedIdea b) =>
(NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGenP NP -> NPStruct
f1 a
t1 b
t2 = UID -> NP -> IdeaDict
ncUID
  (a
t1 a -> b -> UID
forall a b. (HasUID a, HasUID b) => a -> b -> UID
+++! b
t2) ((NP -> NPStruct) -> NP -> NP -> NP
compoundPhrase''' NP -> NPStruct
f1 (a
t1 a -> Getting NP a NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP a NP
forall c. NamedIdea c => Lens' c NP
Lens' a NP
term) (b
t2 b -> Getting NP b NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP b NP
forall c. NamedIdea c => Lens' c NP
Lens' b NP
term))

-- FIXME: Same as above function
-- | Similar to 'compoundNCGenP' but sets first parameter function to plural.
compoundNCPSPP :: IdeaDict -> IdeaDict -> IdeaDict
compoundNCPSPP :: IdeaDict -> IdeaDict -> IdeaDict
compoundNCPSPP = (NP -> NPStruct) -> IdeaDict -> IdeaDict -> IdeaDict
forall a b.
(NamedIdea a, NamedIdea b) =>
(NP -> NPStruct) -> a -> b -> IdeaDict
compoundNCGenP NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
D.pluralNP

-- | Helper function that combines a 'NamedIdea' and a 'NP' without any words in between.
-- Plural case is @(phraseNP t1) :+: (pluralNP t2)@.
combineNINP :: (NamedIdea c) => c -> NP -> NP
combineNINP :: forall c. NamedIdea c => c -> NP -> NP
combineNINP c
t1 NP
t2 = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
phraseNP NP
t2) (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: NP -> NPStruct
forall n. NounPhrase n => n -> NPStruct
pluralNP NP
t2) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Similar to 'combineNINP' but takes two 'NamedIdea's.
combineNINI :: (NamedIdea c, NamedIdea d) => c -> d -> NP
combineNINI :: forall c d. (NamedIdea c, NamedIdea d) => c -> d -> NP
combineNINI c
t1 d
t2 = NPStruct
-> NPStruct -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase d
t2) (c -> NPStruct
forall n. NamedIdea n => n -> NPStruct
phrase c
t1 NPStruct -> NPStruct -> NPStruct
:+: d -> NPStruct
forall n. NamedIdea n => n -> NPStruct
plural d
t2) CapitalizationRule
CapFirst CapitalizationRule
CapWords