{-# 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, displayStrConstrntsAsSet, displayDblConstrntsAsSet,
  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.Expr.Class ( ExprC(sy) )
import Language.Drasil.ModelExpr.Class ( ModelExprC(isIn) )
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.Space ( Space(DiscreteD, DiscreteS) )
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 = forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy 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 = forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a. HasSymbol a => a -> a -> Ordering
compareBySymbol forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` 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 (forall q. HasSymbol q => q -> Symbol
eqSymb a
a) (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 forall a b. (a -> b) -> a -> b
$ 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 (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
+:+ 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
+: 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 = forall a b. (a -> b) -> [a] -> [b]
map (\r
x -> forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
x forall s a. s -> Getting a s a -> a
^. forall d. DefinesQuantity d => Getter d QuantityDict
defLhs) Sentence -> Sentence -> 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 = forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q forall s a. s -> Getting a s a -> a
^. forall d. DefinesQuantity d => Getter d QuantityDict
defLhs) Sentence -> Sentence -> Sentence
`S.is` String -> Sentence
S String
"defined in" Sentence -> Sentence -> 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 = forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (r
q forall s a. s -> Getting a s a -> a
^. forall d. DefinesQuantity d => Getter d QuantityDict
defLhs) Sentence -> Sentence -> Sentence
`S.is` String -> Sentence
S String
"defined" Sentence -> Sentence -> Sentence
`S.in_` 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_` 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 = 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
+:+ 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 = forall a b. [a] -> [b] -> [(a, b)]
zip [Sentence
t Sentence -> Sentence -> Sentence
:+: String -> Sentence
S (forall a. Show a => a -> String
show Integer
x) | Integer
x <- [Integer
s..]] forall a b. (a -> b) -> a -> b
$ 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 (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 = forall {r} {a}.
(Show r, RealFrac r, Integral a) =>
r -> Maybe a -> Sentence
found (forall x. HasUncertainty x => x -> Double
uncVal c
x) (forall x. HasUncertainty x => x -> Maybe Int
uncPrec c
x)
  where
    found :: r -> Maybe a -> Sentence
found r
u Maybe a
Nothing  = forall a. Show a => a -> Sentence
addPercent forall a b. (a -> b) -> a -> b
$ r
u forall a. Num a => a -> a -> a
* r
100
    found r
u (Just a
p) = forall a. Show a => a -> Sentence
addPercent (forall i r. (Integral i, RealFrac r) => Word8 -> r -> DecimalRaw i
realFracToDecimal (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
p) (r
u 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 (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 forall a. [a] -> [a] -> [a]
++ 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 forall a. [a] -> [a] -> [a]
++ [Sentence
xforall 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 [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 = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\a
x -> if a
x 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' = forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Sentence -> Bool
isEmpty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) [(Sentence, [Sentence])]
l in 
  (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(Sentence, [Sentence])]
l', forall a. [[a]] -> [[a]]
transpose forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a -> b) -> [a] -> [b]
map Sentence -> Sentence
replaceEmptyS forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l) forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ItemType] -> [(ItemType, Maybe String)]
noRefs forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Sentence
h ListType
c -> (Sentence -> ListType -> ItemType
Nested Sentence
h ListType
c, 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 forall a b. (a -> b) -> a -> b
$ 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 = forall a b. (a -> b) -> [a] -> [b]
map (, 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 = 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
+:+ forall n. NamedIdea n => n -> Sentence
phrase ConceptChunk
chunk Sentence -> Sentence -> Sentence
+:+ 
  String -> Sentence
S String
"under consideration is" Sentence -> Sentence -> Sentence
+:+. (ConceptChunk
chunk forall s a. s -> Getting a s a -> a
^. forall c. Definition c => Lens' c 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
+:+ forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (forall a b. (a, b) -> b
snd (c, Section)
x) (forall n. NamedIdea n => n -> Sentence
plural forall a b. (a -> b) -> a -> b
$ 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` forall n. NamedIdea n => n -> Sentence
plural (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 (forall c. NamedIdea c => [(c, Section)] -> Sentence
refineChain [(c, Section)
x,(c, Section)
y] forall a. a -> [a] -> [a]
: forall {b} {n}.
(HasRefAddress b, HasShortName b, NamedIdea n, HasUID b) =>
[(n, b)] -> [Sentence]
rc ((c, Section)
y forall a. a -> [a] -> [a]
: [(c, Section)]
xs)) !.)
  where
    rc :: [(n, b)] -> [Sentence]
rc [(n, b)
a, (n, b)
b]   = [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) =  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 forall a. a -> [a] -> [a]
: [(n, b)] -> [Sentence]
rc ((n, b)
b forall a. a -> [a] -> [a]
: [(n, b)]
as)
    rc [(n, b)]
_        = 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
+:+ forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (forall a b. (a, b) -> b
snd (n, b)
a) (forall n. NamedIdea n => n -> Sentence
plural forall a b. (a -> b) -> a -> b
$ forall a b. (a, b) -> a
fst (n, b)
a) Sentence -> Sentence -> Sentence
`S.toThe` forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (forall a b. (a, b) -> b
snd (n, b)
b) (forall n. NamedIdea n => n -> Sentence
plural (forall a b. (a, b) -> a
fst (n, b)
b))
refineChain [(c, Section)]
_ = 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 forall a b. (a -> b) -> a -> b
$ forall n. NamedIdea n => n -> Sentence
atStart s
temp Sentence -> Sentence -> Sentence
+:+. (Sentence -> Sentence
sParen (forall c. Idea c => c -> Sentence
short s
temp) Sentence -> Sentence -> Sentence
`sDash` Sentence -> Sentence
capSent (s
temp forall s a. s -> Getting a s a -> a
^. forall c. Definition c => Lens' c 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 forall a b. (a -> b) -> a -> b
$ forall n. NamedIdea n => n -> Sentence
atStart s
tD Sentence -> Sentence -> Sentence
+:+. (Sentence -> Sentence
sParen (forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch a
sym) Sentence -> Sentence -> Sentence
`sDash` Sentence -> Sentence
capSent (s
tD forall s a. s -> Getting a s a -> a
^. forall c. Definition c => Lens' c 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 forall a b. (a -> b) -> a -> b
$ forall n. NamedIdea n => n -> Sentence
atStart s
chunk Sentence -> Sentence -> Sentence
`sDash` Sentence
EmptyS Sentence -> Sentence -> Sentence
+:+. Sentence -> Sentence
capSent (s
chunk forall s a. s -> Getting a s a -> a
^. forall c. Definition c => Lens' c 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
+:+ 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
+:+ 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 (forall a b. (a -> b) -> [a] -> [b]
map 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 = forall n. NamedIdea n => n -> Sentence
phrase a
a Sentence -> Sentence -> Sentence
+:+ forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch a
a

-- | Produces a 'Sentence' that displays the constraints in a set {}.
displayStrConstrntsAsSet :: Quantity a => a -> [String] -> Sentence
displayStrConstrntsAsSet :: forall a. Quantity a => a -> [String] -> Sentence
displayStrConstrntsAsSet a
sym [String]
listOfVals = ModelExpr -> Sentence
eS forall a b. (a -> b) -> a -> b
$ forall r. ModelExprC r => r -> Space -> r
isIn (forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy a
sym) ([String] -> Space
DiscreteS [String]
listOfVals)

-- | Produces a 'Sentence' that displays the constraints in a set {}.
displayDblConstrntsAsSet :: Quantity a => a -> [Double] -> Sentence
displayDblConstrntsAsSet :: forall a. Quantity a => a -> [Double] -> Sentence
displayDblConstrntsAsSet a
sym [Double]
listOfVals = ModelExpr -> Sentence
eS forall a b. (a -> b) -> a -> b
$ forall r. ModelExprC r => r -> Space -> r
isIn (forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy a
sym) ([Double] -> Space
DiscreteD [Double]
listOfVals)

-- | 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 [] = forall a b. b -> Either a b
Right String
s
checkValidStr String
s (Char
x:String
xs)
  | Char
x forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s = forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Invalid character: \'" forall a. [a] -> [a] -> [a]
++ [Char
x] forall a. [a] -> [a] -> [a]
++ String
"\' in string \"" forall a. [a] -> [a] -> [a]
++ String
s 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 forall s a. s -> Getting a s a -> a
^. forall c. NamedIdea c => Lens' c NP
term) (d
b forall s a. s -> Getting a s a -> a
^. forall c. NamedIdea c => Lens' c NP
term)