{-# Language PostfixOperators, TupleSections #-}
-- | Miscellaneous utility functions for use throughout Drasil.
module Language.Drasil.Document.Combinators (
  -- * Reference-related Functions
  -- | Attach a 'Reference' and a 'Sentence' in different ways.
  chgsStart, definedIn, definedIn', definedIn'', definedIn''',
  eqnWSource, fromReplace, fromSource, fromSources, fmtU, follows,
  makeListRef,
  -- * Sentence-related Functions
  -- | See Reference-related Functions as well.
  addPercent,
  eqN, checkValidStr, getTandS, maybeChanged, maybeExpanded,
  maybeWOVerb, showingCxnBw, substitute, typUncr, underConsidertn,
  unwrap, fterms,
  -- * List-related Functions
  bulletFlat, bulletNested, itemRefToSent, makeTMatrix, mkEnumAbbrevList,
  mkTableFromColumns, noRefs, refineChain, sortBySymbol, sortBySymbolTuple,
  tAndDOnly, tAndDWAcc, tAndDWSym,
  zipSentList
) where

import Language.Drasil.Chunk.Concept.Core ( ConceptChunk )
import Language.Drasil.Chunk.Quantity (DefinesQuantity(defLhs))
import Language.Drasil.Chunk.UnitDefn ( UnitDefn, MayHaveUnit(..) )
import Language.Drasil.Chunk.Unital ( UnitalChunk )
import Language.Drasil.Classes
    ( HasUnitSymbol(usymb),
      Quantity,
      Concept,
      Definition(defn),
      NamedIdea(..) )
import Language.Drasil.ShortName (HasShortName(..))
import Language.Drasil.Development.Sentence
    ( short, atStart, titleize, phrase, plural )
import Language.Drasil.Document ( Section )
import Language.Drasil.Document.Core
    ( ItemType(..), ListType(Bullet) )
import Language.Drasil.ModelExpr.Lang ( ModelExpr )
import Language.Drasil.NounPhrase.Core ( NP )
import Language.Drasil.Reference ( refS, namedRef )
import Language.Drasil.Sentence
    ( Sentence(S, Percent, (:+:), Sy, EmptyS),
      eS,
      ch,
      sParen,
      sDash,
      (+:+),
      sC,
      (+:+.),
      (!.),
      (+:),
      capSent )
import Language.Drasil.Symbol.Helpers ( eqSymb )
import Language.Drasil.Uncertainty
import Language.Drasil.Symbol
import Language.Drasil.Sentence.Fold
import qualified Language.Drasil.Sentence.Combinators as S (are, in_, is, toThe)
import Language.Drasil.UID ( HasUID )
import Language.Drasil.Label.Type

import Control.Lens ((^.))

import Data.Decimal (DecimalRaw, realFracToDecimal)
import Data.Function (on)
import Data.List (sortBy, transpose)

-- | Sorts a list of 'HasSymbols' by 'Symbol'.
sortBySymbol :: HasSymbol a => [a] -> [a]
sortBySymbol :: forall a. HasSymbol a => [a] -> [a]
sortBySymbol = (a -> a -> Ordering) -> [a] -> [a]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy a -> a -> Ordering
forall a. HasSymbol a => a -> a -> Ordering
compareBySymbol

-- | Sorts a tuple list of 'HasSymbols' by first Symbol in the tuple.
sortBySymbolTuple :: HasSymbol a => [(a, b)] -> [(a, b)]
sortBySymbolTuple :: forall a b. HasSymbol a => [(a, b)] -> [(a, b)]
sortBySymbolTuple = ((a, b) -> (a, b) -> Ordering) -> [(a, b)] -> [(a, b)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (a -> a -> Ordering
forall a. HasSymbol a => a -> a -> Ordering
compareBySymbol (a -> a -> Ordering)
-> ((a, b) -> a) -> (a, b) -> (a, b) -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (a, b) -> a
forall a b. (a, b) -> a
fst)

-- | Compare the equational 'Symbol' of two things.
compareBySymbol :: HasSymbol a => a -> a -> Ordering
compareBySymbol :: forall a. HasSymbol a => a -> a -> Ordering
compareBySymbol a
a a
b = Symbol -> Symbol -> Ordering
compsy (a -> Symbol
forall q. HasSymbol q => q -> Symbol
eqSymb a
a) (a -> Symbol
forall q. HasSymbol q => q -> Symbol
eqSymb a
b)

-- Ideally this would create a reference to the equation too.
-- Doesn't use equation concept so utils doesn't depend on data
-- | Prepends the word "Equation" to an 'Int'.
eqN :: Int -> Sentence
eqN :: Int -> Sentence
eqN Int
n = String -> Sentence
S String
"Equation" Sentence -> Sentence -> Sentence
+:+ Sentence -> Sentence
sParen (String -> Sentence
S (String -> Sentence) -> String -> Sentence
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show Int
n)

-- | Takes an expression and a 'Referable' and outputs as a Sentence "expression (source)".
eqnWSource :: (Referable r, HasShortName r) => ModelExpr -> r -> Sentence
eqnWSource :: forall r.
(Referable r, HasShortName r) =>
ModelExpr -> r -> Sentence
eqnWSource ModelExpr
a r
b = ModelExpr -> Sentence
eS ModelExpr
a Sentence -> Sentence -> Sentence
+:+ Sentence -> Sentence
sParen (r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
b)

-- | Takes a 'Referable' source and a 'UnitalChunk' and outputs as a 'Sentence': "From @source@ we can replace @symbol@:".
fromReplace :: (Referable r, HasShortName r) => r -> UnitalChunk -> Sentence
fromReplace :: forall r.
(Referable r, HasShortName r) =>
r -> UnitalChunk -> Sentence
fromReplace r
src UnitalChunk
c = String -> Sentence
S String
"From" Sentence -> Sentence -> Sentence
+:+ r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
src Sentence -> Sentence -> Sentence
`sC` String -> Sentence
S String
"we can replace" Sentence -> Sentence -> Sentence
+: UnitalChunk -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch UnitalChunk
c

-- | Takes a list of 'Referable's and 'Symbol's and outputs as a Sentence "By substituting @symbols@, this can be written as:".
substitute :: (Referable r, HasShortName r, DefinesQuantity r) => [r] -> Sentence
substitute :: forall r.
(Referable r, HasShortName r, DefinesQuantity r) =>
[r] -> Sentence
substitute [r]
s = String -> Sentence
S String
"By substituting" Sentence -> Sentence -> Sentence
+: (SepType -> FoldType -> [Sentence] -> Sentence
foldlList SepType
Comma FoldType
List [Sentence]
l Sentence -> Sentence -> Sentence
`sC` String -> Sentence
S String
"this can be written as")
  where l :: [Sentence]
l = (r -> Sentence) -> [r] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map (\r
x -> QuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
x r -> Getting QuantityDict r QuantityDict -> QuantityDict
forall s a. s -> Getting a s a -> a
^. Getting QuantityDict r QuantityDict
forall d. DefinesQuantity d => Getter d QuantityDict
Getter r QuantityDict
defLhs) Sentence -> Sentence -> Sentence
+:+ r -> Sentence
forall r. (Referable r, HasShortName r) => r -> Sentence
fromSource r
x) [r]
s

-- | Takes a 'HasSymbol' that is also 'Referable' and outputs as a 'Sentence': "@symbol@ is defined in @reference@."
definedIn :: (Referable r, HasShortName r, DefinesQuantity r) => r -> Sentence
definedIn :: forall r.
(Referable r, HasShortName r, DefinesQuantity r) =>
r -> Sentence
definedIn r
q = QuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q r -> Getting QuantityDict r QuantityDict -> QuantityDict
forall s a. s -> Getting a s a -> a
^. Getting QuantityDict r QuantityDict
forall d. DefinesQuantity d => Getter d QuantityDict
Getter r QuantityDict
defLhs) Sentence -> Sentence -> Sentence
`S.is` String -> Sentence
S String
"defined in" Sentence -> Sentence -> Sentence
+:+. r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
q

-- | Same as 'definedIn', but allows for additional information to be appended to the 'Sentence'.
definedIn' :: (Referable r, HasShortName r, DefinesQuantity r) => r -> Sentence -> Sentence
definedIn' :: forall r.
(Referable r, HasShortName r, DefinesQuantity r) =>
r -> Sentence -> Sentence
definedIn' r
q Sentence
info = QuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q r -> Getting QuantityDict r QuantityDict -> QuantityDict
forall s a. s -> Getting a s a -> a
^. Getting QuantityDict r QuantityDict
forall d. DefinesQuantity d => Getter d QuantityDict
Getter r QuantityDict
defLhs) Sentence -> Sentence -> Sentence
`S.is` String -> Sentence
S String
"defined" Sentence -> Sentence -> Sentence
`S.in_` r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
q Sentence -> Sentence -> Sentence
+:+. Sentence
info

-- | Takes a 'Referable' and outputs as a 'Sentence' "defined in @reference@" (no 'HasSymbol').
definedIn'' :: (Referable r, HasShortName r) => r -> Sentence
definedIn'' :: forall r. (Referable r, HasShortName r) => r -> Sentence
definedIn'' r
q =  String -> Sentence
S String
"defined" Sentence -> Sentence -> Sentence
`S.in_` r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
q

-- | Takes a 'Symbol' and its 'Reference' (does not append a period at the end!). Outputs as "@symbol@ is defined in @source@".
definedIn''' :: (HasSymbol q, HasUID q, Referable r, HasShortName r) => q -> r -> Sentence
definedIn''' :: forall q r.
(HasSymbol q, HasUID q, Referable r, HasShortName r) =>
q -> r -> Sentence
definedIn''' q
q r
src = q -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch q
q Sentence -> Sentence -> Sentence
`S.is` String -> Sentence
S String
"defined in" Sentence -> Sentence -> Sentence
+:+ r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
src

-- | Zip helper function enumerates abbreviations and zips it with list of 'ItemType':
--
--     * s - the number from which the enumeration should start from ('Integer'),
--     * t - the title of the list ('Sentence'),
--     * l - the list to be enumerated (['Sentence']).
mkEnumAbbrevList :: Integer -> Sentence -> [Sentence] -> [(Sentence, ItemType)]
mkEnumAbbrevList :: Integer -> Sentence -> [Sentence] -> [(Sentence, ItemType)]
mkEnumAbbrevList Integer
s Sentence
t [Sentence]
l = [Sentence] -> [ItemType] -> [(Sentence, ItemType)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Sentence
t Sentence -> Sentence -> Sentence
:+: String -> Sentence
S (Integer -> String
forall a. Show a => a -> String
show Integer
x) | Integer
x <- [Integer
s..]] ([ItemType] -> [(Sentence, ItemType)])
-> [ItemType] -> [(Sentence, ItemType)]
forall a b. (a -> b) -> a -> b
$ (Sentence -> ItemType) -> [Sentence] -> [ItemType]
forall a b. (a -> b) -> [a] -> [b]
map Sentence -> ItemType
Flat [Sentence]
l

-- | Takes an amount as a 'Sentence' and appends a unit to it.
fmtU :: (MayHaveUnit a) => Sentence -> a -> Sentence
fmtU :: forall a. MayHaveUnit a => Sentence -> a -> Sentence
fmtU Sentence
n a
u  = Sentence
n Sentence -> Sentence -> Sentence
+:+ Maybe UnitDefn -> Sentence
unwrap (a -> Maybe UnitDefn
forall u. MayHaveUnit u => u -> Maybe UnitDefn
getUnit a
u)

-- | Extracts the typical uncertainty to be displayed from something that has an uncertainty.
typUncr :: HasUncertainty c => c -> Sentence
typUncr :: forall c. HasUncertainty c => c -> Sentence
typUncr c
x = Double -> Maybe Int -> Sentence
forall {r} {a}.
(Show r, RealFrac r, Integral a) =>
r -> Maybe a -> Sentence
found (c -> Double
forall x. HasUncertainty x => x -> Double
uncVal c
x) (c -> Maybe Int
forall x. HasUncertainty x => x -> Maybe Int
uncPrec c
x)
  where
    found :: r -> Maybe a -> Sentence
found r
u Maybe a
Nothing  = r -> Sentence
forall a. Show a => a -> Sentence
addPercent (r -> Sentence) -> r -> Sentence
forall a b. (a -> b) -> a -> b
$ r
u r -> r -> r
forall a. Num a => a -> a -> a
* r
100
    found r
u (Just a
p) = DecimalRaw Integer -> Sentence
forall a. Show a => a -> Sentence
addPercent (Word8 -> r -> DecimalRaw Integer
forall i r. (Integral i, RealFrac r) => Word8 -> r -> DecimalRaw i
realFracToDecimal (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
p) (r
u r -> r -> r
forall a. Num a => a -> a -> a
* r
100) :: DecimalRaw Integer)

-- | Converts input to a 'Sentence' and appends %.
addPercent :: Show a => a -> Sentence
addPercent :: forall a. Show a => a -> Sentence
addPercent a
num = String -> Sentence
S (a -> String
forall a. Show a => a -> String
show a
num) Sentence -> Sentence -> Sentence
:+: Sentence
Percent

-- | Distributes a list of Sentences by prepending individual Sentences once to an existing list of Sentences. 
-- 
-- For example: 
--
-- >>> zipSentList [S "Hi", S "Hey", S "Hi"] [[S "Hello"], [S "World"], [S "Hello", S "World"]]
-- [[S "Hi", S "Hello"], [S "Hey", S "World"], [S "Hi", S "Hello", S "World"]]
zipSentList :: [[Sentence]] -> [Sentence] -> [[Sentence]] -> [[Sentence]] 
zipSentList :: [[Sentence]] -> [Sentence] -> [[Sentence]] -> [[Sentence]]
zipSentList [[Sentence]]
acc [Sentence]
_ []           = [[Sentence]]
acc
zipSentList [[Sentence]]
acc [] [[Sentence]]
r           = [[Sentence]]
acc [[Sentence]] -> [[Sentence]] -> [[Sentence]]
forall a. [a] -> [a] -> [a]
++ ([Sentence] -> [Sentence]) -> [[Sentence]] -> [[Sentence]]
forall a b. (a -> b) -> [a] -> [b]
map (Sentence
EmptyS:) [[Sentence]]
r
zipSentList [[Sentence]]
acc (Sentence
x:[Sentence]
xs) ([Sentence]
y:[[Sentence]]
ys)  = [[Sentence]] -> [Sentence] -> [[Sentence]] -> [[Sentence]]
zipSentList ([[Sentence]]
acc [[Sentence]] -> [[Sentence]] -> [[Sentence]]
forall a. [a] -> [a] -> [a]
++ [Sentence
xSentence -> [Sentence] -> [Sentence]
forall a. a -> [a] -> [a]
:[Sentence]
y]) [Sentence]
xs [[Sentence]]
ys

-- | Makes a traceability matrix from a list of row titles, a list of rows
--   of "checked" columns, and a list of columns.
makeTMatrix :: Eq a => [Sentence] -> [[a]] -> [a] -> [[Sentence]]
makeTMatrix :: forall a. Eq a => [Sentence] -> [[a]] -> [a] -> [[Sentence]]
makeTMatrix [Sentence]
rowName [[a]]
rows [a]
cols = [[Sentence]] -> [Sentence] -> [[Sentence]] -> [[Sentence]]
zipSentList [] [Sentence]
rowName [[a] -> [a] -> [Sentence]
forall {t :: * -> *} {t :: * -> *} {a}.
(Foldable t, Foldable t, Eq a) =>
t a -> t a -> [Sentence]
zipFTable' [a]
x [a]
cols | [a]
x <- [[a]]
rows]
  where
    zipFTable' :: t a -> t a -> [Sentence]
zipFTable' t a
content = (a -> [Sentence]) -> t a -> [Sentence]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\a
x -> if a
x a -> t a -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t a
content then [String -> Sentence
S String
"X"] else [Sentence
EmptyS])

-- | Helper for making a table from a columns.
mkTableFromColumns :: [(Sentence, [Sentence])] -> ([Sentence], [[Sentence]])
mkTableFromColumns :: [(Sentence, [Sentence])] -> ([Sentence], [[Sentence]])
mkTableFromColumns [(Sentence, [Sentence])]
l = 
  let l' :: [(Sentence, [Sentence])]
l' = ((Sentence, [Sentence]) -> Bool)
-> [(Sentence, [Sentence])] -> [(Sentence, [Sentence])]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ((Sentence, [Sentence]) -> Bool)
-> (Sentence, [Sentence])
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sentence -> Bool) -> [Sentence] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Sentence -> Bool
isEmpty ([Sentence] -> Bool)
-> ((Sentence, [Sentence]) -> [Sentence])
-> (Sentence, [Sentence])
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sentence, [Sentence]) -> [Sentence]
forall a b. (a, b) -> b
snd) [(Sentence, [Sentence])]
l in 
  (((Sentence, [Sentence]) -> Sentence)
-> [(Sentence, [Sentence])] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map (Sentence, [Sentence]) -> Sentence
forall a b. (a, b) -> a
fst [(Sentence, [Sentence])]
l', [[Sentence]] -> [[Sentence]]
forall a. [[a]] -> [[a]]
transpose ([[Sentence]] -> [[Sentence]]) -> [[Sentence]] -> [[Sentence]]
forall a b. (a -> b) -> a -> b
$ ((Sentence, [Sentence]) -> [Sentence])
-> [(Sentence, [Sentence])] -> [[Sentence]]
forall a b. (a -> b) -> [a] -> [b]
map ((Sentence -> Sentence) -> [Sentence] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map Sentence -> Sentence
replaceEmptyS ([Sentence] -> [Sentence])
-> ((Sentence, [Sentence]) -> [Sentence])
-> (Sentence, [Sentence])
-> [Sentence]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sentence, [Sentence]) -> [Sentence]
forall a b. (a, b) -> b
snd) [(Sentence, [Sentence])]
l')
  where
    isEmpty :: Sentence -> Bool
isEmpty       Sentence
EmptyS = Bool
True
    isEmpty       Sentence
_      = Bool
False
    replaceEmptyS :: Sentence -> Sentence
replaceEmptyS Sentence
EmptyS = String -> Sentence
S String
"--"
    replaceEmptyS Sentence
s      = Sentence
s

-- | Makes 'Sentence's from an item and its reference. 
-- Takes the title of reference as a 'String' and a 
-- 'Sentence' containing the full reference. Wraps the full reference in parenthesis.
itemRefToSent :: String -> Sentence -> Sentence
itemRefToSent :: String -> Sentence -> Sentence
itemRefToSent String
a Sentence
b = String -> Sentence
S String
a Sentence -> Sentence -> Sentence
+:+ Sentence -> Sentence
sParen Sentence
b

-- | Takes a list and a 'Section', then generates a list of that section's reference to 
-- match the length of the list.
makeListRef :: [a] -> Section -> [Sentence]
makeListRef :: forall a. [a] -> Section -> [Sentence]
makeListRef [a]
l = Int -> Sentence -> [Sentence]
forall a. Int -> a -> [a]
replicate ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l) (Sentence -> [Sentence])
-> (Section -> Sentence) -> Section -> [Sentence]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Section -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS

-- | Applies 'Bullet' and 'Flat' to a list.
bulletFlat :: [Sentence] -> ListType
bulletFlat :: [Sentence] -> ListType
bulletFlat = [(ItemType, Maybe String)] -> ListType
Bullet ([(ItemType, Maybe String)] -> ListType)
-> ([Sentence] -> [(ItemType, Maybe String)])
-> [Sentence]
-> ListType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ItemType] -> [(ItemType, Maybe String)]
noRefs ([ItemType] -> [(ItemType, Maybe String)])
-> ([Sentence] -> [ItemType])
-> [Sentence]
-> [(ItemType, Maybe String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sentence -> ItemType) -> [Sentence] -> [ItemType]
forall a b. (a -> b) -> [a] -> [b]
map Sentence -> ItemType
Flat

-- | Applies 'Bullet's and headers to a 'Nested' 'ListType'. 
-- The first argument is the headers of the 'Nested' lists.
bulletNested :: [Sentence] -> [ListType] -> ListType
bulletNested :: [Sentence] -> [ListType] -> ListType
bulletNested [Sentence]
t [ListType]
l = [(ItemType, Maybe String)] -> ListType
Bullet ((Sentence -> ListType -> (ItemType, Maybe String))
-> [Sentence] -> [ListType] -> [(ItemType, Maybe String)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Sentence
h ListType
c -> (Sentence -> ListType -> ItemType
Nested Sentence
h ListType
c, Maybe String
forall a. Maybe a
Nothing)) [Sentence]
t [ListType]
l)

-- | Get a unit symbol if there is one.
unwrap :: Maybe UnitDefn -> Sentence
unwrap :: Maybe UnitDefn -> Sentence
unwrap (Just UnitDefn
a) = USymb -> Sentence
Sy (USymb -> Sentence) -> USymb -> Sentence
forall a b. (a -> b) -> a -> b
$ UnitDefn -> USymb
forall u. HasUnitSymbol u => u -> USymb
usymb UnitDefn
a
unwrap Maybe UnitDefn
Nothing  = Sentence
EmptyS

-- | Converts lists of simple 'ItemType's into a list which may be used
-- in 'Contents' but is not directly referable.
noRefs :: [ItemType] -> [(ItemType, Maybe String)]
noRefs :: [ItemType] -> [(ItemType, Maybe String)]
noRefs = (ItemType -> (ItemType, Maybe String))
-> [ItemType] -> [(ItemType, Maybe String)]
forall a b. (a -> b) -> [a] -> [b]
map (, Maybe String
forall a. Maybe a
Nothing)

--Doesn't use connection phrase so utils doesn't depend on data
-- | Returns the 'Sentence' "@('titleize' aNamedIdea)@ Showing the Connections Between @contents@".
showingCxnBw :: NamedIdea c => c -> Sentence -> Sentence
showingCxnBw :: forall c. NamedIdea c => c -> Sentence -> Sentence
showingCxnBw c
traceyVar Sentence
contents = c -> Sentence
forall n. NamedIdea n => n -> Sentence
titleize c
traceyVar Sentence -> Sentence -> Sentence
+:+
  String -> Sentence
S String
"Showing the Connections Between" Sentence -> Sentence -> Sentence
+:+ Sentence
contents

-- | Returns the 'Sentence' "The @chunk@ under consideration is @chunkDefinition@".
underConsidertn :: ConceptChunk -> Sentence
underConsidertn :: ConceptChunk -> Sentence
underConsidertn ConceptChunk
chunk = String -> Sentence
S String
"The" Sentence -> Sentence -> Sentence
+:+ ConceptChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
phrase ConceptChunk
chunk Sentence -> Sentence -> Sentence
+:+ 
  String -> Sentence
S String
"under consideration is" Sentence -> Sentence -> Sentence
+:+. (ConceptChunk
chunk ConceptChunk -> Getting Sentence ConceptChunk Sentence -> Sentence
forall s a. s -> Getting a s a -> a
^. Getting Sentence ConceptChunk Sentence
forall c. Definition c => Lens' c Sentence
Lens' ConceptChunk Sentence
defn)

-- | Create a list in the pattern of "The \_\_ are refined to the \_\_".
-- Note: Order matters!
refineChain :: NamedIdea c => [(c, Section)] -> Sentence
refineChain :: forall c. NamedIdea c => [(c, Section)] -> Sentence
refineChain [(c, Section)
x,(c, Section)
y] = String -> Sentence
S String
"The" Sentence -> Sentence -> Sentence
+:+ Section -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef ((c, Section) -> Section
forall a b. (a, b) -> b
snd (c, Section)
x) (c -> Sentence
forall n. NamedIdea n => n -> Sentence
plural (c -> Sentence) -> c -> Sentence
forall a b. (a -> b) -> a -> b
$ (c, Section) -> c
forall a b. (a, b) -> a
fst (c, Section)
x) Sentence -> Sentence -> Sentence
`S.are` String -> Sentence
S String
"refined" Sentence -> Sentence -> Sentence
`S.toThe` c -> Sentence
forall n. NamedIdea n => n -> Sentence
plural ((c, Section) -> c
forall a b. (a, b) -> a
fst (c, Section)
y)
refineChain ((c, Section)
x:(c, Section)
y:[(c, Section)]
xs) = (SepType -> FoldType -> [Sentence] -> Sentence
foldlList SepType
Comma FoldType
List ([(c, Section)] -> Sentence
forall c. NamedIdea c => [(c, Section)] -> Sentence
refineChain [(c, Section)
x,(c, Section)
y] Sentence -> [Sentence] -> [Sentence]
forall a. a -> [a] -> [a]
: [(c, Section)] -> [Sentence]
forall {b} {n}.
(HasRefAddress b, HasShortName b, NamedIdea n, HasUID b) =>
[(n, b)] -> [Sentence]
rc ((c, Section)
y (c, Section) -> [(c, Section)] -> [(c, Section)]
forall a. a -> [a] -> [a]
: [(c, Section)]
xs)) !.)
  where
    rc :: [(n, b)] -> [Sentence]
rc [(n, b)
a, (n, b)
b]   = [(n, b) -> (n, b) -> Sentence
forall {b} {b} {n} {n}.
(HasRefAddress b, HasRefAddress b, HasShortName b, HasShortName b,
 NamedIdea n, NamedIdea n, HasUID b, HasUID b) =>
(n, b) -> (n, b) -> Sentence
rcSent (n, b)
a (n, b)
b]
    rc ((n, b)
a:(n, b)
b:[(n, b)]
as) =  (n, b) -> (n, b) -> Sentence
forall {b} {b} {n} {n}.
(HasRefAddress b, HasRefAddress b, HasShortName b, HasShortName b,
 NamedIdea n, NamedIdea n, HasUID b, HasUID b) =>
(n, b) -> (n, b) -> Sentence
rcSent (n, b)
a (n, b)
b Sentence -> [Sentence] -> [Sentence]
forall a. a -> [a] -> [a]
: [(n, b)] -> [Sentence]
rc ((n, b)
b (n, b) -> [(n, b)] -> [(n, b)]
forall a. a -> [a] -> [a]
: [(n, b)]
as)
    rc [(n, b)]
_        = String -> [Sentence]
forall a. HasCallStack => String -> a
error String
"refineChain helper encountered an unexpected empty list"
    rcSent :: (n, b) -> (n, b) -> Sentence
rcSent (n, b)
a (n, b)
b  = String -> Sentence
S String
"the" Sentence -> Sentence -> Sentence
+:+ b -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef ((n, b) -> b
forall a b. (a, b) -> b
snd (n, b)
a) (n -> Sentence
forall n. NamedIdea n => n -> Sentence
plural (n -> Sentence) -> n -> Sentence
forall a b. (a -> b) -> a -> b
$ (n, b) -> n
forall a b. (a, b) -> a
fst (n, b)
a) Sentence -> Sentence -> Sentence
`S.toThe` b -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef ((n, b) -> b
forall a b. (a, b) -> b
snd (n, b)
b) (n -> Sentence
forall n. NamedIdea n => n -> Sentence
plural ((n, b) -> n
forall a b. (a, b) -> a
fst (n, b)
b))
refineChain [(c, Section)]
_ = String -> Sentence
forall a. HasCallStack => String -> a
error String
"refineChain encountered an unexpected empty list"

-- | Helper functions for making likely change statements. Outputs "The @firstSentence@ may be @someVerb@ @thirdSentence@".
likelyFrame :: Sentence -> Sentence -> Sentence -> Sentence
likelyFrame :: Sentence -> Sentence -> Sentence -> Sentence
likelyFrame Sentence
a Sentence
verb Sentence
x = [Sentence] -> Sentence
foldlSent [String -> Sentence
S String
"The", Sentence
a, String -> Sentence
S String
"may be", Sentence
verb, Sentence
x]

-- | Helper functions for making likely change statements. Uses form @'likelyFrame' parameter1 _ parameter2@.
maybeWOVerb, maybeChanged, maybeExpanded :: Sentence -> Sentence -> Sentence
maybeWOVerb :: Sentence -> Sentence -> Sentence
maybeWOVerb Sentence
a   = Sentence -> Sentence -> Sentence -> Sentence
likelyFrame Sentence
a Sentence
EmptyS
maybeChanged :: Sentence -> Sentence -> Sentence
maybeChanged Sentence
a  = Sentence -> Sentence -> Sentence -> Sentence
likelyFrame Sentence
a (String -> Sentence
S String
"changed")
maybeExpanded :: Sentence -> Sentence -> Sentence
maybeExpanded Sentence
a = Sentence -> Sentence -> Sentence -> Sentence
likelyFrame Sentence
a (String -> Sentence
S String
"expanded")

-- | Helpful combinators for making 'Sentence's into Terminologies with Definitions.
-- Returns of the form: "@term (abbreviation) - termDefinition@".
tAndDWAcc :: Concept s => s -> ItemType
tAndDWAcc :: forall s. Concept s => s -> ItemType
tAndDWAcc s
temp = Sentence -> ItemType
Flat (Sentence -> ItemType) -> Sentence -> ItemType
forall a b. (a -> b) -> a -> b
$ s -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart s
temp Sentence -> Sentence -> Sentence
+:+. (Sentence -> Sentence
sParen (s -> Sentence
forall c. Idea c => c -> Sentence
short s
temp) Sentence -> Sentence -> Sentence
`sDash` Sentence -> Sentence
capSent (s
temp s -> Getting Sentence s Sentence -> Sentence
forall s a. s -> Getting a s a -> a
^. Getting Sentence s Sentence
forall c. Definition c => Lens' c Sentence
Lens' s Sentence
defn))

-- | Helpful combinators for making 'Sentence's into Terminologies with Definitions.
-- Returns of the form: "@term (symbol) - termDefinition@".
tAndDWSym :: (Concept s, Quantity a) => s -> a -> ItemType
tAndDWSym :: forall s a. (Concept s, Quantity a) => s -> a -> ItemType
tAndDWSym s
tD a
sym = Sentence -> ItemType
Flat (Sentence -> ItemType) -> Sentence -> ItemType
forall a b. (a -> b) -> a -> b
$ s -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart s
tD Sentence -> Sentence -> Sentence
+:+. (Sentence -> Sentence
sParen (a -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch a
sym) Sentence -> Sentence -> Sentence
`sDash` Sentence -> Sentence
capSent (s
tD s -> Getting Sentence s Sentence -> Sentence
forall s a. s -> Getting a s a -> a
^. Getting Sentence s Sentence
forall c. Definition c => Lens' c Sentence
Lens' s Sentence
defn))

-- | Helpful combinators for making 'Sentence's into Terminologies with Definitions.
-- Returns of the form: "@term - termDefinition@".
tAndDOnly :: Concept s => s -> ItemType
tAndDOnly :: forall s. Concept s => s -> ItemType
tAndDOnly s
chunk  = Sentence -> ItemType
Flat (Sentence -> ItemType) -> Sentence -> ItemType
forall a b. (a -> b) -> a -> b
$ s -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart s
chunk Sentence -> Sentence -> Sentence
`sDash` Sentence
EmptyS Sentence -> Sentence -> Sentence
+:+. Sentence -> Sentence
capSent (s
chunk s -> Getting Sentence s Sentence -> Sentence
forall s a. s -> Getting a s a -> a
^. Getting Sentence s Sentence
forall c. Definition c => Lens' c Sentence
Lens' s Sentence
defn)

-- | Appends "following @reference@" to the end of a 'Sentence'.
follows :: (Referable r, HasShortName r) => Sentence -> r -> Sentence
Sentence
preceding follows :: forall r.
(Referable r, HasShortName r) =>
Sentence -> r -> Sentence
`follows` r
r = Sentence
preceding Sentence -> Sentence -> Sentence
+:+ String -> Sentence
S String
"following" Sentence -> Sentence -> Sentence
+:+ r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
r

-- | Wraps "from @reference@" in parentheses.
fromSource :: (Referable r, HasShortName r) => r -> Sentence
fromSource :: forall r. (Referable r, HasShortName r) => r -> Sentence
fromSource r
r = Sentence -> Sentence
sParen (String -> Sentence
S String
"from" Sentence -> Sentence -> Sentence
+:+ r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
r)

-- | Similar to `fromSource` but takes a list of references instead of one.
fromSources :: (Referable r, HasShortName r) => [r] -> Sentence
fromSources :: forall r. (Referable r, HasShortName r) => [r] -> Sentence
fromSources [r]
rs = Sentence -> Sentence
sParen (String -> Sentence
S String
"from" Sentence -> Sentence -> Sentence
+:+ SepType -> FoldType -> [Sentence] -> Sentence
foldlList SepType
Comma FoldType
List ((r -> Sentence) -> [r] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS [r]
rs))

-- | Used when you want to say a term followed by its symbol. ex. "...using the Force F in...".
getTandS :: (Quantity a) => a -> Sentence
getTandS :: forall a. Quantity a => a -> Sentence
getTandS a
a = a -> Sentence
forall n. NamedIdea n => n -> Sentence
phrase a
a Sentence -> Sentence -> Sentence
+:+ a -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch a
a

-- | Output is of the form "@reference - sentence@".
chgsStart :: (HasShortName x, Referable x) => x -> Sentence -> Sentence
chgsStart :: forall x.
(HasShortName x, Referable x) =>
x -> Sentence -> Sentence
chgsStart = Sentence -> Sentence -> Sentence
sDash (Sentence -> Sentence -> Sentence)
-> (x -> Sentence) -> x -> Sentence -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. x -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS

-- | Uses an 'Either' type to check if a 'String' is valid - 
-- 'Left' with error message if there is an invalid 'Char' in 'String', else 'Right' with 'String'.
checkValidStr :: String -> String -> Either String String
checkValidStr :: String -> String -> Either String String
checkValidStr String
s [] = String -> Either String String
forall a b. b -> Either a b
Right String
s
checkValidStr String
s (Char
x:String
xs)
  | Char
x Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s = String -> Either String String
forall a b. a -> Either a b
Left (String -> Either String String) -> String -> Either String String
forall a b. (a -> b) -> a -> b
$ String
"Invalid character: \'" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
x] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\' in string \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
'\"']
  | Bool
otherwise  = String -> String -> Either String String
checkValidStr String
s String
xs

-- | Apply a binary function to the terms of two named ideas, instead of to the named
-- ideas themselves. Ex. @fterms compoundPhrase t1 t2@ instead of
-- @compoundPhrase (t1 ^. term) (t2 ^. term)@.
fterms :: (NamedIdea c, NamedIdea d) => (NP -> NP -> t) -> c -> d -> t
fterms :: forall c d t.
(NamedIdea c, NamedIdea d) =>
(NP -> NP -> t) -> c -> d -> t
fterms NP -> NP -> t
f c
a d
b = NP -> NP -> t
f (c
a 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
b 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)