In Elm, strings are represented with double quotes:
Characters are represented with single quotes:
Character literals must contain exactly one character. Therefore, these expressions are not allowed in Elm: 'abc'
, ''
. Strings can have as many characters as we want in them.
Multiline Strings
Multi-line strings are created using """
. That’s triple quotes. Here’s how we can insert a multi-line string in repl:
We don’t need to add \
to the end of each line when we create a multi-line string in a file though. Define a constant called revelation
right above main
in Playground.elm
file.
Now pass the revelation
constant to Html.text
in main
.
Run elm reactor
from the beginning-elm
directory in terminal if it’s not running already and refresh the page at http://localhost:8000/src/Playground.elm
. You should see the profound revelation George Costanza had when he was looking at the ocean on a dreary day.
We can use both single and double quotes inside a multi-line string. Using a single quote inside a single-line string is fine, but we need to escape the double quotes with \
.
\
tells Elm that the double quotes immediately after it aren’t there to end the string. Similarly, a single quote must be escaped inside a character literal.
How do we escape the backslash itself? With another backslash.
Calculating Length
To calculate a string’s length, we can use the length
function from String module.
Up until now, we have been creating only custom functions by explicitly defining them. Going forward we will make heavy use of built-in functions like String.length
, which is a part of Elm’s standard library.
- Standard Library
- Most programming languages come with a standard library — a collection of functions and values most likely written in the same language. Elm follows that trend by providing a standard library of its own. All functions and values in Elm’s standard library are grouped into modules based on what type of data they operate on. For example, the
String
module contains functions for manipulating strings. Similarly, theList
module provides functions for modifying lists. There are many more modules in the standard library for working with almost any type of data, for example Dict, Set, and Time to name a few. Various math and function helper operators we saw earlier in this chapter are inside the Basics module. -
Modules are further grouped into packages.
String
,List
, andBasics
all belong to a package called Core, which comes pre-loaded with the Elm Platform. Only the most essential packages are included in Elm Platform. Others are available for download from the online catalog.
When an elm repl
session is started, the String
module gets loaded automatically. Otherwise we would have to explicitly import it like this:
elm repl
automatically loads modules that are most frequently used in Elm. When using a function, it’s a good practice to prefix it with a module name for two reasons:
-
It tells us where the function came from.
-
It prevents name clashes between functions from different modules.
If we want to, we can expose the length
function so that we don’t have to use the prefix.
We used a slightly different syntax to import the String
module here. The exposing (length)
part tells Elm to expose the length
function so that we don’t have to prefix it with String
. As it happens, the List
module also provides a function called length
. What will happen if we expose that function too? Let’s find out.
Note: In Elm, a list is a data structure for storing multiple values. We can create one with square brackets like this: [ "Titan", "Encaladus" ]
. We will cover lists in detail later in this chapter.
Even though we exposed the length
function from List
, Elm still thinks we are trying to use String.length
. To avoid this confusion, we need to be specific by prefixing the module name.
Checking Emptiness
The String
module provides a function called isEmpty
that tells us whether a given string is empty or not.
This is more readable than using the length
function, where we have to explicitly compare the length to 0
.
Combining Strings
++
operator is used to concatenate two strings.
Note: We don’t need to prefix operators with a module name.
We can’t use ++
to combine characters or numbers though. These will throw errors:
One way to combine characters is by converting them to strings first. We can use the fromChar
function to do that.
We can also combine two strings using the append
function.
append
is a special case of ++
operator, which puts two appendable things such as strings and lists together.
Concatenating multiple strings
We can also combine more than two strings using the ++
operator.
Technically speaking, the ++
operator combines only two strings. In our example above, Elm first applies ++
to "Bears. "
and "Beats. "
resulting in "Bears. Beats. "
. It then applies ++
with "Battlestar Gallactica."
as a second argument to produce the final string. We can also use append
to combine more than two strings. Although it tends to get a bit verbose.
Another way of concatenating multiple strings is by using the concat
function which requires us to put individual strings into a list.
Notice how we included the space between words as part of the individual strings themselves. That looks awkward. If we use the join
function instead, we don’t have to do that.
join
takes two parameters:
-
A separator that separates individual strings when they all get combined.
-
A list of strings.
The separator can be anything we want.
Splitting a String
We can use the split
function to break a string into multiple parts. It’s the exact opposite of join
.
Did you notice that in the first example above, when we split on " "
, we end up with four strings, while in the other examples the result is three strings? That’s because there is a space between the words “Battlestar” and “Gallactica.” If we wanted to get a result of three strings, we’d have to be more specific on what to split on like the following example:
Reversing a String
Let’s write a function that tells us whether or not a word is a palindrome. Palindrome is a word or groups of words that read the same forward as backward.
We reverse the word using the reverse
function and compare it with the original. If they both are same, we return True
. Now let’s have some fun with this function.
Unfortunately, our function is too simple to recognize the last example as a palindrome. See if you can improve it to return True
for that phrase too. Also, why is the word "palindrome"
not a palindrome?
Filtering a String
Let’s say we need to do a background check on every candidate that wants to join the Enceladus Program for exploring one of Saturn’s moons. So we have asked the candidates to give us their social security number. Someone miscommunicated and asked them to enter it like this: 222-11-5555 when in fact our system doesn’t accept dashes. We can use the filter
function to get rid of them, but we can’t just apply it like this:
It expects a function that takes a character and returns a boolean. Let’s create a function which does exactly that.
Note: In mathematics, a function that takes a value and returns a boolean is called a predicate function. You will often hear functions like isValid
being called a predicate.
If the character is -
we return False
, otherwise True
. Let’s give the isValid
function to filter
and see what happens.
Aha! The dashes are gone. The following diagram illustrates how filter
works.
filter
fed each character from the string we provided into isValid
. If it returned True
, the character was kept, otherwise it was discarded. filter
is a higher-order function because it takes another function as an argument. The String module provides many more higher-order functions like this such as map
. We won’t cover them all here, but you should check them out from the official documentation.
Anonymous Function
Sometimes its desirable to inline the function that determines whether or not a value should be filtered instead of defining it separately as shown below.
This time we gave filter
a function that doesn’t have a name. It’s called an anonymous function. The following diagram explains various components of an anonymous function.
Anonymous functions are quite useful for writing quick inline functions. We will see more examples later. We can actually re-write the isValid
function we saw earlier like this:
As it turns out a function name is just a constant pointing to an anonymous function definition.
Formatting a String
We often need to convert a string to all upper or lower case. The String
module provides just the functions we need.
We can also trim unnecessary whitespaces from a string.
If we want to stuff more characters into a string, the String
module has functions for that too.
The pad
function pads both sides of a string with a character of our choice until it reaches the given length: 10
. We can also pad only one side if we want.
Substrings
Finding Substrings
We can check for substrings using the contains
function.
We can also find out if a string starts or ends with a certain substring.
We can even pinpoint where exactly the substring lies with the indexes
function.
indexes
returns an empty list when it can’t find a substring. Otherwise it returns an index where the substring starts for each occurrence. And remember when we count indexes in Elm, we have to start from 0
. We can also use the indexes
function on multi-line strings.
It’s important to note that most functions in the String
module for locating substrings are case-sensitive.
Extracting Substrings
Now that we know how to look for substrings, let’s go ahead and extract them using the slice
function.
slice
takes start and end indices of the substring we are interested in. But there is a catch. It stops at the character right before the end index. When we extracted “Bears”, we had to give 5 as the end index even though the last character on that word (s
) is located at index 4
. We can also count backwards like this:
Counting backwards can be confusing. Because of how the end index works, we can’t extract the last dot (.
) if we count from the back. -1
is the index of the last dot, but slice
only extracts characters up until the index before it. If we try to use 0
as the end, we get an empty string. Let’s just stick with the positive indices.
Replacing Substrings
The String
module doesn’t provide an easy way to replace substrings yet. We will have to use regular expressions for that. The next section is all about them.
We have only covered some of the most commonly used functions for manipulating strings. The String
module provides plenty more functions. You can learn all about them here.