on master help sign in
Expose fewer internal functions, making more information available only through `toHtml :: String -> Html` and `toParts :: String -> (Html, String, String)`. Make the required changes to dependent files. Yesod.hs still needs one fix though.
commita6cf0d28157efbf4480fe6901a9d42893ea42805 authorevancz <info@elm-lang.org> dateTue 29 May 2012, 13:25 (14 years ago) parent1600aae
11 files changed+234−236
elm-server/Server.hs+2−2 elm-server/elm-server.cabal+2−2 elm-yesod/Language/Elm/Yesod.hs+11−31 elm-yesod/elm-yesod.cabal+2−2 elm/Elm.cabal+22−23 elm/src/Language/Elm/CompileToJS.hs → elm/src/CompileToJS.hs+2−2 elm/src/Compiler.hs+2−2 elm/src/Language/Elm/ExtractNoscript.hs → elm/src/ExtractNoscript.hs+1−1 elm/src/Language/Elm/GenerateHtml.hs → elm/src/GenerateHtml.hs+53−52 elm/src/Language/Elm/Initialize.hs → elm/src/Initialize.hs+106−106 elm/src/Language/Elm.hs+31−13
elm-server/Server.hs+2−2
@@ -7,7 +7,7 @@ import Data.List (isPrefixOf, isSuffixOf)
77import Happstack.Server
88import Happstack.Server.Compression
99import System.Environment
10−import Language.Elm
10+import qualified Language.Elm as Elm
1111
1212serve :: String -> IO ()
1313serve libLoc = do
@@ -25,7 +25,7 @@ serveElm libLoc fp = do
2525 let ('/':path) = fp
2626 guard (".elm" `isSuffixOf` path)
2727 content <- liftIO (readFile path)
28− ok . toResponse $ generateHtml libLoc (pageTitle path) content
28+ ok . toResponse $ Elm.toHtml libLoc (pageTitle path) content
2929
3030
3131main = getArgs >>= parse
elm-server/elm-server.cabal+2−2
@@ -1,5 +1,5 @@
11Name: Elm-server
2−Version: 0.1.1.8
2+Version: 0.1.2
33Synopsis: The Elm language server.
44Description: This package provides a standalone, Happstack-based Elm server.
55
@@ -35,4 +35,4 @@ Executable elm-server
3535 HTTP >= 4000,
3636 happstack-server == 7.0.2,
3737 deepseq,
38− Elm >= 0.1.1.8
38+ Elm >= 0.1.2
elm-yesod/Language/Elm/Yesod.hs+11−31
@@ -15,42 +15,22 @@
1515
1616 A full example implementation is provided in the examples folder of the Elm github repository.
1717-}
18−module Language.Elm.Yesod (generateWidget) where
18+module Language.Elm.Yesod (toWidget) where
1919
2020import Text.Blaze (preEscapedToMarkup)
2121import Text.Hamlet
2222import Text.Julius
23−import Text.Lucius
23+import Text.Cassius
2424import Yesod.Widget
25+import Language.Elm
2526
26−import Language.Elm.Initialize
27−import Language.Elm.CompileToJS
28−import Language.Elm.ExtractNoscript
29−
30−css = [lucius|
31−* { padding:0; margin:0;
32−hyphens: auto; -moz-hyphens: auto;
33−-webkit-hyphens: auto; -ms-hyphens: auto;}
34−body { font-family: Arial; }
35−a:link, a:visited, a:active { text-decoration: none}
36−a:hover {text-decoration: underline; color: #ff8f12;}
37−|]
38−
39−-- |generateWidget takes some Elm code in String format and produces a widget. Usage example:
27+-- |toWidget takes some Elm code in String format and produces a widget. Usage example:
4028--
41−-- > generateWidget [elmFile|elm-source/somePage.elm|]
42−generateWidget :: String -- ^ The Elm source code
43− -> GWidget sub master ()
44−generateWidget source =
45− let expr = initialize source
46− js = compileToJS expr
47− noscript = either id extract expr
48− in do toWidgetHead css
29+-- > toWidget [elmFile|elm-source/somePage.elm|]
30+toWidget :: String -- ^ The Elm source code
31+ -> GWidget sub master ()
32+toWidget source =
33+ let (html, css, js) = toParts source
34+ in do toWidgetHead [cassius| css |]
4935 toWidgetHead [julius| #{js} |]
50− [whamlet|
51−<div #widthChecker style="width:100%; height:1px; position:absolute; top:-1px;">
52−<span #content>
53−<script type="text/javascript">
54− Dispatcher.initialize()
55−<noscript>^{preEscapedToMarkup noscript}
56−|]
36+ [whamlet| ^{html} |]
elm-yesod/elm-yesod.cabal+2−2
@@ -1,5 +1,5 @@
11Name: Elm-yesod
2−Version: 0.1.1.8
2+Version: 0.1.2
33Synopsis: The Elm language Yesod compatibility module.
44Description: This module provides a simple function to embed Elm code
55 as a Yesod widget.
@@ -28,7 +28,7 @@ Library
2828 exposed-modules: Language.Elm.Yesod
2929 Build-depends: base >=4.2 && <5,
3030 blaze-markup == 0.5.*,
31− Elm >= 0.1.1.8,
31+ Elm >= 0.1.2,
3232 yesod-core >= 1,
3333 hamlet,
3434 shakespeare-css,
elm/Elm.cabal+22−23
@@ -22,34 +22,37 @@ Category: Compiler, Language
2222Build-type: Simple
2323
2424Extra-source-files: README.md
25−Cabal-version: >=1.6
25+Cabal-version: >=1.8
2626
2727source-repository head
2828 type: git
2929 location: git://github.com/evancz/Elm.git
3030
31−Executable elm
32− -- .hs or .lhs file containing the Main module.
33− Main-is: Compiler.hs
34− Hs-Source-Dirs: src, src/Parse, src/Types, src/Language
31+Library
32+ exposed-modules: Language.Elm
33+ ghc-options: -O2
34+ Hs-Source-Dirs: src, src/Parse, src/Types
3535 other-modules: Ast,
36+ CompileToJS,
37+ ExtractNoscript,
38+ GenerateHtml,
39+ Guid,
40+ Initialize,
41+ Rename,
3642 Binop,
3743 Combinators,
38− Constrain,
39− Guid,
40− Hints,
4144 Lexer,
4245 ParsePatterns,
4346 Parser,
4447 ParserLib,
4548 ParseTypes,
46− Rename,
4749 Tokens,
4850 Types,
51+ Constrain,
52+ Hints,
4953 Types,
5054 Unify
51−
52− ghc-options: -O2
55+
5356 Build-depends: base >=4.2 && <5,
5457 containers >= 0.3,
5558 transformers >= 0.2,
@@ -59,16 +62,16 @@ Executable elm
5962 blaze-markup == 0.5.1.*,
6063 deepseq
6164
62−Library
63− exposed-modules: Language.Elm,
64− Language.Elm.CompileToJS,
65− Language.Elm.ExtractNoscript,
66− Language.Elm.Initialize,
67− Language.Elm.GenerateHtml,
68− Language.Elm.Quasi
65+Executable elm
66+ Main-is: Compiler.hs
67+ ghc-options: -O2
6968 Hs-Source-Dirs: src, src/Parse, src/Types
7069 other-modules: Ast,
70+ CompileToJS,
71+ ExtractNoscript,
72+ GenerateHtml,
7173 Guid,
74+ Initialize,
7275 Rename,
7376 Binop,
7477 Combinators,
@@ -91,8 +94,4 @@ Library
9194 parsec >= 3.1.1,
9295 blaze-html == 0.5.0.*,
9396 blaze-markup == 0.5.1.*,
94− deepseq,
95− template-haskell,
96− haskell-src-meta == 0.5.*,
97− text,
98− attoparsec == 0.10.*
97+ deepseq
elm/src/Language/Elm/CompileToJS.hs → elm/src/CompileToJS.hsrenamed+2−2
@@ -1,5 +1,5 @@
11
2−module Language.Elm.CompileToJS (compile, compileToJS) where
2+module CompileToJS (compile, compileToJS) where
33
44import Ast
55import Control.Monad (liftM,(<=<),join)
@@ -7,7 +7,7 @@ import Data.Char (isAlpha)
77import Data.List (intercalate,sortBy)
88import Data.Map (toList)
99
10−import Language.Elm.Initialize
10+import Initialize
1111
1212
1313compile = (return . addMain . toJS) <=< initialize
elm/src/Compiler.hs+2−2
@@ -1,8 +1,8 @@
11module Main where
22
33import Data.List (isPrefixOf)
4−import Language.Elm.CompileToJS
5−import Language.Elm.GenerateHtml
4+import CompileToJS
5+import GenerateHtml
66import System.Environment
77import Text.Blaze.Html.Renderer.String (renderHtml)
88
elm/src/Language/Elm/ExtractNoscript.hs → elm/src/ExtractNoscript.hsrenamed+1−1
@@ -1,5 +1,5 @@
11
2−module Language.Elm.ExtractNoscript (extract) where
2+module ExtractNoscript (extract) where
33
44import Ast
55
elm/src/Language/Elm/GenerateHtml.hs → elm/src/GenerateHtml.hsrenamed+53−52
@@ -1,52 +1,53 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−module Language.Elm.GenerateHtml (generateHtml) where
3−
4−import Text.Blaze (preEscapedToMarkup)
5−import Text.Blaze.Html (Html)
6−import qualified Text.Blaze.Html5 as H
7−import Text.Blaze.Html5 ((!))
8−import qualified Text.Blaze.Html5.Attributes as A
9−
10−import Language.Elm.Initialize
11−import Language.Elm.CompileToJS
12−import Language.Elm.ExtractNoscript
13−
14−css = preEscapedToMarkup $
15− ("* { padding:0; margin:0; \
16− \hyphens: auto; -moz-hyphens: auto;\
17− \ -webkit-hyphens: auto; -ms-hyphens: auto; }\
18− \body { font-family: Arial; }\
19− \a:link {text-decoration: none}\
20− \a:visited {text-decoration: none}\
21− \a:active {text-decoration: none}\
22− \a:hover {text-decoration: underline; color: #ff8f12;}" :: String)
23−
24−makeScript :: String -> H.Html
25−makeScript s = H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ ""
26−
27−-- |This function compiles Elm code into simple HTML.
28−--
29−-- Usage example:
30−--
31−-- > generateHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|]
32−generateHtml :: String -- ^ Location of elm-min.js as expected by the browser
33− -> String -- ^ The page title
34− -> String -- ^ The elm source code.
35− -> Html
36−generateHtml libLoc title source =
37− let expr = initialize source
38− js = compileToJS expr
39− noscript = either id extract expr
40− in
41− H.docTypeHtml $ do
42− H.head $ do
43− H.meta ! A.charset "UTF-8"
44− H.title . H.toHtml $ title
45− makeScript libLoc
46− H.script ! A.type_ "text/javascript" $ preEscapedToMarkup js
47− H.style ! A.type_ "text/css" $ css
48− H.body $ do
49− H.div ! A.id "widthChecker" ! A.style "width:100%; height:1px; position:absolute; top:-1px;" $ ""
50− H.span ! A.id "content" $ ""
51− H.script ! A.type_ "text/javascript" $ "Dispatcher.initialize()"
52− H.noscript $ preEscapedToMarkup noscript
1+{-# LANGUAGE OverloadedStrings #-}
2+module GenerateHtml (generateHtml, body, css) where
3+
4+import Text.Blaze (preEscapedToMarkup)
5+import Text.Blaze.Html (Html)
6+import qualified Text.Blaze.Html5 as H
7+import Text.Blaze.Html5 ((!))
8+import qualified Text.Blaze.Html5.Attributes as A
9+
10+import Initialize
11+import CompileToJS
12+import ExtractNoscript
13+
14+css = "* { padding:0; margin:0; \
15+ \hyphens: auto; -moz-hyphens: auto;\
16+ \ -webkit-hyphens: auto; -ms-hyphens: auto; }\
17+ \body { font-family: Arial; }\
18+ \a:link {text-decoration: none}\
19+ \a:visited {text-decoration: none}\
20+ \a:active {text-decoration: none}\
21+ \a:hover {text-decoration: underline; color: #ff8f12;}"
22+
23+makeScript :: String -> H.Html
24+makeScript s = H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ ""
25+
26+-- |This function compiles Elm code into simple HTML.
27+--
28+-- Usage example:
29+--
30+-- > generateHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|]
31+generateHtml :: String -- ^ Location of elm-min.js as expected by the browser
32+ -> String -- ^ The page title
33+ -> String -- ^ The elm source code.
34+ -> Html
35+generateHtml libLoc title source =
36+ let expr = initialize source
37+ js = compileToJS expr
38+ noscript = either id extract expr
39+ in
40+ H.docTypeHtml $ do
41+ H.head $ do
42+ H.meta ! A.charset "UTF-8"
43+ H.title . H.toHtml $ title
44+ makeScript libLoc
45+ H.script ! A.type_ "text/javascript" $ preEscapedToMarkup js
46+ H.style ! A.type_ "text/css" $ preEscapedToMarkup (css :: String)
47+ H.body $ body noscript
48+
49+body noscript = do
50+ H.div ! A.id "widthChecker" ! A.style "width:100%; height:1px; position:absolute; top:-1px;" $ ""
51+ H.span ! A.id "content" $ ""
52+ H.script ! A.type_ "text/javascript" $ "Dispatcher.initialize()"
53+ H.noscript $ preEscapedToMarkup noscript
elm/src/Language/Elm/Initialize.hs → elm/src/Initialize.hsrenamed+106−106
@@ -1,107 +1,107 @@
1−module Language.Elm.Initialize (initialize) where
2−
3−import Ast
4−import Control.Arrow (first, second)
5−import Control.Monad
6−import Data.Char (isAlpha)
7−import Data.Maybe (mapMaybe)
8−import Data.Either (rights)
9−import Lexer
10−import Parser (toExpr,toDefs)
11−import Rename (rename)
12−
13−import Unify
14−import Hints
15−
16−{--
17−initialize str = do
18− (expr, hints') <- toDefs =<< tokenize str
19− let expr' = rename expr
20− subs <- unify (liftM2 (++) hints hints') expr'
21− return (seq subs expr')
22−--}
23−
24−initialize str = do
25− (expr, hints') <- toDefs =<< tokenize str
26− let expr' = rename expr
27− subs <- unify (liftM2 (++) hints hints') expr'
28− let init = simp_loop expr'
29− return (seq subs init)
30−
31−simp_loop exp = if exp == exp' then exp' else simp_loop exp'
32− where exp' = simp exp
33−
34−simp expr =
35− let f = simp in
36− case expr of
37− Range e1 e2 -> Range (f e1) (f e2)
38− Binop op e1 e2 -> simp_binop op (f e1) (f e2)
39− Lambda x e -> Lambda x (f e)
40− App e1 e2 -> App (f e1) (f e2)
41− If e1 e2 e3 -> simp_if (f e1) (f e2) (f e3)
42− Let defs e -> Let (map (second f) defs) (f e)
43− Data name es -> Data name (map f es)
44− Case e cases -> Case (f e) (map (second f) cases)
45− _ -> expr
46−
47−simp_if (Boolean b) e2 e3 = if b then e2 else e3
48−simp_if a b c = If a b c
49−
50−simp_binop "mod" (Number n) (Number m) = Number (mod n m)
51−simp_binop "mod" e1 e2 = Binop "mod" e1 e2
52−simp_binop str e1 e2
53− | isAlpha (head str) || '_' == head str = App (App (Var str) e1) e2
54− | otherwise = binop str e1 e2
55−
56−binop op (Number n) (Number m) = f n m
57− where f a b = case op of
58− { "+" -> Number $ (+) a b
59− ; "-" -> Number $ (-) a b
60− ; "*" -> Number $ (*) a b
61− --; "/" -> Number $ div a b
62− ; "<" -> Boolean $ a < b
63− ; ">" -> Boolean $ a < b
64− ; "<=" -> Boolean $ a <= b
65− ; ">=" -> Boolean $ a >= b
66− ; "==" -> Boolean $ a == b
67− ; "/=" -> Boolean $ a /= b
68− ; _ -> Binop op (Number n) (Number m) }
69−
70−binop "-" e (Number 0) = e
71−binop "+" (Number 0) e = e
72−binop "+" (Number n) (Binop "+" (Number m) e) = binop "+" (Number (n+m)) e
73−binop "+" (Number n) (Binop "+" e (Number m)) = binop "+" (Number (n+m)) e
74−
75−binop "/" e (Number 1) = e
76−binop "*" (Number 0) e = Number 0
77−binop "*" (Number 1) e = e
78−binop "*" (Number n) (Binop "*" (Number m) e) = binop "*" (Number (n*m)) e
79−binop "*" (Number n) (Binop "*" e (Number m)) = binop "*" (Number (n*m)) e
80−
81−binop "+" e (Number n) = binop "+" (Number n) e
82−binop "*" e (Number n) = binop "*" (Number n) e
83−
84−binop op (Boolean n) (Boolean m) = f n m
85− where f a b = case op of { "&&" -> Boolean $ (&&) n m
86− ; "||" -> Boolean $ (||) n m
87− ; _ -> Binop op (Boolean n) (Boolean m) }
88−
89−binop "&&" (Boolean True) e = e
90−binop "&&" (Boolean False) e = Boolean False
91−binop "||" (Boolean True) e = Boolean True
92−binop "||" (Boolean False) e = e
93−
94−binop op e (Boolean n) = binop op (Boolean n) e
95−
96−binop ":" h t = cons h t
97−binop "++" (Str s1) (Str s2) = Str $ s1 ++ s2
98−binop "++" (Str s1) (Binop "++" (Str s2) e) = Binop "++" (Str $ s1 ++ s2) e
99−binop "++" (Binop "++" e (Str s1)) (Str s2) = Binop "++" e (Str $ s1 ++ s2)
100−binop "++" (Data "Nil" []) e = e
101−binop "++" e (Data "Nil" []) = e
102−binop "++" (Data "Cons" [h,t]) e = Data "Cons" [h, binop "++" t e]
103−
104−binop "$" e1 e2 = App e1 e2
105−
106−binop op e1 e2 = Binop op e1 e2
1+module Initialize (initialize) where
2+
3+import Ast
4+import Control.Arrow (first, second)
5+import Control.Monad
6+import Data.Char (isAlpha)
7+import Data.Maybe (mapMaybe)
8+import Data.Either (rights)
9+import Lexer
10+import Parser (toExpr,toDefs)
11+import Rename (rename)
12+
13+import Unify
14+import Hints
15+
16+{--
17+initialize str = do
18+ (expr, hints') <- toDefs =<< tokenize str
19+ let expr' = rename expr
20+ subs <- unify (liftM2 (++) hints hints') expr'
21+ return (seq subs expr')
22+--}
23+
24+initialize str = do
25+ (expr, hints') <- toDefs =<< tokenize str
26+ let expr' = rename expr
27+ subs <- unify (liftM2 (++) hints hints') expr'
28+ let init = simp_loop expr'
29+ return (seq subs init)
30+
31+simp_loop exp = if exp == exp' then exp' else simp_loop exp'
32+ where exp' = simp exp
33+
34+simp expr =
35+ let f = simp in
36+ case expr of
37+ Range e1 e2 -> Range (f e1) (f e2)
38+ Binop op e1 e2 -> simp_binop op (f e1) (f e2)
39+ Lambda x e -> Lambda x (f e)
40+ App e1 e2 -> App (f e1) (f e2)
41+ If e1 e2 e3 -> simp_if (f e1) (f e2) (f e3)
42+ Let defs e -> Let (map (second f) defs) (f e)
43+ Data name es -> Data name (map f es)
44+ Case e cases -> Case (f e) (map (second f) cases)
45+ _ -> expr
46+
47+simp_if (Boolean b) e2 e3 = if b then e2 else e3
48+simp_if a b c = If a b c
49+
50+simp_binop "mod" (Number n) (Number m) = Number (mod n m)
51+simp_binop "mod" e1 e2 = Binop "mod" e1 e2
52+simp_binop str e1 e2
53+ | isAlpha (head str) || '_' == head str = App (App (Var str) e1) e2
54+ | otherwise = binop str e1 e2
55+
56+binop op (Number n) (Number m) = f n m
57+ where f a b = case op of
58+ { "+" -> Number $ (+) a b
59+ ; "-" -> Number $ (-) a b
60+ ; "*" -> Number $ (*) a b
61+ --; "/" -> Number $ div a b
62+ ; "<" -> Boolean $ a < b
63+ ; ">" -> Boolean $ a < b
64+ ; "<=" -> Boolean $ a <= b
65+ ; ">=" -> Boolean $ a >= b
66+ ; "==" -> Boolean $ a == b
67+ ; "/=" -> Boolean $ a /= b
68+ ; _ -> Binop op (Number n) (Number m) }
69+
70+binop "-" e (Number 0) = e
71+binop "+" (Number 0) e = e
72+binop "+" (Number n) (Binop "+" (Number m) e) = binop "+" (Number (n+m)) e
73+binop "+" (Number n) (Binop "+" e (Number m)) = binop "+" (Number (n+m)) e
74+
75+binop "/" e (Number 1) = e
76+binop "*" (Number 0) e = Number 0
77+binop "*" (Number 1) e = e
78+binop "*" (Number n) (Binop "*" (Number m) e) = binop "*" (Number (n*m)) e
79+binop "*" (Number n) (Binop "*" e (Number m)) = binop "*" (Number (n*m)) e
80+
81+binop "+" e (Number n) = binop "+" (Number n) e
82+binop "*" e (Number n) = binop "*" (Number n) e
83+
84+binop op (Boolean n) (Boolean m) = f n m
85+ where f a b = case op of { "&&" -> Boolean $ (&&) n m
86+ ; "||" -> Boolean $ (||) n m
87+ ; _ -> Binop op (Boolean n) (Boolean m) }
88+
89+binop "&&" (Boolean True) e = e
90+binop "&&" (Boolean False) e = Boolean False
91+binop "||" (Boolean True) e = Boolean True
92+binop "||" (Boolean False) e = e
93+
94+binop op e (Boolean n) = binop op (Boolean n) e
95+
96+binop ":" h t = cons h t
97+binop "++" (Str s1) (Str s2) = Str $ s1 ++ s2
98+binop "++" (Str s1) (Binop "++" (Str s2) e) = Binop "++" (Str $ s1 ++ s2) e
99+binop "++" (Binop "++" e (Str s1)) (Str s2) = Binop "++" e (Str $ s1 ++ s2)
100+binop "++" (Data "Nil" []) e = e
101+binop "++" e (Data "Nil" []) = e
102+binop "++" (Data "Cons" [h,t]) e = Data "Cons" [h, binop "++" t e]
103+
104+binop "$" e1 e2 = App e1 e2
105+
106+binop op e1 e2 = Binop op e1 e2
107107--}
elm/src/Language/Elm.hs+31−13
@@ -1,21 +1,39 @@
1−{- | This module re-exports the modules necessary for compiling Elm code into the
1+{- | This module exports the functions necessary for compiling Elm code into the
22 respective HTML, JS and CSS code.
33
4− It also provides a predefined generateHtml function for use with the Blaze markup library
4+ It also provides a predefined compileToHtml function for use with the Blaze markup library
55 as well as a simple QuasiQuoter for embedding literal elm code in a Haskell file.
66
77 The documentation for the Elm language is available at <http://elm-lang.org/Documentation.elm>
88-}
99module Language.Elm (
10− module Language.Elm.Initialize,
11− module Language.Elm.CompileToJS,
12− module Language.Elm.ExtractNoscript,
13− generateHtml,
14− elm,
15− elmFile) where
10+ toHtml,
11+ toParts) where
1612
17−import Language.Elm.CompileToJS
18−import Language.Elm.ExtractNoscript
19−import Language.Elm.Initialize
20−import Language.Elm.GenerateHtml
21−import Language.Elm.Quasi
13+import CompileToJS
14+import ExtractNoscript
15+import GenerateHtml
16+import Initialize
17+import Text.Blaze.Html (Html)
18+
19+-- |This function compiles Elm code into a full HTML page.
20+--
21+-- Usage example:
22+--
23+-- > toHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|]
24+toHtml :: String -- ^ Location of elm-min.js as expected by the browser
25+ -> String -- ^ The page title
26+ -> String -- ^ The elm source code.
27+ -> Html
28+toHtml = generateHtml
29+
30+-- |This function compiles Elm code to three separate parts: HTML, CSS,
31+-- and JavaScript. The HTML is only the contents of the body, so the three
32+-- parts must be combined in a basic HTML skeleton.
33+toParts :: String -- ^ The Elm source code.
34+ -> (Html, String, String) -- ^ HTML, CSS, and JavaScript in that order.
35+toParts source = (html, css, js)
36+ where expr = initialize source
37+ js = compileToJS expr
38+ html = body $ either id extract expr
39+