Elm-Lang syntax and basic concepts
In less than 10 mins
Ellie
If you are new to elm and just want to play around with the code quickly you can go to Ellie it’s just like JSfiddle is for JavaScript.
Comments
-- a single line comment {- a multiline comment
{- nestend comment -}
-}
Data Types
-- Boolean
True, False-- Int
42-- Float
3.14 -- Char
'a' -- String
"abc" -- multi-line String
"""
This is useful for holding JSON or other content that has "quotation marks".
"""-- List
[1, 2, 3]
["string1", "string2"]-- Tuples
-- Tip: try to use tuples for 2 to 3 variables
-- if you need more than 3 variables in a tuple
-- I recommend to use records
(True, 11, "Foo Bar")
(3.14, 9)-- Record
{ name = "foo bar", age = 28, canVote = True}
Conditional Statements
If..else statements
Please note that elm is not a flexible language, there can not be a if
statement without else
.
if (condition == True) then
1
else
0
Also the returned value by each branch of if else should be of the same type.
// WRONG: would give you a compile error
if (condition == True) then
"count"
else
0
if..else if..else statement
if (weather == "rainy") then
"Pickup the umbrella."
else if (text == "sunny")
"Pickup the sunglasses."
else
"Do you live on the planet Mercury?"
It goes without saying each branch returns the same value of same data type, and also else
is not optional, we are supposed to handle all the possible outcomes.
case statements
I have used case statements more than if else because they are much easier to write and handle the test cases and there’s one more benefit of getting parameters associated to types which we’ll see in Custom Types.
case n of
0 ->
1
1 ->
1
_ ->
fib (n-1) + fib (n-2)
_
represents same as else
in if..else or the default
of the cases.
-- Using case with tuples
-- Following case performs the logical OR operation case (flag1, flag2) of
(True, True)->
True
(True, False) ->
True
(False, True) ->
True
_ ->
False-- We could have also written the last condition as
(_, _) ->
False
Records
Records are not exactly but somewhat similar to JavaScript objects with following rules
- You cannot ask for a field that does not exist.
- No field will ever be
undefined
ornull
. - You cannot create recursive records with a
this
orself
keyword - (This one is just my recommendation) Try avoiding multilevel records, although you can create it but updating them is a pain.
Defining record
record =
{ name = "Albert Carter", age = 20 }
Updating Record
updatedRecord = { record | age = 21 }
Multilevel Records
You can create multilevel records but I would recommend you not to do it.
multiLevelRecord =
{
name = "Albert Carter",
age = 20,
address = { line1 = "Nightmare at", street = "Elm Street" }
}
Updating multilevel Records
Updating multilevel record is not straight forward to update and you will not be able to update it directly so we need update it in two step process, first update address
and then we need to update the main record
updatedAdd =
{ multiLevelRecord.address | line1 = "Not a nightmare anymore" }updatedMultilevelRecord =
{ multiLevelRecord | address = updatedAdd }
Record Type Alias
You can also define type of a record and then re-use it
-- Define the record type
type alias Record = { name: String, age: Int }-- Create a record
record: Record -- type definition, displays what is the data type
record =
{ name = "Albert Carter", age = 20 }-- or you can also create it as
record =
Record "Albert Carter" 20
I recommend the first method as it is easier to recognise name-values, in second method sequence is important. I haven’t covered everything with records, just the stuff you need to know. You can read more detailed article here.
Custom Types
Custom types are like enums but more.
type UserStatus = Regular | Visitor
if I use a data type/alias UserStatus it can have only two possible values either Regular
or Visitor
.
for a record
type alias User =
{ type: UserStatus }userRecord: User
userRecord =
{ type = Regular }
we can also bind a Type with one or more data variables, let’s say we’d like to know name of the user with each status.
In fact a regular user will have an id, we can also add id to Regular status, we can change the definition to
type UserStatus =
Regular String Int
| Visitor Stringtype alias User =
{ type: UserStatus }userRecord: User
userRecord =
{ type = (Regular "Albert Carter" 20) }
so we know anywhere we get user status as Regular it will have id and name of the user. How can we fetch the user name and id?
userNameAndIdRecord =
case userRecord.type of
Regular username id ->
{ name = username, id = id }
Visitor username ->
{ name = username, id = -1}
Functions
A typical function in elm is similar to a method or function in any other language, it accepts parameters and provides an output. In elm it’s mandatory to return (or whatever you do is automatically returned) let’s see how
-- a function returning 5
someFunction =
5
In above code, you could also argue that it is a variable. Elm is a functional language, everything works in function.
-- a function returning 5 to the power of "power"
someFunction power =
5^power
In both of the above function automatically returns the output.
Another thing to remember is the function can only have one statement which it automatically returns.
-- this is valid
customOrOperation flag1 flag2 =
case (flag1, flag2) of
(True, True)->
True
(True, False) ->
True
(False, True) ->
True
_ ->
False
since the case above returns only one object/value.
What if I want to write multiple statements in a single function?
When you want to break your method in to multiple statements, you should use Let Expressions like below.
someFunction =
let
twentyFour =
3 * 8 sixteen =
4 ^ 2
in
twentyFour + sixteen
you can write as many as statements inside Let Expressions, you can use if..else or cases or any other functions.
someFunction =
let
condition =
True defaultVar =
10
in
if condition then
let
var1 =
2 var2 =
3
in
var1 + var2
else
defaultVar
Type Annotations
One of the most important and useful features of elm language. I recommend to declare type annotations always, it can help you understand a nature of a function.
I have dedicated a whole article to this feature, which you can refer here.
Ports
There will be times when you need to perform some operations in JavaScript space, in such times, you can use ports to send an object out to JavaScript and accept an object from JavaScript.
I would recommend you to learn once you have good understanding of elm’s basic concepts and understand using ports after that.
But if you are in a rush refer this article. I will add an article explaining ports in future.