Talk at Lambda Conf June 9 2019 Boulder
Talk at Lambda Conf, June 9, 2019, Boulder, Colorado James Carlson, jxxcarlson@gmail. com The Mini. Latex Project Bring Latex to the Browser http: //minilatex. io
What is La. Te. X? (1) (2) $$ int_0^1 x^n dx = frac{1}{n+1} $$ begin{theorem} The indefinite integral of $e^x$ is $e^x + C$. end{theorem} Source Text ===> PDF Source Text ===> HTML Math. Jax for Math Mode Pandoc (Batch)
Live Editing Immediate Content Delivery Searchable Document Repository . . .
render How to? La. Te. X ------> HTML Typed functional programming Division of Labor (Math. Jax !) render = parse to AST, then render Parser combinators elm/parser
strong{Newton} says begin{theorem} The indefinite integral of $e^x$ is $e^x + C$. end{theorem} Parse AST Render
Start symbol Non terminal nodes Terminal nodes Sentence Subject Verb Object Alice eats oranges
Grammar Sentence Subject Verb Object Alice eats oranges Alice eats Object Alice eats oranges Sentence -> Subject Verb Object Subject -> Alice | Bob Verb -> eats | likes Object -> apples | oranges
Grammar = Production Rules Identifiers (1) Ident -> Alpha Tail (2) Tail -> "" | Alpha Tail | Num Tail (3) Alpha -> "a" | "b" |. . . (4) Num -> "0" | "1" |. . . Ident (1) -> Alpha Tail (3) -> "a" Tail (2) -> "a" Alpha Tail (3) -> "a" "b" Tail (2) -> "a" "b" Num Tail (4) -> "a" "b" "7" Tail -> "a" "b" "7" "" => "ab 7" (2)
What is the Grammar of Mini. La. Te. X?
Type of the AST type Latex. Expr = LXString | Inline. Math String | Display. Math String Once upon a time … $ a^2 + b^2 = c^2 $ $$ a^2 + b^2 = c^2 $$ | Macro String (List Latex. Expr) italic{Wow!} | Environment String Latex. Expr begin{foo} … end{foo} | Latex. List (List Latex. Expr) | Comment String | Item Latex. Expr | New. Command String Int Latex. Expr | LXError (List Dead. End) [a, b, c, … ] % la di dah do day! item whatever… newcommand{foo][1}{. . . } Oops!
Mini. La. Te. X Grammar Latex. Expr -> Inline. Math | Display. Math | Macro | LXString | Env | Newcommand |. . . Display. Math -> $$ math. Symbols+ $$ Inline. Math -> $ math. Symbols+ $ Macro -> Macro. Name Arg* WS Env env. Name -> begin{ env. Name } Latex. Expr end{ env. Name } Latex. List -> List Latex. Expr
strong{Newton} says AST begin{theorem} The indefinite integral of $e^x$ is $e^x + C$. Latex. List Macro Latex String end{theorem} Environment says strong Latex List theorem Latex List Latex String Inline Math Latex String Newton The indef. . e^x is e^x + C .
Parsing A kind of inverse of production ( ““ 4 2 …
Elementary parsers symbol “a“ : Parser ( ) > run ( symbol “a" ) "adx!3@" Ok ( ) Result List [Parser. Dead. End] ( ) > run (symbol "a") "Wdx!3@" Err […] Result List [Parser. Dead. End] ( ) float : Parser Float > run float "1. 2" Ok 1. 2 Result List [Parser. Dead. End] Float
spaces : Parser ( ) spaces = chomp. While (c -> c == ‘ ‘) > run spaces " " Ok ( ) succeed : a -> Parser a > run (succeed "a") "a" Ok "a" > run (succeed "a") "b" Ok "a"
Parser Combinators 22
Alternation one. Of : List (Parser a) -> Parser a one. Of [ symbol “a”, symbol “b” ] accepts "a. . . " "b. . . ", but not "c. . . "
Sequencing I ( |. ) : Parser a -> Parser b -> Parser a float |. spaces : Parser Float run (float |. spaces) "1. 2 abc" Ok 1. 2 Result (List Dead. End) Float
Sequencing II ( |= ) : Parser (a -> b) -> Parser a -> Parser b Example: parsing a Point type alias Point = { x : Float, y : Float } Point : Float -> Point succeed Point : Parser ( Float -> Point )
Points in real life: life "1. 3 4. 7" Grammar: Point -> Float Spaces Float parser. Point = succeed Point |= float |. spaces |= float run parser. Point "1. 0 3. 7" Ok { x = 1. 0, y = 3. 7 } Result (List Parser. Dead. End) Point
succeed Point Parser (F -> Pt) |= float Parser F |. spaces Parser ( ) |= float Parser F Parser (F -> Pt) Parser Pt
Yikes! we can read off the parser from the production!! Production Point -> Float Spaces Float parser. Point = succeed Point |= float |. spaces |= float
"(1. 3, 4. 7)" Point -> “(“ SP Float SP “, ” SP Float SP “)” point : Parser Point point = succeed Point |. symbol “(“ |. spaces |= float |. spaces |. symbol “, ” |. spaces |= float |. spaces |. symbol “)”
Top level parser Latex. Expr -> Display. Math | Inline. Math | Macro | Words | Env latex. Expr : Parser Latex. Expression latex. Expr = one. Of [ display. Math , inline. Math , macro , words , lazy (_ -> environment) ] 334 loc
Macro parser italic{Wow!} Macro -> Macro. Name Arg* WS macro : Parser ( ) -> Parser Latex. Expression macro ws. Parser = succeed Macro |= macro. Name |= item. List arg |. ws. Parser
environment : Parser Latex. Expression environment = env. Name |> and. Then environment. Body env. Name : Parser String env. Name = succeed identity = |. symbol "\begin{" |= word |. word "}"
environment. Body : String -> Parser Latex. Expression environment. Body env. Name = let end. Phrase = "\end{" ++ env. Name ++ "}" in succeed (Environment end. Phrase) |. ws |= (nonempty. Item. List latex. Expression) |> map Latex. List) |. ws |. symbol end. Phrase |. ws environment : Parser Latex. Expression environment = env. Name |> and. Then environment. Body
The M Word
Monads in Elm and. Then : (a -> Parser b) -> Parser a -> Parser b and. Then : (a -> M b) -> M a -> M b (>>=) : M a -> (a -> M b) -> M b
Testing suite : Test suite = describe "Mini. Latex Parser" [ do. Test "(1) Comment" (run latex. Expression "% A comment!n" (Ok (Comment "% A commentn")) [ do. Test "(1) Inline. Math" (run latex. Expression "$a^2 = 7$" (Ok (Inlin. Math "a^2 = 7")) [ do. Test "(1) Display. Math" (run latex. Expression "$$a^2 = 7$$" (Ok (Display. Math "a^2 = 7"))
Rendering
One rendering function per nonterminal symbol
render : Latex. State -> Latex. Expression -> Html msg render latex. State latex. Expression = case latex. Expression of Macro name opt. Args args -> render. Macro latex. State name opt. Args args Inline. Math str -> Html. span [] [one. Space, inline. Math str] Display. Math str -> display. Math str Environment name args body -> render. Environment latex. State name args body Latex. List latex. List render. Latex. List latex. State latex. List ETCETERA
render. Macro : Latex. State -> String -> List Latex. Expression -> Html msg render. Macro latex. State name opt. Args args = case Dict. get name render. Macro. Dict of Just f -> f latex. State opt. Args args Nothing -> case Dict. get name latex. State. macro. Dictionary of Nothing -> reproduce. Macro name latex. State args Just macro. Def -> let macro = Macro name opt. Args args expr = Macro. expand macro. Def in render latex. State expr
The full parse-render pipeline
Source text (1) => List of logical paragraphs : : FSM (2) => (Latex. State, List (List Latex. Expr)) : : Parse (3) => List (Html msg) : : Render (4) => Html msg : : Concatenate (5) => DOM : : Elm runtime (6) => DOM : : Mathjax. js
Computing Latex. State List. foldl: (a -> b) -> b -> List a -> b reducer : a -> b List. foldl (+) 0 [1, 2, 3, 4] => 10 input list accumulator Int -> Int
module Accumulator : state -> List a -> ( state, List b ) parse : Latex. State -> List String -> ( Latex. State, List (List Latex. Expression) ) parse latex. State paragraphs = paragraphs |> List. foldl parse. Reducer ( latex. State, [] ) reducer : a -> b a = String b = ( Latex. State, List (List Latex. Expression) ) state = Latex. State
parse. Reducer input. String ( latex. State, input. List ) = let parsed. Input = Parser. parse input. String new. Latex. State = latex. State. Reducer parsed. Input latex. State in ( new. Latex. State, input. List ++ [ parsed. Input ] )
Diffing u = text v = edited text u=axb v=ayb a = greatest common prefix b = greatest common suffix u’ = render u u’ = a’ x’ b’ Store a’ x’ b’ v’ = a' y' b' Only compute y'
Ingredients for success of project Expressive type system • AST • Accumulators Parser combinators (align with grammar) Optimizations (logical paragraphs, diffing) One language throughout Division of labor Elm is fast
Thanks!! minilatex. io
- Slides: 45