module Language.Drasil.NounPhrase (
  -- * Types
  NounPhrase(..), NP,
  -- * Phrase Accessors
  atStartNP, atStartNP', titleizeNP, titleizeNP',
  -- * Constructors
  -- ** Common Noun Constructors
  cn, cn', cn'', cn''', cnICES, cnIES, cnIP, cnIS, cnIrr, cnUM,
  -- ** Proper Noun Constructors
  pn, pn', pn'', pn''', pnIrr,
  -- ** Noun Phrase Constructors
  nounPhrase, nounPhrase', nounPhrase'', nounPhraseSP, nounPhraseSent,
  -- * Combinators
  compoundPhrase,
  compoundPhrase', compoundPhrase'', compoundPhrase''', compoundPhraseP1,
  -- * Re-exported Types
  CapitalizationRule(..), PluralRule(..)
  ) where

import Data.Char (isLatin1, isLetter, toLower, toUpper)

import Language.Drasil.NounPhrase.Core -- uses whole module
import Language.Drasil.Sentence (Sentence((:+:), S, Ch, P), (+:+), TermCapitalization(..))

--Linguistically, nounphrase might not be the best name (yet!), but once
-- it is fleshed out and/or we do more with it, it will likely be a good fit

class NounPhrase n where
  -- | Retrieves singular form of term. Ex. "the quick brown fox".
  phraseNP :: n -> Sentence 
  -- | Retrieves plural form of term. Ex. "the quick brown foxes".
  pluralNP :: n -> PluralForm
    --Could replace plural string with a function.
  -- | Retrieves the singular form and applies a captalization 
  -- rule (usually capitalizes the first word) to produce a 'Sentence'.
  -- Ex. "The quick brown fox".
  sentenceCase :: n -> (NP -> Sentence) -> Capitalization 
    --Should this be replaced with a data type instead?
    --Data types should use functions to determine capitalization based
    -- on rules.
  -- | Retrieves the singular form and applies a captalization 
  -- rule (usually capitalizes all words) to produce a 'Sentence'.
  -- Ex. "The Quick Brown Fox".
  titleCase :: n -> (NP -> Sentence) -> Capitalization 

-- | Type synonym for 'Sentence'.
type Capitalization = Sentence
-- | Type synonym for 'String'.
type PluralString   = String

-- | Defines NP as a NounPhrase. 
-- Default capitalization rules for proper and common nouns
-- are 'CapFirst' for sentence case and 'CapWords' for title case.
-- Also accepts a 'Phrase' where the capitalization case may be specified.
instance NounPhrase NP where
  phraseNP :: NP -> PluralForm
phraseNP (ProperNoun String
n PluralRule
_)           = String -> PluralForm
S String
n
  phraseNP (CommonNoun String
n PluralRule
_ CapitalizationRule
_)         = String -> PluralForm
S String
n
  phraseNP (Phrase PluralForm
n PluralForm
_ CapitalizationRule
_ CapitalizationRule
_)           = PluralForm
n
  pluralNP :: NP -> PluralForm
pluralNP n :: NP
n@(ProperNoun String
_ PluralRule
p)         = PluralForm -> PluralRule -> PluralForm
sPlur (NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
n) PluralRule
p
  pluralNP n :: NP
n@(CommonNoun String
_ PluralRule
p CapitalizationRule
_)       = PluralForm -> PluralRule -> PluralForm
sPlur (NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
n) PluralRule
p
  pluralNP (Phrase PluralForm
_ PluralForm
p CapitalizationRule
_ CapitalizationRule
_)           = PluralForm
p
  sentenceCase :: NP -> (NP -> PluralForm) -> PluralForm
sentenceCase n :: NP
n@ProperNoun {}      NP -> PluralForm
_ = NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
n
  sentenceCase n :: NP
n@(CommonNoun String
_ PluralRule
_ CapitalizationRule
r) NP -> PluralForm
f = PluralForm -> CapitalizationRule -> PluralForm
cap (NP -> PluralForm
f NP
n) CapitalizationRule
r
  sentenceCase n :: NP
n@(Phrase PluralForm
_ PluralForm
_ CapitalizationRule
r CapitalizationRule
_)   NP -> PluralForm
f = PluralForm -> CapitalizationRule -> PluralForm
cap (NP -> PluralForm
f NP
n) CapitalizationRule
r
  titleCase :: NP -> (NP -> PluralForm) -> PluralForm
titleCase n :: NP
n@ProperNoun {}         NP -> PluralForm
_ = NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
n
  titleCase n :: NP
n@CommonNoun {}         NP -> PluralForm
f = PluralForm -> CapitalizationRule -> PluralForm
cap (NP -> PluralForm
f NP
n) CapitalizationRule
CapWords
  titleCase n :: NP
n@(Phrase PluralForm
_ PluralForm
_ CapitalizationRule
_ CapitalizationRule
r)      NP -> PluralForm
f = PluralForm -> CapitalizationRule -> PluralForm
cap (NP -> PluralForm
f NP
n) CapitalizationRule
r
  
-- ===Constructors=== --
-- | Constructs a Proper Noun, it is always capitalized as written.
pn, pn', pn'', pn''' :: String -> NP
-- | Self plural.
pn :: String -> NP
pn    String
n = String -> PluralRule -> NP
ProperNoun String
n PluralRule
SelfPlur
-- | Plural form simply adds "s" (ex. Henderson -> Hendersons).
pn' :: String -> NP
pn'   String
n = String -> PluralRule -> NP
ProperNoun String
n PluralRule
AddS
-- | Plural form adds "e".
pn'' :: String -> NP
pn''  String
n = String -> PluralRule -> NP
ProperNoun String
n PluralRule
AddE
-- | Plural form adds "es" (ex. Bush -> Bushes).
pn''' :: String -> NP
pn''' String
n = String -> PluralRule -> NP
ProperNoun String
n PluralRule
AddES

-- | Constructs a 'ProperNoun' with a custom plural rule (using 'IrregPlur' from 'PluralRule').
-- First argument is the String representing the noun, second is the rule.
pnIrr :: String -> PluralRule -> NP
pnIrr :: String -> PluralRule -> NP
pnIrr = String -> PluralRule -> NP
ProperNoun

-- | Constructs a common noun which capitalizes the first letter of the first word
-- at the beginning of a sentence.
cn, cn', cn'', cn''' :: String -> NP
-- | Self plural.
cn :: String -> NP
cn    String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n PluralRule
SelfPlur CapitalizationRule
CapFirst
-- | Plural form simply adds "s" (ex. dog -> dogs).
cn' :: String -> NP
cn'   String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n PluralRule
AddS CapitalizationRule
CapFirst
-- | Plural form adds "e" (ex. formula -> formulae).
cn'' :: String -> NP
cn''  String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n PluralRule
AddE CapitalizationRule
CapFirst
-- | Plural form adds "es" (ex. bush -> bushes).
cn''' :: String -> NP
cn''' String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n PluralRule
AddES CapitalizationRule
CapFirst

-- | Constructs a common noun that pluralizes by dropping the last letter and adding an "ies"
-- ending (ex. body -> bodies).
cnIES :: String -> NP
cnIES :: String -> NP
cnIES String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n ((String -> String) -> PluralRule
IrregPlur (\String
x -> String -> String
forall a. HasCallStack => [a] -> [a]
init String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"ies")) CapitalizationRule
CapFirst

--FIXME: Shouldn't this just be drop one and add "ces"?
-- | Construct a common noun that pluralizes by dropping the last two letters and adding an 
-- "ices" ending (ex. matrix -> matrices).
cnICES :: String -> NP
cnICES :: String -> NP
cnICES String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n ((String -> String) -> PluralRule
IrregPlur (\String
x -> String -> String
forall a. HasCallStack => [a] -> [a]
init (String -> String
forall a. HasCallStack => [a] -> [a]
init String
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"ices")) CapitalizationRule
CapFirst

-- | Constructs a common noun that pluralizes by dropping the last two letters and adding
-- "es" (ex. analysis -> analyses).
cnIS :: String -> NP
cnIS :: String -> NP
cnIS String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n ((String -> String) -> PluralRule
IrregPlur (\String
x -> String -> String
forall a. HasCallStack => [a] -> [a]
init (String -> String
forall a. HasCallStack => [a] -> [a]
init String
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"es")) CapitalizationRule
CapFirst

-- | Constructs a common noun that pluralizes by dropping the last two letters and adding "a"
-- (ex. datum -> data).
cnUM :: String -> NP
cnUM :: String -> NP
cnUM String
n = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n ((String -> String) -> PluralRule
IrregPlur (\String
x -> String -> String
forall a. HasCallStack => [a] -> [a]
init (String -> String
forall a. HasCallStack => [a] -> [a]
init String
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"a")) CapitalizationRule
CapFirst

-- | Constructs a common noun that allows you to specify the pluralization rule 
-- (as in 'pnIrr').
cnIP :: String -> PluralRule -> NP
cnIP :: String -> PluralRule -> NP
cnIP String
n PluralRule
p = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun String
n PluralRule
p CapitalizationRule
CapFirst

-- | Common noun that allows you to specify both the pluralization rule and the
-- capitalization rule for sentence case (if the noun is used at the beginning
-- of a sentence).
cnIrr :: String -> PluralRule -> CapitalizationRule -> NP
cnIrr :: String -> PluralRule -> CapitalizationRule -> NP
cnIrr = String -> PluralRule -> CapitalizationRule -> NP
CommonNoun 

-- | Creates a 'NP' with a given singular and plural form (as 'String's) that capitalizes the first
-- letter of the first word for sentence case.
nounPhrase :: String -> PluralString -> NP
nounPhrase :: String -> String -> NP
nounPhrase String
s String
p = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase (String -> PluralForm
S String
s) (String -> PluralForm
S String
p) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Similar to 'nounPhrase', but takes a specified capitalization rule for the sentence case.
nounPhrase' :: String -> PluralString -> CapitalizationRule -> NP
nounPhrase' :: String -> String -> CapitalizationRule -> NP
nounPhrase' String
s String
p CapitalizationRule
c = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase (String -> PluralForm
S String
s) (String -> PluralForm
S String
p) CapitalizationRule
c CapitalizationRule
CapWords

-- | Custom noun phrase constructor that takes a singular form ('Sentence'), plural form ('Sentence'), 
-- sentence case capitalization rule, and title case capitalization rule.
nounPhrase'' :: Sentence -> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' :: PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
nounPhrase'' = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase

-- | For things that should not be pluralized (or are self-plural). Works like 'nounPhrase', but with
-- only the first argument.
nounPhraseSP :: String -> NP
nounPhraseSP :: String -> NP
nounPhraseSP String
s = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase (String -> PluralForm
S String
s) (String -> PluralForm
S String
s) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Similar to nounPhrase, except it only accepts one 'Sentence'. Used for Requirements,
-- Assumptions, LikelyChanges, etc. to allow for referencing.
-- Plural case is just 'AddS'.
nounPhraseSent :: Sentence -> NP
nounPhraseSent :: PluralForm -> NP
nounPhraseSent PluralForm
s = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase PluralForm
s (PluralForm -> PluralRule -> PluralForm
sPlur PluralForm
s PluralRule
AddS) CapitalizationRule
CapFirst CapitalizationRule
CapWords

-- | Combine two noun phrases. The singular form becomes 'phrase' from t1 followed
-- by 'phrase' of t2. The plural becomes 'phrase' of t1 followed by 'plural' of t2.
-- Uses standard 'CapFirst' sentence case and 'CapWords' title case.
-- For example: @compoundPhrase system constraint@ will have singular form
-- "system constraint" and plural "system constraints".
compoundPhrase :: (NounPhrase a, NounPhrase b) => a -> b -> NP
compoundPhrase :: forall a b. (NounPhrase a, NounPhrase b) => a -> b -> NP
compoundPhrase a
t1 b
t2 = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase 
  (a -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP a
t1 PluralForm -> PluralForm -> PluralForm
+:+ b -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP b
t2) (a -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP a
t1 PluralForm -> PluralForm -> PluralForm
+:+ b -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP b
t2) CapitalizationRule
CapFirst CapitalizationRule
CapWords
  
-- | Similar to 'compoundPhrase', but the sentence case is the same
-- as the title case ('CapWords').
compoundPhrase' :: NP -> NP -> NP
compoundPhrase' :: NP -> NP -> NP
compoundPhrase' NP
t1 NP
t2 = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase
  (NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t2) (NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP NP
t2) CapitalizationRule
CapWords CapitalizationRule
CapWords

-- | Similar to 'compoundPhrase'', but accepts two functions that will be used to
-- construct the plural form. For example,
-- @compoundPhrase'' plural phrase system constraint@ would have the plural
-- form "systems constraint". 
compoundPhrase'' :: (NP -> Sentence) -> (NP -> Sentence) -> NP -> NP -> NP
compoundPhrase'' :: (NP -> PluralForm) -> (NP -> PluralForm) -> NP -> NP -> NP
compoundPhrase'' NP -> PluralForm
f1 NP -> PluralForm
f2 NP
t1 NP
t2 = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase
  (NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t2) (NP -> PluralForm
f1 NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
f2 NP
t2) CapitalizationRule
CapWords CapitalizationRule
CapWords

--More primes might not be wanted but fixes two issues
-- pluralization problem with software requirements specification (Documentation.hs)
-- SWHS program not being about to use a compound to create the IdeaDict
-- | Similar to 'compoundPhrase', but used when you need a special function applied 
-- to the first term of both singular and pluralcases (eg. short or plural).
compoundPhrase''' :: (NP -> Sentence) -> NP -> NP -> NP
compoundPhrase''' :: (NP -> PluralForm) -> NP -> NP -> NP
compoundPhrase''' NP -> PluralForm
f1 NP
t1 NP
t2 = PluralForm
-> PluralForm -> CapitalizationRule -> CapitalizationRule -> NP
Phrase 
  (NP -> PluralForm
f1 NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP NP
t2) (NP -> PluralForm
f1 NP
t1 PluralForm -> PluralForm -> PluralForm
+:+ NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP NP
t2) CapitalizationRule
CapFirst CapitalizationRule
CapWords

--For Data.Drasil.Documentation
-- | Similar to 'compoundPhrase', but pluralizes the first 'NP' for both singular and plural cases.
compoundPhraseP1 :: NP -> NP -> NP
compoundPhraseP1 :: NP -> NP -> NP
compoundPhraseP1 = (NP -> PluralForm) -> NP -> NP -> NP
compoundPhrase''' NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP

-- === Helpers === 
-- | Helper function for getting the sentence case of a noun phrase.
atStartNP, atStartNP' :: NounPhrase n => n -> Capitalization
-- | Singular sentence case.
atStartNP :: forall n. NounPhrase n => n -> PluralForm
atStartNP  n
n = n -> (NP -> PluralForm) -> PluralForm
forall n. NounPhrase n => n -> (NP -> PluralForm) -> PluralForm
sentenceCase n
n NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP
-- | Plural sentence case.
atStartNP' :: forall n. NounPhrase n => n -> PluralForm
atStartNP' n
n = n -> (NP -> PluralForm) -> PluralForm
forall n. NounPhrase n => n -> (NP -> PluralForm) -> PluralForm
sentenceCase n
n NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP

-- | Helper function for getting the title case of a noun phrase.
titleizeNP, titleizeNP' :: NounPhrase n => n -> Capitalization
-- | Singular title case.
titleizeNP :: forall n. NounPhrase n => n -> PluralForm
titleizeNP  n
n = n -> (NP -> PluralForm) -> PluralForm
forall n. NounPhrase n => n -> (NP -> PluralForm) -> PluralForm
titleCase n
n NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
phraseNP
-- | Plural title case.
titleizeNP' :: forall n. NounPhrase n => n -> PluralForm
titleizeNP' n
n = n -> (NP -> PluralForm) -> PluralForm
forall n. NounPhrase n => n -> (NP -> PluralForm) -> PluralForm
titleCase n
n NP -> PluralForm
forall n. NounPhrase n => n -> PluralForm
pluralNP

-- DO NOT EXPORT --                
-- | Pluralization helper function.
sPlur :: Sentence -> PluralRule -> Sentence
sPlur :: PluralForm -> PluralRule -> PluralForm
sPlur (S String
s) PluralRule
AddS = String -> PluralForm
S (String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"s")
sPlur (S String
s) PluralRule
AddE = String -> PluralForm
S (String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"e")
sPlur s :: PluralForm
s@(S String
_) PluralRule
AddES = PluralForm -> PluralRule -> PluralForm
sPlur (PluralForm -> PluralRule -> PluralForm
sPlur PluralForm
s PluralRule
AddE) PluralRule
AddS
sPlur s :: PluralForm
s@(S String
_) PluralRule
SelfPlur = PluralForm
s
sPlur (S String
sts) (IrregPlur String -> String
f) = String -> PluralForm
S (String -> PluralForm) -> String -> PluralForm
forall a b. (a -> b) -> a -> b
$ String -> String
f String
sts --Custom pluralization
sPlur (PluralForm
a :+: PluralForm
b) PluralRule
pt = PluralForm
a PluralForm -> PluralForm -> PluralForm
:+: PluralForm -> PluralRule -> PluralForm
sPlur PluralForm
b PluralRule
pt
sPlur PluralForm
a PluralRule
_ = String -> PluralForm
S String
"MISSING PLURAL FOR:" PluralForm -> PluralForm -> PluralForm
+:+ PluralForm
a

-- | Capitalization helper function given a sentence.
cap :: Sentence -> CapitalizationRule -> Sentence
cap :: PluralForm -> CapitalizationRule -> PluralForm
cap PluralForm
_ (Replace PluralForm
s) = PluralForm
s
cap (S (Char
s:String
ss)) CapitalizationRule
CapFirst = String -> PluralForm
S (Char -> Char
toUpper Char
s Char -> String -> String
forall a. a -> [a] -> [a]
: String
ss)
cap (S String
s)      CapitalizationRule
CapWords = String -> (String -> String) -> (String -> String) -> PluralForm
capString String
s String -> String
capFirstWord String -> String
capWords
cap (P Symbol
symb :+: PluralForm
x) CapitalizationRule
CapFirst = Symbol -> PluralForm
P Symbol
symb PluralForm -> PluralForm -> PluralForm
:+: PluralForm
x -- TODO: See why the Table of Symbols uses the CapWords case instead of CapFirst for items of the form:
cap (P Symbol
symb :+: PluralForm
x) CapitalizationRule
CapWords = Symbol -> PluralForm
P Symbol
symb PluralForm -> PluralForm -> PluralForm
:+: PluralForm
x -- "x-component". Instead, it displays as "x-Component". Using a temp fix for now by ignoring everything after a P symbol.
cap (Ch SentenceStyle
style TermCapitalization
_ UID
s) CapitalizationRule
CapFirst = SentenceStyle -> TermCapitalization -> UID -> PluralForm
Ch SentenceStyle
style TermCapitalization
CapF UID
s
cap (Ch SentenceStyle
style TermCapitalization
_ UID
s) CapitalizationRule
CapWords = SentenceStyle -> TermCapitalization -> UID -> PluralForm
Ch SentenceStyle
style TermCapitalization
CapW UID
s
cap (S String
s1 :+: S String
s2 :+: PluralForm
x) CapitalizationRule
r = PluralForm -> CapitalizationRule -> PluralForm
cap (String -> PluralForm
S (String
s1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s2) PluralForm -> PluralForm -> PluralForm
:+: PluralForm
x) CapitalizationRule
r
cap (PluralForm
s1 :+: PluralForm
s2) CapitalizationRule
CapWords = PluralForm -> CapitalizationRule -> PluralForm
cap PluralForm
s1 CapitalizationRule
CapWords PluralForm -> PluralForm -> PluralForm
+:+ PluralForm -> PluralForm
capTail PluralForm
s2 --FIXME: why does this use +:+ instead of :+:? Could unwords be a problem?
cap (PluralForm
s1 :+: PluralForm
s2) CapitalizationRule
CapFirst = PluralForm -> CapitalizationRule -> PluralForm
cap PluralForm
s1 CapitalizationRule
CapFirst PluralForm -> PluralForm -> PluralForm
:+: PluralForm
s2
cap PluralForm
a CapitalizationRule
_ = PluralForm
a

-- | Helper for 'cap' and for capitalizing the end of a 'Sentence' (assumes 'CapWords').
capTail :: Sentence -> Sentence
capTail :: PluralForm -> PluralForm
capTail (S String
s) = String -> (String -> String) -> (String -> String) -> PluralForm
capString String
s String -> String
capWords String -> String
capWords
capTail (Ch SentenceStyle
style TermCapitalization
_ UID
s) = SentenceStyle -> TermCapitalization -> UID -> PluralForm
Ch SentenceStyle
style TermCapitalization
CapW UID
s
capTail (PluralForm
a :+: PluralForm
b) = PluralForm -> PluralForm
capTail PluralForm
a PluralForm -> PluralForm -> PluralForm
:+: PluralForm -> PluralForm
capTail PluralForm
b
capTail PluralForm
x = PluralForm
x

-- | Helper for capitalizing a string.
capString :: String -> (String -> String) -> (String -> String) -> Sentence 
capString :: String -> (String -> String) -> (String -> String) -> PluralForm
capString String
s String -> String
f String -> String
g = String -> PluralForm
S (String -> PluralForm)
-> ([String] -> String) -> [String] -> PluralForm
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> String -> String
findHyph String -> String
g (String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unwords ([String] -> PluralForm) -> [String] -> PluralForm
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
process (String -> [String]
words String
s)
  where
    process :: [String] -> [String]
process (String
x:[String]
xs) = String -> String
f String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
g [String]
xs
    process []     = []

-- | Finds hyphens in a 'String' and applies capitalization to words after a hyphen.
findHyph :: (String -> String) -> String -> String
findHyph :: (String -> String) -> String -> String
findHyph String -> String
_ String
"" = String
""
findHyph String -> String
_ [Char
x] = [Char
x]
findHyph String -> String
f (Char
x:String
xs)
  | Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'-'  = Char
'-' Char -> String -> String
forall a. a -> [a] -> [a]
: (String -> String) -> String -> String
findHyph String -> String
f (String -> String
f String
xs)
  | Bool
otherwise = Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: (String -> String) -> String -> String
findHyph String -> String
f String
xs

-- | Capitalize first word of a 'String'. Does not ignore prepositions, articles, or conjunctions (intended for beginning of a phrase/sentence).
capFirstWord :: String -> String
capFirstWord :: String -> String
capFirstWord String
"" = String
""
capFirstWord w :: String
w@(Char
c:String
cs)
  | Bool -> Bool
not (Char -> Bool
isLetter Char
c) = String
w
  | Bool -> Bool
not (Char -> Bool
isLatin1 Char
c) = String
w
  | Bool
otherwise        = Char -> Char
toUpper Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
cs

-- | Capitalize all words of a 'String' (unless they are prepositions, articles, or conjunctions).
capWords :: String -> String
capWords :: String -> String
capWords String
"" = String
""
capWords w :: String
w@(Char
c:String
cs)
  | Bool -> Bool
not (Char -> Bool
isLetter Char
c)   = String
w
  | Bool -> Bool
not (Char -> Bool
isLatin1 Char
c)   = String
w
  | String
w String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
doNotCaps = Char -> Char
toLower Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
cs
  | Bool
otherwise          = Char -> Char
toUpper Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
cs

-- | Words that should not be capitalized in a title (prepositions, articles, or conjunctions).
doNotCaps :: [String]
doNotCaps :: [String]
doNotCaps = [String
"a", String
"an", String
"the", String
"at", String
"by", String
"for", String
"in", String
"of",
  String
"on", String
"to", String
"up", String
"and", String
"as", String
"but", String
"or", String
"nor"] --Ref http://grammar.yourdictionary.com