{-# 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 Control.Lens ((^.))
import Data.Decimal (DecimalRaw, realFracToDecimal)
import Data.Function (on)
import Data.List (sortBy, transpose)

import Drasil.Database (HasUID)

import Language.Drasil.Chunk.Concept.Core (ConceptChunk)
import Language.Drasil.Chunk.DefinedQuantity (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.Label.Type

-- | 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 -> DefinedQuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
x r
-> Getting DefinedQuantityDict r DefinedQuantityDict
-> DefinedQuantityDict
forall s a. s -> Getting a s a -> a
^. Getting DefinedQuantityDict r DefinedQuantityDict
forall d. DefinesQuantity d => Getter d DefinedQuantityDict
Getter r DefinedQuantityDict
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 = DefinedQuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q r
-> Getting DefinedQuantityDict r DefinedQuantityDict
-> DefinedQuantityDict
forall s a. s -> Getting a s a -> a
^. Getting DefinedQuantityDict r DefinedQuantityDict
forall d. DefinesQuantity d => Getter d DefinedQuantityDict
Getter r DefinedQuantityDict
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 = DefinedQuantityDict -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q r
-> Getting DefinedQuantityDict r DefinedQuantityDict
-> DefinedQuantityDict
forall s a. s -> Getting a s a -> a
^. Getting DefinedQuantityDict r DefinedQuantityDict
forall d. DefinesQuantity d => Getter d DefinedQuantityDict
Getter r DefinedQuantityDict
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)