summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorleftaroundabout <>2019-07-11 22:01:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2019-07-11 22:01:00 (GMT)
commit3cfaac3ab574b234e6d8f0d466c4b9ef8b4a5397 (patch)
tree9c6ef1789916ab3febe314aa15869eb2f8e0bce0
parent822eb8a35e69b60d88de3868a169cb27b1b86446 (diff)
version 0.201.2.0HEAD0.201.2.0master
-rw-r--r--CAS/Dumb/LaTeX/Symbols.hs221
-rw-r--r--Math/LaTeX/Internal/Display.hs71
-rw-r--r--Math/LaTeX/Internal/MathExpr.hs151
-rw-r--r--Math/LaTeX/Prelude.hs93
-rw-r--r--Math/LaTeX/StringLiterals.hs3
-rw-r--r--TeX-my-math.cabal24
-rw-r--r--example/Simple.hs97
-rw-r--r--test/PdfSnippets/MkSnippets.hs56
8 files changed, 611 insertions, 105 deletions
diff --git a/CAS/Dumb/LaTeX/Symbols.hs b/CAS/Dumb/LaTeX/Symbols.hs
index 89bf54a..389dec5 100644
--- a/CAS/Dumb/LaTeX/Symbols.hs
+++ b/CAS/Dumb/LaTeX/Symbols.hs
@@ -14,13 +14,16 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE CPP #-}
-module CAS.Dumb.LaTeX.Symbols () where
+module CAS.Dumb.LaTeX.Symbols ( fixateLaTeXAlgebraEncaps
+ , LaTeXMathEncapsulation(..) ) where
import CAS.Dumb.Tree
-import CAS.Dumb.Symbols
+import CAS.Dumb.Symbols hiding (Negation, Reciprocal)
import Text.LaTeX
import Text.LaTeX.Base.Class
@@ -40,10 +43,158 @@ import qualified Data.HashMap.Strict as Map
import Data.Hashable
import Control.Monad
+import Control.Arrow (second)
import qualified Language.Haskell.TH as Hs
+data LaTeXMathEncapsulation
+ = Negation | Reciprocal | Subscript | Superscript
+ | StdMathsFunc StdMathsFunc
+ deriving (Eq, Show)
+
+data StdMathsFunc
+ = Abs
+ | ConventionalFunction Text
+ deriving (Eq, Show)
+
+type instance SpecialEncapsulation LaTeX = LaTeXMathEncapsulation
+
+instance RenderableEncapsulations LaTeX where
+ fixateAlgebraEncaps = fixateShowAlgebraEncaps
+
+showMagic :: Text -> LaTeX
+showMagic s = raw $ "{"<>s<>"}"
+matchShowMagic :: LaTeX -> Maybe Text
+matchShowMagic e = case render e of
+ s' | "{"`Txt.isPrefixOf`s'
+ , "}"`Txt.isSuffixOf`s' -> Just $ Txt.drop 1
+ $ Txt.dropEnd 1 s'
+ _ -> Nothing
+
+fixateShowAlgebraEncaps :: ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
+ => CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+ -> CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+fixateShowAlgebraEncaps (OperatorChain x
+ ((o,Function (SpecialEncapsulation ι) z):ys))
+ | (Infix (Hs.Fixity 6 Hs.InfixL) addSym', Negation) <- (o,ι)
+ , addSym' == addSym
+ = case fixateShowAlgebraEncaps $ OperatorChain x ys of
+ x' -> Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-") x' z'
+ | (Infix (Hs.Fixity 7 Hs.InfixL) mulSym', Reciprocal) <- (o,ι)
+ , mulSym' == mulSym
+ = case fixateShowAlgebraEncaps $ OperatorChain x ys of
+ x' -> Operator (Infix (Hs.Fixity 7 Hs.InfixL) $ showMagic "/") x' z'
+ where [addSym, mulSym] = fromCharSymbol ([]::[σ]) <$> "+*" :: [LaTeX]
+ z' = fixateShowAlgebraEncaps z
+fixateShowAlgebraEncaps (OperatorChain x []) = fixateShowAlgebraEncaps x
+fixateShowAlgebraEncaps (OperatorChain x ((o@(Infix (Hs.Fixity _ Hs.InfixL) _), z):ys))
+ = Operator o (fixateShowAlgebraEncaps $ OperatorChain x ys) (fixateShowAlgebraEncaps z)
+fixateShowAlgebraEncaps (Operator o x (Function (SpecialEncapsulation ι) y))
+ | (Infix (Hs.Fixity 6 Hs.InfixL) addSym', Negation) <- (o,ι)
+ , addSym' == addSym
+ = Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-") x' y'
+ | (Infix (Hs.Fixity 7 Hs.InfixL) mulSym', Reciprocal) <- (o,ι)
+ , mulSym' == mulSym
+ = Operator (Infix (Hs.Fixity 7 Hs.InfixL) $ showMagic "/") x' y'
+ | (Infix fxty catSym', Superscript) <- (o,ι)
+ , catSym' == mempty
+ = Operator (Infix fxty $ showMagic "◝") x' y'
+ | (Infix fxty catSym', Subscript) <- (o,ι)
+ , catSym' == mempty
+ = Operator (Infix fxty $ showMagic "◞") x' y'
+ where [addSym, mulSym] = fromCharSymbol ([]::[σ]) <$> "+*" :: [LaTeX]
+ [x',y'] = fixateShowAlgebraEncaps<$>[x,y]
+fixateShowAlgebraEncaps (Function (SpecialEncapsulation Negation) e)
+ = Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-")
+ (Symbol $ StringSymbol " ") $ fixateShowAlgebraEncaps e
+fixateShowAlgebraEncaps (Function (SpecialEncapsulation Reciprocal) e)
+ = Operator (Infix (Hs.Fixity 7 Hs.InfixL) $ showMagic "/")
+ (Symbol $ NatSymbol 1)
+ (fixateShowAlgebraEncaps e)
+fixateShowAlgebraEncaps (Function (SpecialEncapsulation Superscript) e)
+ = Operator (Infix (Hs.Fixity 7 Hs.InfixL) $ showMagic "◝")
+ (Symbol $ StringSymbol "\"\"")
+ (fixateShowAlgebraEncaps e)
+fixateShowAlgebraEncaps (Function (SpecialEncapsulation Subscript) e)
+ = Operator (Infix (Hs.Fixity 7 Hs.InfixL) $ showMagic "◞")
+ (Symbol $ StringSymbol "\"\"")
+ (fixateShowAlgebraEncaps e)
+fixateShowAlgebraEncaps (StdMathFn Abs e)
+ = haskellFunction "abs" $ fixateShowAlgebraEncaps e
+fixateShowAlgebraEncaps (ConventionalMathFn f e)
+ = haskellFunction f $ fixateShowAlgebraEncaps e
+fixateShowAlgebraEncaps (Function f e) = Function f $ fixateShowAlgebraEncaps e
+fixateShowAlgebraEncaps (Operator o x y)
+ = Operator o (fixateShowAlgebraEncaps x) (fixateShowAlgebraEncaps y)
+fixateShowAlgebraEncaps (OperatorChain x₀ oys)
+ = OperatorChain (fixateShowAlgebraEncaps x₀) (second fixateShowAlgebraEncaps <$> oys)
+fixateShowAlgebraEncaps e = e
+
+fixateLaTeXAlgebraEncaps :: ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
+ => CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+ -> CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+fixateLaTeXAlgebraEncaps (OperatorChain x
+ ((o,Function (SpecialEncapsulation ι) z):ys))
+ | (Infix (Hs.Fixity 6 Hs.InfixL) addSym', Negation) <- (o,ι)
+ , addSym' == addSym
+ = case fixateLaTeXAlgebraEncaps $ OperatorChain x ys of
+ x' -> Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-") x' z'
+ | (Infix (Hs.Fixity 7 Hs.InfixL) mulSym', Reciprocal) <- (o,ι)
+ , mulSym' == mulSym
+ = case fixateLaTeXAlgebraEncaps $ OperatorChain x ys of
+ x' -> Operator (Infix (Hs.Fixity 8 Hs.InfixL) mempty)
+ (encapsulation (raw "\\frac{") (raw "}") x')
+ (encapsulation (raw "{") (raw "}") z')
+ where [addSym, mulSym] = fromCharSymbol ([]::[σ]) <$> "+*" :: [LaTeX]
+ z' = fixateLaTeXAlgebraEncaps z
+fixateLaTeXAlgebraEncaps (OperatorChain x []) = fixateLaTeXAlgebraEncaps x
+fixateLaTeXAlgebraEncaps (OperatorChain x ((o@(Infix (Hs.Fixity _ Hs.InfixL) _), z):ys))
+ = Operator o (fixateLaTeXAlgebraEncaps $ OperatorChain x ys) (fixateLaTeXAlgebraEncaps z)
+fixateLaTeXAlgebraEncaps (Operator o x (Function (SpecialEncapsulation ι) y))
+ | (Infix (Hs.Fixity 6 Hs.InfixL) addSym', Negation) <- (o,ι)
+ , addSym' == addSym
+ = Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-") x' y'
+ | (Infix (Hs.Fixity 7 Hs.InfixL) mulSym', Reciprocal) <- (o,ι)
+ , mulSym' == mulSym
+ = Operator (Infix (Hs.Fixity 8 Hs.InfixL) mempty)
+ (encapsulation (raw "\\frac{") (raw "}") x')
+ (encapsulation (raw "{") (raw "}") y')
+ | (Infix fxty catSym', Superscript) <- (o,ι)
+ , catSym' == mempty
+ = Operator (Infix fxty (raw "^"))
+ x'
+ (encapsulation (raw "{") (raw "}") y')
+ | (Infix fxty catSym', Subscript) <- (o,ι)
+ , catSym' == mempty
+ = Operator (Infix fxty (raw "_"))
+ x'
+ (encapsulation (raw "{") (raw "}") y')
+ where [addSym, mulSym] = fromCharSymbol ([]::[σ]) <$> "+*" :: [LaTeX]
+ [x',y'] = fixateLaTeXAlgebraEncaps<$>[x,y]
+fixateLaTeXAlgebraEncaps (Function (SpecialEncapsulation Negation) e)
+ = Operator (Infix (Hs.Fixity 6 Hs.InfixL) "-")
+ (Symbol $ StringSymbol " ") $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (Function (SpecialEncapsulation Reciprocal) e)
+ = Operator (Infix (Hs.Fixity 8 Hs.InfixL) mempty)
+ (encapsulation (raw "\\frac{") (raw "}") . Symbol $ NatSymbol 1)
+ (encapsulation (raw "{") (raw "}") $ fixateLaTeXAlgebraEncaps e)
+fixateLaTeXAlgebraEncaps (Function (SpecialEncapsulation Superscript) e)
+ = encapsulation (raw "{}^{") (raw "}") $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (Function (SpecialEncapsulation Subscript) e)
+ = encapsulation (raw "{}_{") (raw "}") $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (StdMathFn Abs e)
+ = encapsulation (raw "\\left|") (raw "\\right|") $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (ConventionalMathFn f e)
+ = latexFunction ("\\"<>f) $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (Function f e) = Function f $ fixateLaTeXAlgebraEncaps e
+fixateLaTeXAlgebraEncaps (Operator o x y)
+ = Operator o (fixateLaTeXAlgebraEncaps x) (fixateLaTeXAlgebraEncaps y)
+fixateLaTeXAlgebraEncaps (OperatorChain x₀ oys)
+ = OperatorChain (fixateLaTeXAlgebraEncaps x₀) (second fixateLaTeXAlgebraEncaps <$> oys)
+fixateLaTeXAlgebraEncaps e = e
+
+
instance ASCIISymbols LaTeX where
fromASCIISymbol c
| isAlpha c = fromString [c]
@@ -56,6 +207,7 @@ instance UnicodeSymbols LaTeX where
toUnicodeSymbols lc
| Just c <- Map.lookup lc mappingToUnicode = [c]
| lc==mempty = ""
+ | Just s' <- matchShowMagic lc = Txt.unpack s'
| otherwise = "《"++Txt.unpack(render lc)++"》"
mappingFromUnicode :: Map.HashMap Char LaTeX
@@ -69,8 +221,8 @@ InvertibleMap mappingFromUnicode mappingToUnicode
['A'..'Z']
<|> mapToLaTeXWith mathbf ['𝐀'..'𝐙']
['A'..'Z']
- <|> mapToLaTeXWith mathbb "ℂℍℚℝℤ"
- "CHQRZ"
+ <|> mapToLaTeXWith mathbb "ℂℍℚℝℤℕ"
+ "CHQRZN"
<|> mapToLaTeXWith mathcal ['𝓐'..'𝓩']
['A'..'Z']
<|> mapToLaTeXWith mathfrak "𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜"
@@ -122,6 +274,23 @@ latexFunction :: LaTeXC l
-> (CAS' γ (Infix l) (Encapsulation l) (SymbolD σ l))
latexFunction f = Function $ Encapsulation True False (raw $ f<>"{") (raw "}")
+haskellFunction :: l ~ LaTeX
+ => Text
+ -> (CAS' γ (Infix l) (Encapsulation l) (SymbolD σ l))
+ -> (CAS' γ (Infix l) (Encapsulation l) (SymbolD σ l))
+haskellFunction f
+ = Function $ Encapsulation True False (showMagic $ f<>" ") mempty
+
+pattern StdMathFn ::
+ StdMathsFunc -> (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX))
+ -> (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX))
+pattern StdMathFn f e = Function (SpecialEncapsulation (StdMathsFunc f)) e
+
+pattern ConventionalMathFn ::
+ Text -> (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX))
+ -> (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX))
+pattern ConventionalMathFn f e = StdMathFn (ConventionalFunction f) e
+
instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
=> Num (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) where
fromInteger n
@@ -133,13 +302,9 @@ instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
(*) = chainableInfixL (==mulOp) mulOp
where fcs = fromCharSymbol ([]::[σ])
mulOp = Infix (Hs.Fixity 7 Hs.InfixL) $ fcs '*'
- (-) = symbolInfix (Infix (Hs.Fixity 6 Hs.InfixL) $ fcs '-')
- where fcs = fromCharSymbol ([]::[σ])
- abs = encapsulation (raw "\\left|") (raw "\\right|")
+ abs = StdMathFn Abs
signum = latexFunction "\\signum"
- negate = Operator (Infix (Hs.Fixity 6 Hs.InfixL) $ fcs '-')
- . Symbol $ StringSymbol mempty
- where fcs = fromCharSymbol ([]::[σ])
+ negate = Function $ SpecialEncapsulation Negation
instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
=> Fractional (CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) where
@@ -151,9 +316,7 @@ instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
else "."++(show=<<acs))
in if e==0 then m
else m * 10**fromIntegral e
- a / b = Operator (Infix (Hs.Fixity 8 Hs.InfixL) mempty)
- (encapsulation (raw "\\frac{") (raw "}") a)
- (encapsulation (raw "{") (raw "}") b)
+ recip = Function $ SpecialEncapsulation Reciprocal
instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
@@ -161,27 +324,29 @@ instance ∀ σ γ . (SymbolClass σ, SCConstraint σ LaTeX)
pi = Symbol $ StringSymbol pi_
sqrt = encapsulation (raw "\\sqrt{") (raw "}")
a ** b = Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
- a (encapsulation (raw "^{") (raw "}") b)
+ a (Function (SpecialEncapsulation Superscript) b)
logBase b a = Operator (Infix (Hs.Fixity 10 Hs.InfixL) mempty)
(encapsulation (raw "\\log_{") (raw "}") b) a
- exp = latexFunction "\\exp"
- log = latexFunction "\\log"
- sin = latexFunction "\\sin"
- cos = latexFunction "\\cos"
- tan = latexFunction "\\tan"
- asin = latexFunction "\\asin"
- acos = latexFunction "\\acos"
- atan = latexFunction "\\atan"
- sinh = latexFunction "\\sinh"
- cosh = latexFunction "\\cosh"
- tanh = latexFunction "\\tanh"
- asinh = latexFunction "\\asinh"
- acosh = latexFunction "\\acosh"
- atanh = latexFunction "\\atanh"
+ exp = ConventionalMathFn "exp"
+ log = ConventionalMathFn "log"
+ sin = ConventionalMathFn "sin"
+ cos = ConventionalMathFn "cos"
+ tan = ConventionalMathFn "tan"
+ asin = latexFunction "\\arcsin"
+ acos = latexFunction "\\arccos"
+ atan = latexFunction "\\arctan"
+ sinh = ConventionalMathFn "sinh"
+ cosh = ConventionalMathFn "cosh"
+ tanh = ConventionalMathFn "tanh"
+ asinh = latexFunction "\\operatorname{arsinh}"
+ acosh = latexFunction "\\operatorname{arcosh}"
+ atanh = latexFunction "\\operatorname{artanh}"
instance Eq (Encapsulation LaTeX) where
Encapsulation _ _ l r == Encapsulation _ _ l' r'
= l==l' && r==r'
+ SpecialEncapsulation e == SpecialEncapsulation e' = e==e'
+ _ == _ = False
diff --git a/Math/LaTeX/Internal/Display.hs b/Math/LaTeX/Internal/Display.hs
index e0de3a4..f5cf50f 100644
--- a/Math/LaTeX/Internal/Display.hs
+++ b/Math/LaTeX/Internal/Display.hs
@@ -23,7 +23,7 @@ import Text.LaTeX.Base.Class (LaTeXC, fromLaTeX)
import qualified Text.LaTeX.Base.Class as LaTeX
import qualified Text.LaTeX.Base.Types as LaTeX
import qualified Text.LaTeX.Base.Commands as LaTeX
-import Text.LaTeX.Base.Syntax (LaTeX(TeXEnv))
+import Text.LaTeX.Base.Syntax (LaTeX(TeXEnv, TeXComm))
import qualified Text.LaTeX.Packages.AMSMath as LaTeX
import qualified Text.LaTeX.Packages.AMSFonts as LaTeX
@@ -37,18 +37,38 @@ import Data.Foldable (fold)
import Data.Monoid ((<>))
import Control.Arrow
import Data.String (fromString)
+import Data.Char (isAlpha)
infixl 1 >$
-(>$) :: (LaTeXC r, SymbolClass σ, SCConstraint σ LaTeX)
- => r -> CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX) -> r
+-- | Embed inline maths in a monadic chain of document-components. Space before
+-- the math is included automatically.
+--
+-- @
+-- do
+-- \"If\">$𝑎;" and">$𝑏;" are the lengths of the legs and">$𝑐
+-- " of the cathete of a right triangle, then">$ 𝑎◝2+𝑏◝2 ⩵ 𝑐◝2;" holds."
+-- @
+(>$) :: (LaTeXC r, LaTeXSymbol σ)
+ => r -> LaTeXMath σ -> r
s >$ m = s <> " " <> LaTeX.math (toMathLaTeX' m)
+infixr 6 $<>
+-- | Embed inline maths in a semigroup/monoidal chain of document-components.
+--
+-- @
+-- "If "<>𝑎$<>" and "<>𝑏$<>" are the lengths of the legs and "<>𝑐$<>
+-- " of the cathete of a right triangle, then "<>(𝑎◝2+𝑏◝2 ⩵ 𝑐◝2)$<>" holds."
+-- @
+($<>) :: (LaTeXC r, LaTeXSymbol σ)
+ => LaTeXMath σ -> r -> r
+m $<> s = LaTeX.math (toMathLaTeX' m) <> s
+
-- | Include a formula / equation system as a LaTeX display. If it's a single
-- equation, automatic line breaks are inserted (requires the
-- <https://www.ctan.org/pkg/breqn?lang=en breqn LaTeX package>).
-dmaths :: (LaTeXC r, SymbolClass σ, SCConstraint σ LaTeX)
- => [[CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)]]
+dmaths :: (LaTeXC r, LaTeXSymbol σ)
+ => [[LaTeXMath σ]]
-- ^ Equations to show.
-> String -- ^ “Terminator” – this can include punctuation (when an equation
-- is at the end of a sentence in the preceding text).
@@ -67,9 +87,35 @@ dmaths eqLines garnish = fromLaTeX . TeXEnv
= contentsWithAlignAnchor q LaTeX.& aliLine cols
(eqnum, terminator) = parseEqnum garnish
+-- | Include a set of equations or formulas, each with a LaTeX label that can be
+-- referenced with 'LaTeX.ref'. (The label name will /not/ appear in the rendered
+-- document output; by default it will be just a number but you can tweak it with
+-- the terminator by including the desired tag in parentheses.)
+equations :: (LaTeXC r, LaTeXSymbol σ)
+ => [(LaTeXMath σ, String)]
+ -- ^ Equations to show, with label name.
+ -> String -- ^ “Terminator” – this can include punctuation (when an equation
+ -- is at the end of a sentence in the preceding text).
+ -> r
+equations [(e,lbl)] garnish = fromLaTeX $ case eqnum of
+ Nothing -> TeXEnv "equation" []
+ $ maybe mempty id eqnum <> toMathLaTeX e <> terminator <> asSafeLabel lbl
+ Just tag -> TeXEnv "equation*" []
+ $ tag <> toMathLaTeX e <> terminator <> asSafeLabel lbl
+ where (eqnum, terminator) = parseEqnum garnish
+equations eqLines garnish = fromLaTeX . TeXEnv "align" [] $ stack eqLines
+ where stack [singline] = fold eqnum <> aliLine singline <> terminator
+ stack (line : lines) = aliLine line <> LaTeX.lnbk <> stack lines
+ aliLine (q, lbl) = contentsWithAlignAnchor q <> asSafeLabel lbl
+ terminator :: LaTeX
+ (eqnum, terminator) = parseEqnum garnish
+
+asSafeLabel :: String -> LaTeX
+asSafeLabel = LaTeX.label . fromString . filter isAlpha
+
-- | Include a formula / equation system as a LaTeX display.
-maths :: (LaTeXC r, SymbolClass σ, SCConstraint σ LaTeX)
- => [[CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)]]
+maths :: (LaTeXC r, LaTeXSymbol σ)
+ => [[LaTeXMath σ]]
-- ^ Equations to show.
-> String -- ^ “Terminator” – this can include punctuation (when an equation
-- is at the end of a sentence in the preceding text).
@@ -90,12 +136,12 @@ maths eqLines garnish = fromLaTeX . TeXEnv
-- | Display an equation and also extract the final result. As with 'dmaths', automatic
-- line breaks are inserted by <https://www.ctan.org/pkg/breqn?lang=en breqn>.
-dcalculation :: (LaTeXC (m ()), SymbolClass σ, SCConstraint σ LaTeX, Functor m)
- => CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+dcalculation :: (LaTeXC (m ()), LaTeXSymbol σ, Functor m)
+ => LaTeXMath σ
-- ^ Computation chain to display.
-> String -- ^ “Terminator” – this can include punctuation (when an equation
-- is at the end of a sentence in the preceding text).
- -> m (CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX))
+ -> m (LaTeXMath σ)
-- ^ Yield the rightmost expression in the displayed computation
-- (i.e. usually the final result in a chain of algebraic equalities).
dcalculation ch garnish = fmap (\() -> result) $ case eqnum of
@@ -119,9 +165,8 @@ parseEqnum ('(':n) = ( Just $ raw"\\tag{"<>fromString num<>raw"}"
where (num,')':r) = break (==')') n
parseEqnum (c:n) = parseEqnum n
-
-contentsWithAlignAnchor :: (LaTeXC c, SymbolClass σ, SCConstraint σ LaTeX)
- => CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX) -> c
+contentsWithAlignAnchor :: (LaTeXC c, LaTeXSymbol σ)
+ => LaTeXMath σ -> c
contentsWithAlignAnchor (OperatorChain lc rcs@(_:_))
= toMathLaTeX' lc <> fromLaTeX op
<> raw"\\:"LaTeX.&toMathLaTeX' (OperatorChain rc₀ $ init rcs)
diff --git a/Math/LaTeX/Internal/MathExpr.hs b/Math/LaTeX/Internal/MathExpr.hs
index 11de3de..2279904 100644
--- a/Math/LaTeX/Internal/MathExpr.hs
+++ b/Math/LaTeX/Internal/MathExpr.hs
@@ -8,14 +8,18 @@
-- Portability : requires GHC>7 extensions
--
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE UnicodeSyntax #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnicodeSyntax #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE CPP #-}
module Math.LaTeX.Internal.MathExpr where
@@ -25,8 +29,10 @@ import Text.LaTeX.Base.Class (LaTeXC, fromLaTeX)
import qualified Text.LaTeX.Base.Class as LaTeX
import qualified Text.LaTeX.Base.Types as LaTeX
import qualified Text.LaTeX.Base.Commands as LaTeX
+import qualified Text.LaTeX.Base.Math as LaTeX
import Text.LaTeX.Base.Syntax (LaTeX(TeXEnv))
import qualified Text.LaTeX.Packages.AMSMath as LaTeX
+import qualified Text.LaTeX.Packages.AMSSymb as LaTeX
import qualified Text.LaTeX.Packages.AMSFonts as LaTeX
import CAS.Dumb
@@ -35,13 +41,30 @@ import CAS.Dumb.Symbols
import CAS.Dumb.LaTeX.Symbols
import Math.LaTeX.Internal.OperatorGenerator
-import Data.Foldable (fold)
-import Data.Monoid ((<>))
+import Data.Foldable (fold, toList)
+import Data.Semigroup
+import qualified Data.List.NonEmpty as NE
+import Data.Monoid hiding ((<>))
+import Data.Void
+import Data.AdditiveGroup
+import Data.VectorSpace
+import Data.String (IsString)
import qualified Language.Haskell.TH.Syntax as Hs
import Language.Haskell.TH.Syntax (Fixity(..), FixityDirection(..))
-
-
+
+-- | Mathematical expressions to be typeset in LaTeX.
+-- Most of the functions in this library have more generic signatures, but
+-- all can be used with this type.
+--
+-- The @σ@ parameter specifies how single-symbol “literals” are used in your
+-- Haskell code.
+type LaTeXMath σ = CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
+
+-- | The @CAS.Dumb.Symbols.Unicode.*@ modules offer symbols that can be rendered
+-- in LaTeX.
+type LaTeXSymbol σ = (SymbolClass σ, SCConstraint σ LaTeX)
+
type MathsInfix = ∀ γ σ .
CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
-> CAS' γ (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)
@@ -92,8 +115,8 @@ factorial n = Operator (Infix (Hs.Fixity 8 Hs.InfixR) $ raw"!")
infixr 3 ∧, ∨
(∧), (∨) :: MathsInfix
-(∧) = opR 3 $ raw"\\wedge{}"
-(∨) = opR 3 $ raw"\\vee{}"
+(∧) = opR 3 $ LaTeX.comm0"wedge"
+(∨) = opR 3 $ LaTeX.comm0"vee"
(∩), (∪), (-\-) :: MathsInfix
infixr 3 ∩
@@ -107,7 +130,7 @@ infixr 5 ⸪, -→, ↪
(⸪), (-→), (↪) :: MathsInfix
(⸪) = opR 5 ":"
(-→) = opR 5 LaTeX.to
-(↪) = opR 5 $ raw"\\hookrightarrow{}"
+(↪) = opR 5 $ LaTeX.comm0"hookrightarrow"
infix 2 ∀:, ∃:
(∀:), (∃:) :: MathsInfix
@@ -122,11 +145,11 @@ infixl 8 ◞◝, ₌₌
(°), (⁀), (◝), (◝⁀), (◞), (|◞), (₌₌) :: MathsInfix
f°x = opL 7 mempty f (encapsulation (raw"\\left(") (raw"\\right)") x)
(⁀) = opR 9 mempty
-l◝⁀s = opR 9 mempty l $ encapsulation (raw"\\left(") (raw"\\right)^") s
+l◝⁀s = opR 9 mempty l $ encapsulation (raw"^{\\left(") (raw"\\right)}") s
l◝s = Operator (Infix (Hs.Fixity 9 Hs.InfixR) mempty)
- l (encapsulation (raw "^{") (raw "}") s)
+ l (Function (SpecialEncapsulation Superscript) s)
l◞s = Operator (Infix (Hs.Fixity 9 Hs.InfixR) mempty)
- l (encapsulation (raw "_{") (raw "}") s)
+ l (Function (SpecialEncapsulation Subscript) s)
l₌₌s = Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
(encapsulation (raw "\\underbrace{") (raw "}") l)
(encapsulation (raw "_{") (raw "}") s)
@@ -136,13 +159,13 @@ l◞◝(s,p) = Operator (Infix (Hs.Fixity 9 Hs.InfixR) mempty)
(encapsulation (raw "_{") (raw "}") s)
(encapsulation (raw "^{") (raw "}") p)
l|◝s = Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
- (encapsulation (raw "left.") (raw "right|") l)
+ (encapsulation (raw "\\left.") (raw "\\right|") l)
(encapsulation (raw "^{") (raw "}") s)
l|◞s = Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
- (encapsulation (raw "left.") (raw "right|") l)
+ (encapsulation (raw "\\left.") (raw "\\right|") l)
(encapsulation (raw "_{") (raw "}") s)
l|◞◝(s,p) = Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
- (encapsulation (raw "left.") (raw "right|") l)
+ (encapsulation (raw "\\left.") (raw "\\right|") l)
$ Operator (Infix (Hs.Fixity 8 Hs.InfixR) mempty)
(encapsulation (raw "_{") (raw "}") s)
(encapsulation (raw "^{") (raw "}") p)
@@ -152,9 +175,9 @@ makeOperatorCaste "implicationOperators"
(''MathsInfix, ''LaTeX)
(Fixity 1 InfixL)
True
- [ ("==>", [e|raw"\\Longrightarrow "|])
- , ("<==", [e|raw"\\Longleftarrow "|])
- , ("<=>", [e|raw"\\Longleftrightarrow "|])
+ [ ("==>", [e|LaTeX.longrightarrow2|])
+ , ("<==", [e|LaTeX.longleftarrow2|])
+ , ("<=>", [e|LaTeX.longleftrightarrow2|])
]
makeOperatorCaste "relationOperators"
@@ -166,25 +189,31 @@ makeOperatorCaste "relationOperators"
, ("⸪=", [e|raw"{:=}"|])
, ("=⸪", [e|raw"{=:}"|])
#endif
- , ("≡", [e|raw" \\equiv "|])
+ , ("≡", [e|LaTeX.comm0"equiv"|])
, ("⩵!", [e|raw" \\overset{!}{=} "|])
, ("≠", [e|""LaTeX./=:""|])
- , ("≈", [e|raw" \\approx "|])
- , ("∼", [e|raw" \\sim "|])
+ , ("≈", [e|LaTeX.comm0"approx"|])
+ , ("∼", [e|LaTeX.comm0"sim"|])
+ , ("≃", [e|LaTeX.comm0"simeq"|])
+ , ("≅", [e|LaTeX.comm0"cong"|])
, ("⪡", [e|""LaTeX.<:""|])
, ("⪢", [e|""LaTeX.>:""|])
, ("≤", [e|""LaTeX.<=:""|])
, ("≥", [e|""LaTeX.>=:""|])
, ("≪", [e|LaTeX.ll""""|])
, ("≫", [e|LaTeX.gg""""|])
+ , ("∝", [e|LaTeX.propto""""|])
+ , ("⟂", [e|LaTeX.perp""""|])
+ , ("∥", [e|LaTeX.parallel""""|])
, ("⊂", [e|LaTeX.subset""""|])
, ("/⊂", [e|raw" \\not\\subset "|])
, ("⊃", [e|LaTeX.supset""""|])
- , ("⊆", [e|raw"\\subseteq{}"|])
- , ("⊇", [e|raw"\\supseteq{}"|])
+ , ("⊆", [e|LaTeX.comm0"subseteq"|])
+ , ("⊇", [e|LaTeX.comm0"supseteq"|])
, ("∋", [e|LaTeX.ni""""|])
, ("∌", [e|raw"\\not\\ni{}"|])
, ("=→", [e|LaTeX.to|])
+ , ("←=", [e|LaTeX.leftarrow|])
, ("∈", [e|LaTeX.in_""""|])
, ("∉", [e|raw"\\not\\in{}"|])
, ("↦", [e|LaTeX.mapsto|])
@@ -203,7 +232,7 @@ newtype Integrand γ s² s¹ s⁰ = Integrand { getIntgrand :: CAS' γ s² s¹ s
d :: LaTeXC l => CAS' γ (Infix l) (Encapsulation l) s⁰
-> CAS' γ (Infix l) (Encapsulation l) s⁰
-> Integrand γ (Infix l) (Encapsulation l) s⁰
-d x f = Integrand $ opR 7 (raw "\\ ") x f
+d x f = Integrand $ opR 7 LaTeX.space x f
infixr 8 ∫, ◞∫, ◞∮, ∑, ◞∑, ∏, ◞∏
@@ -289,8 +318,8 @@ makeOperatorCaste "juxtapositionOperators"
(''MathsInfix, ''LaTeX)
(Fixity 0 InfixR)
True
- [ ("␣", [e|raw"\\ "|])
- , ("...", [e|raw"{\\ldots}"|])
+ [ ("␣", [e|LaTeX.space|])
+ , ("...", [e|LaTeX.comm0"ldots"|])
#if __GLASGOW_HASKELL__ > 801
, ("،", [e|raw","|])
, ("،..،", [e|raw",\\ldots,"|])
@@ -344,20 +373,68 @@ toMathLaTeX' :: ∀ σ l . (LaTeXC l, SymbolClass σ, SCConstraint σ LaTeX)
=> CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX) -> l
toMathLaTeX' = fromLaTeX . toMathLaTeX
-toMathLaTeX :: ∀ σ l . (LaTeXC l, Num l, SymbolClass σ, SCConstraint σ l)
+toMathLaTeX :: ∀ σ l . ( l ~ LaTeX, SymbolClass σ
+ , SCConstraint σ l )
=> CAS (Infix l) (Encapsulation l) (SymbolD σ l) -> l
toMathLaTeX = renderSymbolExpression (AtLHS $ Hs.Fixity 0 Hs.InfixL) ρ
+ . fixateLaTeXAlgebraEncaps
where ρ dop lctxt (StringSymbol sym) rctxt
- = showLParen dop $ flip (foldr (<>)) lctxt $ foldl (<>) sym rctxt
+ = showLParen dop $ flip (foldr mappend) lctxt $ foldl mappend sym rctxt
ρ dop lctxt (NatSymbol n) rctxt
- = showLParen dop $ flip (foldr (<>)) lctxt $ foldl (<>) (fromInteger n) rctxt
+ = showLParen dop $ flip (foldr mappend) lctxt $ foldl mappend (fromInteger n) rctxt
ρ dop lctxt (PrimitiveSymbol c) rctxt
= case fromCharSymbol ([]::[σ]) of
- fcs -> showLParen dop $ flip (foldr (<>)) lctxt $ foldl (<>) (fcs c) rctxt
+ fcs -> showLParen dop $ flip (foldr mappend) lctxt $ foldl mappend (fcs c) rctxt
showLParen :: LaTeXC l => Bool -> l -> l
showLParen True = LaTeX.autoParens
showLParen False = id
-
+instance (SymbolClass σ, SCConstraint σ LaTeX)
+ => Semigroup (CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) where
+ l<>r = sconcat $ l NE.:|[r]
+ sconcat es = case don'tParenthesise <$> NE.toList es of
+ [l,r] -> symbolInfix (Infix loosestFixity mempty) l r
+ (l:rs) -> OperatorChain l [(Infix loosestFixity mempty, r) | r<-reverse rs]
+ where loosestFixity = case foldr1 looser $ expressionFixity <$> es of
+ Nothing -> Hs.Fixity 10 Hs.InfixR
+ Just fxty -> fxty
+ looser Nothing Nothing = Nothing
+ looser (Just fxty) Nothing = Just fxty
+ looser Nothing (Just fxty) = Just fxty
+ looser (Just (Hs.Fixity fxtyL fdL)) (Just (Hs.Fixity fxtyR fdR))
+ | fxtyL > fxtyR = Just $ Hs.Fixity fxtyR fdR
+ | fxtyL < fxtyR
+ || fdL == fdR = Just $ Hs.Fixity fxtyL fdL
+ | otherwise = Just $ Hs.Fixity fxtyL Hs.InfixN
+
+instance (SymbolClass σ, SCConstraint σ LaTeX)
+ => Monoid (CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) where
+ mempty = atom mempty
+ mappend = (<>)
+ mconcat [] = mempty
+ mconcat (l : m) = sconcat $ l NE.:| m
+instance ( SymbolClass σ, SCConstraint σ LaTeX
+ , IsString (CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) )
+ => LaTeXC (CAS (Infix LaTeX) (Encapsulation LaTeX) (SymbolD σ LaTeX)) where
+ liftListL f = atom . f . map toMathLaTeX
+
+instance ( γ ~ Void, s² ~ Infix LaTeX, s¹ ~ Encapsulation LaTeX, s⁰ ~ SymbolD σ LaTeX
+ , SymbolClass σ, SCConstraint σ LaTeX )
+ => LaTeX.Texy (CAS' γ s² s¹ s⁰) where
+ texy = LaTeX.math . LaTeX.texy . toMathLaTeX
+
+instance LaTeXSymbol σ => AdditiveGroup (LaTeXMath σ) where
+ zeroV = 0
+ (^+^) = (+)
+ (^-^) = (-)
+ negateV = negate
+
+instance LaTeXSymbol σ => VectorSpace (LaTeXMath σ) where
+ type Scalar (LaTeXMath σ) = LaTeXMath σ
+ (*^) = (*)
+
+instance LaTeXSymbol σ => InnerSpace (LaTeXMath σ) where
+ l <.> r = encapsulation (raw"\\left\\langle{") (raw"}\\right\\rangle")
+ $ opN 0 (raw",") l r
diff --git a/Math/LaTeX/Prelude.hs b/Math/LaTeX/Prelude.hs
index 4c89b1e..08693e7 100644
--- a/Math/LaTeX/Prelude.hs
+++ b/Math/LaTeX/Prelude.hs
@@ -11,21 +11,29 @@
{-# LANGUAGE CPP #-}
module Math.LaTeX.Prelude (
- -- * Use in documents
- toMathLaTeX, (>$), dmaths, maths, dcalculation
+ LaTeXMath
-- * Primitive symbols
+ , LaTeXSymbol
+ -- ** Unicode literals
, module CAS.Dumb.Symbols.Unicode.MathLatin_RomanGreek__BopomofoGaps
- -- ** Modifiers
- , (%$>), prime, LaTeX.bar, LaTeX.hat, LaTeX.vec, LaTeX.underline, LaTeX.tilde
- -- * Operators
+ -- $unicodeLiterals
+ , LaTeXMath__MathLatin_RomanGreek__BopomofoGaps
+ -- ** Custom symbol-literals
+ -- $nonunicodeLiterals
+
+ -- ** Symbol modifiers
+ , (%$>), prime
+ , LaTeX.dot, LaTeX.ddot, LaTeX.bar, LaTeX.hat
+ , LaTeX.vec, LaTeX.underline, LaTeX.tilde
+ -- * Maths operators
, (°), (⁀), (...)
#if __GLASGOW_HASKELL__ > 801
, (،..،), (،), (⸪=), (=⸪)
#endif
, (␣), (+..+), (*..*), (×), (⊗), (∘), factorial
, (◝), (◝⁀), (◞), (◞◝), (|◞), (|◝), (|◞◝)
- , (⩵), (≡), (⩵!), (≠), (⪡), (⪢), (≤), (≥), (≪), (≫), (₌₌)
- , (=→), (≈), (∼)
+ , (⩵), (≡), (⩵!), (≠), (⪡), (⪢), (≤), (≥), (≪), (≫), (∝), (⟂), (∥), (₌₌)
+ , (=→), (←=), (≈), (∼), (≃), (≅)
, (⊂), (/⊂), (⊆), (⊃), (⊇), (∋), (∌), (∈), (∉), (∩), (∪), (-\-), (⸪), (⊕)
, (∀:), (∃:)
, (-→), (↦), (↪), (==>), (<==), (<=>), (∧), (∨)
@@ -34,8 +42,12 @@ module Math.LaTeX.Prelude (
, infty, norm
, nobreaks, matrix, cases
-- * Algebraic manipulation
+ -- #algebraManip
, (&~~!), (&~~:), continueExpr, (&)
, (&~:), (&~?), (&~!), (|->)
+ -- * Use in documents
+ , (Math.LaTeX.Prelude.$<>), (Math.LaTeX.Prelude.>$)
+ , dmaths, maths, equations, dcalculation, toMathLaTeX
) where
import CAS.Dumb.Symbols.Unicode.MathLatin_RomanGreek__BopomofoGaps hiding ((%$>))
@@ -44,7 +56,7 @@ import Math.LaTeX.Internal.MathExpr
import Math.LaTeX.Internal.Display
import Text.LaTeX.Base.Class (LaTeXC)
-import Text.LaTeX.Base (raw)
+import Text.LaTeX.Base (raw, LaTeX)
import qualified Text.LaTeX.Packages.AMSMath as LaTeX
import qualified Text.LaTeX.Base.Commands as LaTeX
@@ -53,7 +65,72 @@ import Data.Function ((&))
import CAS.Dumb.Tree
+type LaTeXMath__MathLatin_RomanGreek__BopomofoGaps
+ = CAS (Infix LaTeX) (Encapsulation LaTeX) (Symbol LaTeX)
+
+infixl 1 >$
+-- | Embed inline maths in a monadic chain of document-components. Space before
+-- the math is included automatically.
+--
+-- @
+-- do
+-- \"If\">$𝑎;" and">$𝑏;" are the lengths of the legs and">$𝑐
+-- " of the cathete of a right triangle, then">$ 𝑎◝2+𝑏◝2 ⩵ 𝑐◝2;" holds."
+-- @
+--
+-- Note: these versions of the '$<>' and '>$' operators have a signature that's
+-- monomorphic to unicode symbol-literals.
+-- (This restriction is to avoid ambiguous types when writing maths /without/ any
+-- symbols in it, like simply embedding a fraction in inline text.) See
+-- [Custom literals](#nonunicodeLiteralsHowto) if this is a problem for you.
+(>$) :: LaTeXC r
+ => r -> LaTeXMath__MathLatin_RomanGreek__BopomofoGaps -> r
+(>$) = (Math.LaTeX.Internal.Display.>$)
+
+infixr 6 $<>
+-- | Embed inline maths in a semigroup/monoidal chain of document-components.
+--
+-- @
+-- "If "<>𝑎$<>" and "<>𝑏$<>" are the lengths of the legs and "<>𝑐$<>
+-- " of the cathete of a right triangle, then "<>(𝑎◝2+𝑏◝2 ⩵ 𝑐◝2)$<>" holds."
+-- @
+--
+-- This will be rendered as: If \(a\) and \(b\) are the lengths of the legs and \(c\)
+-- of the cathete of a right triangle, then \(a^2+b^2=c^2\) holds.
+($<>) :: LaTeXC r
+ => LaTeXMath__MathLatin_RomanGreek__BopomofoGaps -> r -> r
+($<>) = (Math.LaTeX.Internal.Display.$<>)
+-- $unicodeLiterals
+-- This module offers a “WYSiWYG” style, with italic Unicode math symbols
+-- (@U+1d44e 𝑎@ - @U+1d467 𝑧@) coming out as standard italic symbols \(a\) - \(z\),
+-- bold Unicode math symbols (@U+1d41a 𝐚@ - @U+1d433 𝐳@) coming out as bold
+-- \(\mathbf{a}\) - \(\mathbf{z}\) and so on.
+-- Greek letters can be used from the standard block
+-- (@U+3b1 α@ → \(\alpha\) - @U+3c9 ω@ → \(\omega\)).
+-- All of this also works for uppercase letters (it circumvents Haskell syntax
+-- restrictions by using the @PatternSynonyms@ extension).
+--
+-- Upright (roman) symbols are not directly supported, but if you import
+-- "Math.LaTeX.StringLiterals" they can be written as strings.
+--
+-- Example: @𝑎 + 𝐛 + 𝐶 + \"D\" + ε + Φ ∈ ℝ@ is rendered as
+-- \(a + \mathbf{b} + C + \text{D} + \varepsilon + \Phi \in \mathbb{R}\).
+--
+-- The Bopomofo symbols here are not exported for use in documents but
+-- for [Algebraic manipulation](#algebraManip).
+
+-- $nonunicodeLiterals
+-- If you prefer using instead e.g. ASCII letters @A@ - @z@ for simple symbols
+-- \(A\) - \(z\), use this import list:
+--
+-- @
+-- import Math.LaTeX.Prelude hiding ((>$), (<>$))
+-- import "Math.LaTeX.Internal.Display" ((>$), (<>$))
+-- import "CAS.Dumb.Symbols.ASCII"
+-- @
+--
+-- We give no guarantee that this will work without name clashes or type ambiguities.
prime :: LaTeXC l => l -> l
prime = (<>raw"'")
diff --git a/Math/LaTeX/StringLiterals.hs b/Math/LaTeX/StringLiterals.hs
index f4b9406..1c29914 100644
--- a/Math/LaTeX/StringLiterals.hs
+++ b/Math/LaTeX/StringLiterals.hs
@@ -8,7 +8,8 @@
-- Portability : requires GHC>7 extensions
--
-- An orphan instance to the 'FromString' class, which allows maths expressions
--- to include literal strings. These will be rendered in roman font.
+-- to include literal strings if you enable @{-# LANGUAGE OverloadedStrings #-}@.
+-- These will be rendered in roman font.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
diff --git a/TeX-my-math.cabal b/TeX-my-math.cabal
index 474ad2d..ae71779 100644
--- a/TeX-my-math.cabal
+++ b/TeX-my-math.cabal
@@ -1,5 +1,5 @@
Name: TeX-my-math
-Version: 0.201.1.1
+Version: 0.201.2.0
Category: math
Synopsis: Render general Haskell math to LaTeX. Or: math typesetting with high signal-to-noise–ratio.
Description: For tl;dr: look at <https://github.com/leftaroundabout/Symbolic-math-HaTeX/blob/master/EXAMPLES.md>.
@@ -35,16 +35,16 @@ Description: For tl;dr: look at <https://github.com/leftaroundabout/Symb
License: GPL-3
License-file: COPYING
Author: Justus Sagemüller
-Maintainer: (@) jsagemue $ uni-koeln.de
+Maintainer: (@) jsag $ hvl.no
Homepage: http://github.com/leftaroundabout/Symbolic-math-HaTeX
Build-Type: Simple
Cabal-Version: >=1.10
Library
- Build-Depends: base>=4.8 && <4.11
- , HaTeX>3.4
+ Build-Depends: base>=4.8 && <4.14
+ , HaTeX>3.19
, vector-space
- , dumb-cas >= 0.1.1.1 && < 0.2
+ , dumb-cas >= 0.2 && < 0.3
, decimal-literals
, text
, void
@@ -77,5 +77,17 @@ test-suite makeSnippets
, TeX-my-math
, text
, directory, filepath, process
- Default-Language: Haskell2010
+executable TeXmyMath-example
+ default-language:
+ Haskell2010
+ hs-source-dirs:
+ example
+ main-is:
+ Simple.hs
+ build-depends:
+ base
+ , TeX-my-math
+ , HaTeX
+ , text
+ , directory, filepath, process
diff --git a/example/Simple.hs b/example/Simple.hs
new file mode 100644
index 0000000..9bd8b4a
--- /dev/null
+++ b/example/Simple.hs
@@ -0,0 +1,97 @@
+-- |
+-- Module : Main
+-- Copyright : (c) Justus Sagemüller 2019
+-- License : GPL v3
+--
+-- Maintainer : (@) jsagemue $ uni-koeln.de
+-- Stability : experimental
+-- Portability : portable
+--
+-- Example document. Run `cabal run TeXMyMath-example` in the top-level directory
+-- to render it as a PDF.
+--
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE CPP #-}
+
+module Main where
+
+import Math.LaTeX.Prelude
+import Math.LaTeX.StringLiterals
+
+import Text.LaTeX (LaTeX, raw, Text)
+import qualified Text.LaTeX as TeX
+import qualified Text.LaTeX.Packages.AMSMath as TeX
+import qualified Text.LaTeX.Packages.AMSSymb as TeX
+import qualified Text.LaTeX.Packages.Babel as Babel
+import qualified Data.Text as Txt
+import qualified Data.Text.IO as Txt
+import Data.Char
+
+import System.FilePath
+import System.Directory
+import System.Process
+
+import Data.Monoid
+import Data.Function ((&))
+import Control.Monad
+import Data.Functor.Identity
+
+type Math = LaTeXMath__MathLatin_RomanGreek__BopomofoGaps
+
+example :: LaTeX
+example
+ = TeX.title ("A simple example document for the "<>texmymath<>" Haskell package.")
+ <> TeX.author "Justus Sagemüller"
+ <> TeX.usepackage [] TeX.amsmath
+ <> TeX.usepackage [] TeX.amssymb
+ <> TeX.raw "\\usepackage{fontspec}"
+ <> TeX.raw "\\usepackage{bigfoot}"
+ <> Babel.uselanguage `id` Babel.English
+ <> TeX.document `id`do
+ TeX.maketitle
+ <> "The "<>texmymath<>" package allows you to write maths formulas with a plaintext"
+ <>" syntax that is more human-readable than LaTeX, and more structurally coherent,"
+ <>" namely being Haskell source code whose AST represents how the math would"
+ <>" actually parse semantically. The simplest example would be arithmetic expressions"
+ <>" with number literals, like"
+ <>maths[[4+5*6 :: Math]]"."
+ <>"Note that parenthesisation is obeyed:"
+ <>maths[[(4+5)*6 :: Math]]"."
+ <>"For symbols, we recommend using the Unicode primitives that come by default "
+ <>" with the "<>TeX.verb"Math.LaTeX.Prelude"<>" module"
+ <>TeX.footnote("These symbols are originally declared in the "<>TeX.verb"dumb-cas"
+ <>" package, in the "
+ <>TeX.verb"CAS.Dumb.Symbols.Unicode.MathLatin_RomanGreek__BopomofoGaps"
+ <>" module.")
+ <>". This allows symbols like "<>𝑎$<>", "<>𝑏$<>" or "<>ψ$<>" to appear natural and"
+ <>" similar to their rendered form in the plaintext source. This includes also bold,"
+ <>" “blackboard” etc. variants, and notably allows uppercase characters"
+ <>TeX.footnote("Using the GHC "<>TeX.verb"PatternSynonyms"<>" extension as a hack"
+ <>" around Haskell's syntax restriction that identifiers must start with"
+ <>" a lowercase character.")
+ <>" in addition to lowercase."
+ <>maths[[ 𝑎 + 𝑏 + 𝑀 + 𝑁 + 𝐱 + 𝐲 + ℍ + 𝓠 + 𝓛 + Γ + ω ]]"."
+ where texmymath = TeX.tex<>"-my-Math"
+
+main :: IO ()
+main = do
+ wdAbs <- makeAbsolute workdir
+ createDirectoryIfMissing True wdAbs
+ withCurrentDirectory wdAbs $ do
+ TeX.renderFile (thisDocument<>".tex") $ do
+ TeX.raw "\\documentclass{article}"
+ <> example
+ callProcess "xelatex" [thisDocument]
+ callProcess "convert" [ "-density", "150"
+ , thisDocument<>".pdf"
+ , "-trim"
+ , "-background", "white", "-alpha", "off"
+ , "-resize", "50%"
+ , thisDocument<>".png" ]
+ putStrLn $ "Output generated in directory "<>wdAbs
+ where workdir = "example/outputs"
+ thisDocument = "simple"
+
+
+
diff --git a/test/PdfSnippets/MkSnippets.hs b/test/PdfSnippets/MkSnippets.hs
index e2f6043..ed734b8 100644
--- a/test/PdfSnippets/MkSnippets.hs
+++ b/test/PdfSnippets/MkSnippets.hs
@@ -61,16 +61,16 @@ tests = testGroup "Tests"
, [mkLaTeXSnip| sin (sin 𝑥) |] "\\sin{\\left(\\sin{x}\\right)}"
, [mkLaTeXSnip| (𝑖⩵0,3)∑ 𝑖 |] "\\sum_{i=0}^{3} i"
, [mkLaTeXSnip| matrix[[ 0,1]
- ,[-1,0]] |] "\\begin{pmatrix}0&1\\\\-1&0\\end{pmatrix}"
+ ,[-1,0]] |] "\\begin{pmatrix}0&1\\\\ -1&0\\end{pmatrix}"
]
, testGroup "Number literals"
[ [mkLaTeXSnip| 25697325 |] "25697325"
, [mkLaTeXSnip| 4.718 |] "4.718"
- , [mkLaTeXSnip| 1e-3 |] "1{\\cdot}10^{-3}"
+ , [mkLaTeXSnip| 1e-3 |] "1{\\cdot}10^{ -3}"
, [mkLaTeXSnip| 257.35e9 |] "2.5735{\\cdot}10^{11}"
- , [mkLaTeXSnip| -5.1e-8 |] "-5.1{\\cdot}10^{-8}"
+ , [mkLaTeXSnip| -5.1e-8 |] " -5.1{\\cdot}10^{ -8}"
, [mkLaTeXSnip| 7/13 |] "\\frac{7}{13}"
- , [mkLaTeXSnip| -(1/2) |] "-\\frac{1}{2}"
+ , [mkLaTeXSnip| -(1/2) |] " -\\frac{1}{2}"
]
, testGroup "Operators"
[ testGroup "Arithmetic"
@@ -89,6 +89,7 @@ tests = testGroup "Tests"
, [mkLaTeXSnip| ψ◞"Foo" |] "\\psi{}_{\\mathrm{Foo}}"
#if __GLASGOW_HASKELL__ > 801
, [mkLaTeXSnip| ψ◞𝐹⁀𝑜⁀𝑜 |] "\\psi{}_{Foo}"
+ , [mkLaTeXSnip| 𝑓◝⁀3°𝑥 |] "f^{\\left(3\\right)}\\left(x\\right)"
#endif
]
, testGroup "Function application"
@@ -100,10 +101,10 @@ tests = testGroup "Tests"
, testGroup "Logical"
[ [mkLaTeXSnip| 𝑝 ∨ 𝑞 |] "p\\vee{}q"
, [mkLaTeXSnip| 𝑝 ∧ 𝑞 |] "p\\wedge{}q"
- , [mkLaTeXSnip| 𝑝==>𝑞 |] "p\\Longrightarrow q"
- , [mkLaTeXSnip| 𝑝<==𝑞 |] "p\\Longleftarrow q"
- , [mkLaTeXSnip| 𝑝<=>𝑞 |] "p\\Longleftrightarrow q"
- , [mkLaTeXSnip| 𝑝==>𝑞==>𝑟 |] "p\\Longrightarrow q\\Longrightarrow r"
+ , [mkLaTeXSnip| 𝑝==>𝑞 |] "p\\Longrightarrow{}q"
+ , [mkLaTeXSnip| 𝑝<==𝑞 |] "p\\Longleftarrow{}q"
+ , [mkLaTeXSnip| 𝑝<=>𝑞 |] "p\\Longleftrightarrow{}q"
+ , [mkLaTeXSnip| 𝑝==>𝑞==>𝑟 |] "p\\Longrightarrow{}q\\Longrightarrow{}r"
, [mkLaTeXSnip| cases[(1, "Today"), (2, "Else")] |]
"\\begin{cases}1&\\text{Today}\\\\2&\\text{Else}\\end{cases}"
]
@@ -113,18 +114,21 @@ tests = testGroup "Tests"
, [mkLaTeXSnip| 𝑎 ⪡ ρ |] "a<\\rho{}"
, [mkLaTeXSnip| 𝑥 ⩵ 𝑦 ⩵ 𝑧 |] "x=y=z"
, [mkLaTeXSnip| 𝑠 ⊂ 𝑡 ⊆ 𝑢 |] "s\\subset{}t\\subseteq{}u"
+ , [mkLaTeXSnip| ℎ ≈ 𝑔 ∼ 𝑓 ≃ 𝑒 ≅ 𝑑 |] "h\\approx{}g\\sim{}f\\simeq{}e\\cong{}d"
#if __GLASGOW_HASKELL__ > 801
, [mkLaTeXSnip| 𝑝 ∈ ℚ ⊂ ℝ |] "p\\in{}\\mathbb{Q}\\subset{}\\mathbb{R}"
#endif
+ , [mkLaTeXSnip| 𝐮 ⟂ (vec%$>𝑣) ∥ (underline%$>𝑤) |]
+ "\\mathbf{u}\\perp{}\\vec{v}\\parallel{}\\underline{w}"
]
]
, testGroup "Calculus"
[ testGroup "Integration"
- [ [mkLaTeXSnip| (-1,1)∫d 𝑥 (𝑥**2) |] "\\int\\limits_{-1}^{1}\\mathrm{d}x\\ x^{2}"
+ [ [mkLaTeXSnip| (-1,1)∫d 𝑥 (𝑥**2) |] "\\int\\limits_{ -1}^{1}\\mathrm{d}x\\ {}x^{2}"
, [mkLaTeXSnip| ω◞∫d 𝑥 (exp $ -(𝑥**2)) |]
- "\\int_{\\omega{}}\\!\\!\\!\\mathrm{d}x\\ \\exp{\\left(-x^{2}\\right)}"
+ "\\int_{\\omega{}}\\!\\!\\!\\mathrm{d}x\\ {}\\exp{\\left( -x^{2}\\right)}"
, [mkLaTeXSnip| (0,1)∫d 𝑥 ((0,1)∫d 𝑦 (𝑥*𝑦)) |]
- "\\int\\limits_{0}^{1}\\mathrm{d}x\\ \\int\\limits_{0}^{1}\\mathrm{d}y\\ \\left(x{\\cdot}y\\right)"
+ "\\int\\limits_{0}^{1}\\mathrm{d}x\\ {}\\int\\limits_{0}^{1}\\mathrm{d}y\\ {}\\left(x{\\cdot}y\\right)"
]
]
, testGroup "Algebraic manipulation"
@@ -139,6 +143,32 @@ tests = testGroup "Tests"
& continueExpr (⩵) (&~: 𝑥 :=: 2◝𝑝) |]
"x+y=x+x{\\cdot}\\left(1+x\\right)=2^{p}+2^{p}{\\cdot}\\left(1+2^{p}\\right)"
]
+ , testGroup "Juxtaposition"
+ [ [mkLaTeXSnip| 𝑚 + 𝑝⁀𝑞⁀𝑟 |]
+ "m+pqr"
+ , [mkLaTeXSnip| 𝑚 + 𝑝⁀(2+𝑞)⁀𝑟 |]
+ "m+p\\left(2+q\\right)r"
+ , [mkLaTeXSnip| 𝑚 + (𝑝␣𝑞␣𝑟) |]
+ "m+\\left(p\\ {}q\\ {}r\\right)"
+ , [mkLaTeXSnip| 𝑚 + (𝑝␣2+𝑞␣𝑟) |]
+ "m+\\left(p\\ {}2+q\\ {}r\\right)"
+ , [mkLaTeXSnip| 𝑚 + (𝑝<>𝑞<>𝑟) |]
+ "m+pqr"
+ , [mkLaTeXSnip| 𝑚 + (𝑝<>(2+𝑞)<>𝑟) |]
+ "m+\\left(p2+qr\\right)"
+ , [mkLaTeXSnip| 𝑚 * ((1+2)<>(3+4)) |]
+ "m{\\cdot}\\left(1+23+4\\right)"
+ ]
+ , testGroup "Misc"
+ [ [mkLaTeXSnip| 3*𝑧 - 1 |]
+ "3{\\cdot}z-1"
+ , [mkLaTeXSnip| 𝑎-𝑏+𝑐 |]
+ "a-b+c"
+ , [mkLaTeXSnip| (𝑥/2)|◞◝(𝑥⩵0,1) |]
+ "\\left.\\frac{x}{2}\\right|_{x=0}^{1}"
+ , TestCase (3 - 1 &~~! [ ㄒ-ㄗ ⩵ -(ㄗ-ㄒ) ])
+ "3 - 1 &~~! [ ㄒ-ㄗ ⩵ -(ㄗ-ㄒ) ]" "3-1= -\\left(1-3\\right)"
+ ]
]
@@ -169,7 +199,9 @@ evalTests = go False 1
return . (if hasHeader then id
else (("| Haskell | LaTeX | pdf |"
<>"\n| ---: | --- | :--- |\n")<>)) $
- "| "<>mconcat["`"<>Txt.pack (dropWhile (==' ') ecl)<>"` " | ecl<-lines ec]
+ "| "<>mconcat["`"
+ <>mkGithubtablesaveCode(Txt.pack (dropWhile (==' ') ecl))
+ <>"` " | ecl<-lines ec]
<>"| `"<>mkGithubtablesaveCode s
<>"` | ![pdflatex-rendered version of `"<>mkGithubtablesaveCode s
<>"`]("<>Txt.pack(snipName<.>"png")<>") |\n"