title |
---|
Hello World |
The first example will display the “Hello World” message. The program — HelloWorld1.elm — is presented below.
% HelloWorld1.elm import Text main = Text.plainText "Hello World"
The first line — import Text
— imports the Text
module, allowing
us to reference its functions in our program. We need the import,
since our program uses the plainText
function that is defined in
that module. We reference a function by prefixing the function name
with the module name and the dot.
The meaning of an Elm program is defined by the main
function. Every
program needs to define one. To define a function, we provide its name
followed by the =
character and the function body. Functions may
have parameters, which are declared between the function name and the
equals sign. The main
function does not have parameters.
The body of our function contains a call to the Text.plainText
function
with one argument — the “Hello World” string. The string is delimited
with the quotation marks. The function argument is separated from the
function name by a single space (more spaces would do as well). Elm
does not require enclosing function arguments in parenthesis.
Before the program can be run, it needs to be compiled. If you create a directory with the HelloWorld1.elm program in it, you can use the following command to compile:
elm-make HelloWorld1.elm --output HelloWorld1.html
When you run that command the first time in that directory, it needs
to perform certain setup steps: download, configure and compile
standard library files. Before doing that, it asks for
permission. You should answer y
to proceed. The command will create
a file called elm-package.json and a folder called elm-stuff in
the current directory.
$ elm-make HelloWorld1.elm --output HelloWorld1.html
Some new packages are needed. Here is the upgrade plan.
Install:
elm-lang/core 1.0.0
Do you approve of this plan? (y/n) y
Downloading elm-lang/core
Packages configured successfully!
Compiled 33 files
Successfully generated HelloWorld1.html
When the program is compiled again in the same folder, the setup is not performed again.
$ elm-make HelloWorld1.elm --output HelloWorld1.html
Successfully generated HelloWorld1.html
The compiler builds the HelloWorld1.html file. You can now open that file using your favorite browser. Click here to see the program output.
The elm-package.json file contains information related to the Elm project. Its content may look like this:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/USER/PROJECT.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "1.0.0 <= v < 2.0.0"
}
}
You may change its content manually. It can also be modified by elm
tools: elm-make
, that we have just met, and elm-package
, that we
will meet soon.
Our program shows the “Hello World” message using the default font. What if we want to use a different font? The HelloWorld2.elm program, presented below, shows one way of styling the message in a custom way. You can see it in action here.
% HelloWorld2.elm module HelloWorld2 where
import Color (blue)
import Graphics.Element (..)
import Text
main : Element
main =
Text.fromString "Hello World"
|> Text.color blue
|> Text.italic
|> Text.bold
|> Text.height 60
|> Text.leftAligned
The program begins with a module declaration. The declaration consists
of the module
keyword followed by the module name and the where
keyword, which marks the beginning of the module body. If a program
does not start with the module declaration — like our
HelloWorld1.elm program — the module called Main
is implicitly
assumed.
In order to add style to our message, we use functions from the Text
module from Elm’s standard library. To make that possible, we import
the Text
module.
Instead of importing a module, we can alternatively import its
members, which introduces those members to the current namespace. We
do this by following the module name with a list of imported values
enclosed in parentheses. The second import statement imports one member
(blue
) from the Color
module. Alternatively, we can replace the
list with two dot characters, thus imporing everything that the module
exported. The third import is using that possiblity, importing
everything that the Graphics.Element
exported, including the
Element
type.
The main
function in this program has a type declaration (or in
other words, its signature). Signatures are optional and we did not
have it in our first program. In fact, the first versions of Elm did
not even provide a way of declaring function signatures. It is however
often a good idea to add them to our programs, as a way of documenting
its functions. The type declaration is given in the line preceding its
definition, and it consists of the function name followed by the colon
character and the function type. Our declaration states, that the
main
function does not take any parameters and returns a value of
the Element
type. Elements are “things” that Elm’s runtime know how
to display. The Element
type name starts with a capital letter. In
fact, all type names in Elm must start with a capital letter.
The function definition must be consistent with its
signature. Otherwise Elm will complain by printing a compilation
error. For example, if we temporarily change the function type
declaration to main : String
in our program (such a declaration
implies that the result of the main
function is a string), the
compiler would complain:
$ elm-make HelloWorld2.elm --output HelloWorld2.html
Error in HelloWorld2.elm:
Type mismatch between the following types between lines 8 and 13:
Graphics.Element.Element
String
It is related to the following expression:
(((((Text.fromString "Hello World") |> (Text.color blue))
|> Text.italic)
|> Text.bold)
|> (Text.height 60))
|> Text.leftAligned
The main
function body contains a set of expressions separated with
the |>
operators. What are they? They are in fact a way of function
application. If we have a function f
taking one argument a
, we can
call it using the f a
syntax. But we can also swap the argument and
the function name and add the |>
operator, like so:
a |> f
For greater readability, the program includes new line characters
before the |>
operators.
The body of our main
function consists of several function
applications chained together. In fact, it could alternatively have
been written in the following way:
main = Text.leftAligned (Text.height 60 (Text.bold (Text.italic (Text.color blue (Text.fromString "Hello World")))))
Let’s now analyze what the function does. It starts with a call to the
fromString
function, which transforms a string into a value of type
Text
. It’s type looks like this:
fromString : String -> Text
The ->
arrow separates the function argument type from the result
type. The Text
value created by the fromString
function has
certain default properties, like color or font size. The function
calls following the fromString
call modify those properties,
creating new Text
values, which differ in some respect from the old
value.
It is important to keep in mind, that Elm functions do not modify their arguments in place. So, whenever I write about “modifying” the function argument in some way, it is really a shortcut for saying that the function returns a copy of the argument, which differs from the original argument in some way.
The color
function let us specify the color of the Text
value. It
takes two arguments: the color and the text value and it returns a new
text value. Here is it’s type:
color : Color -> Text -> Text
Notice how the ->
operator not only separates the result type of the
function from its arguments, but the same operator is also used for
separatting one argument from the other.
The italic
and bold
functions, as their names suggest, modify the
text to be italic and bold. The call to the height
function sets the
text height to 60 pixels. Like color
, it is also a two-argument
function:
height : Float -> Text -> Text
Finally, the leftAligned
function turns a Text
value into an
Element
that can be displayed:
leftAligned : Text -> Element
Let us get back to the signatures of the color
and height
functions. Why is it, that the same operator — the ->
arrow — is
used for what might seem to be two different things: to separate one
function argument from the other and in the same time to separate the
arguments from the function result type? In fact, stricly speaking,
all Elm functions can only take at most one argument. The color
function, which can in many circumstances be treated just as a
function taking two arguments, is more formally speaking a
one-argument function taking an argument of the Color
type, that
returns another one-argument function, taking an argument of the
Text
type, which in turn returns the result of type Text
. It might
seem to be a small technical distinction only and in many situtions it
can be ignored. However, it also allows us to use a useful programming
technique of partially applying a function. Consider the
HelloWorld3.elm program, which displays the same
text that HelloWorld2.elm does, but is written in
a slightly different way.
% HelloWorld3.elm module HelloWorld3 where
import Color (blue)
import Graphics.Element (..)
import Text as T
makeBlue : T.Text -> T.Text
makeBlue = T.color blue
main : Element
main =
T.fromString "Hello World"
|> makeBlue
|> T.italic
|> T.bold
|> T.height 60
|> T.leftAligned
The first difference is the use of a qualified import. By suffixing
the import statement for the Text
module with the as T
clause, we
make the Text
module available with the qualified name T
instead
of the full name Text
. The references to symbols defined in that
module must now be prefixed with T.
.
The main
function differs from its equivalent in the previous
program by using the auxiliary function makeBlue
instead of directly
calling the color
function with the blue
argument.
Let us analyze the makeBlue
function. Its body consists of applying
the blue
value (of type Color
) as the argument of the color
function. Let us recall the signature of color
:
color : Color -> Text -> Text
We have applied the first argument, but not the second. The result of
that application is a Text -> Text
function. We have thus converted
a two-argument function color
into a one-argument function
makeBlue
, that transforms a Text
value into another Text
value,
which has its color set to blue.
The Text
module is part of the Elm standard library. We have so far
only used a small subset of its functions, but it contains more of
them. If you want to verify what are the functions that a module
provide, try to find the module on the
package.elm-lang.org/ web site.
The final example presented in this chapter — HelloWorld4.elm — shows a web page, the content of which is specified using the Markdown format. See the program output here.
% HelloWorld4.elm module HelloWorld4 where
import Markdown
main = Markdown.toElement \"\"\"
# Hello World
This is the output of the *HelloWorld4.elm* program.
---
\"\"\"
The body of the main
function contains a call to the
Markdown.toElement function with one argument — a string containing
markdown syntax. The string is delimited with triple quotation mark
characters.
The line starting with a single hash #
character is displayed as a
header (using the h1
HTML tag) line. The words enclosed in
asterisks are displayed in italic. Finally, the three consecutive
dash characters are showed as a horizontal line. Our program only uses
a few selected Markdown features. You can read about others on the
Markdown Syntax
web page.
The Markdown
module does not belong to the Elm standard library. It
belongs to the evancz/elm-markdown package. We can install the
package with the following command:
$ elm-package install evancz/elm-markdown
To install evancz/elm-markdown I would like to add the following
dependency to elm-package.json:
"evancz/elm-markdown": "1.1.1 <= v < 2.0.0"
May I add that to elm-package.json for you? (y/n) y
Some new packages are needed. Here is the upgrade plan.
Install:
evancz/elm-html 1.0.0
evancz/elm-markdown 1.1.1
evancz/virtual-dom 1.0.0
Do you approve of this plan? (y/n) y
Downloading evancz/elm-html
Downloading evancz/elm-markdown
Downloading evancz/virtual-dom
Packages configured successfully!
The command asked two questions and installed the package. It also modified the elm-package.json file from the current folder:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/USER/PROJECT.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "1.0.0 <= v < 2.0.0",
"evancz/elm-markdown": "1.1.1 <= v < 2.0.0"
}
}
Notice the additional line in the dependencies section. We can now
compile our program using elm-make
:
elm-make HelloWorld4.elm --output HelloWorld4.html
The next chapter will show you how to make arithmetic calculations and draw simple pictures. It will also present another tool provided by Elm — the REPL.