After going through the basic operations with arithmetic and logical values, we still have Char
and String
as primitive
. By the way, when it comes to String
, although they are primitive
, in most programming languages that speak them String
have the added ability to interact like a range of values stored as an enumerated sequence
. Therefore, I decided to bring List
to the content of this article and save Tuple
and Record
for the following article for easy comparison.
1 2 3 | cd Documents && cd learn-elm elm repl |
Char
Package:
elm/core/Char
Static static-typing
languages like C
or Java
have the Char
type separate from String
and both use single quotes 'A'
to represent Char
values in the code. Here Elm
also uses the same convention and we also have a library that provides sub-program
to work with Char
values in the link above.
The number of operations provided with Char
is also small, so we could probably list them all here. The first will be the operation to check numeric characters, alphanumeric characters, lowercase, uppercase. The check characters in the example are respectively:
- Digit
0
- Lowercase letter
o
- Capital letter
O
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Char.isDigit '0' -- True Char.isDigit 'o' -- False Char.isDigit 'O' -- False Char.isAlpha '0' -- False Char.isAlpha 'o' -- True Char.isAlpha 'O' -- True Char.isUpper '0' -- False Char.isUpper 'o' -- False Char.isUpper 'O' -- True Char.isLower '0' -- False Char.isLower 'o' -- True Char.isLower 'O' -- False |
In the example code here, I want to write enough module
names to modify the names of the sub-program
. If you feel cumbersome and want the code to be more compact, you can add the exposing
operation as in the opening articles.
1 2 | import Char exposing (..) |
The remaining group of operations is to convert between lowercase <=> uppercase letters, and convert between Unicode <=> alphabetic characters.
1 2 3 4 5 6 | Char.toUpper 'a' -- 'A' char.toLower 'A' -- 'a' Char.toCode 'a' -- 97 Char.fromCode 98 -- 'b' |
String
Package:
elm/core/String
In addition to expressing with a pair of double quotes "a string"
, Elm
also allows describing long text content on many contiguous lines with 3 pairs of double quotes –
1 2 3 4 5 | """A string with a line br eak in Elm""" -- "A string with a line brn eak in Elm" : String |
I have a little note here. That’s the space between the newline character newline
and eak...
because in the Elm REPL
environment automatically indents the line when we write the code. As for the standard logic, when we write the code in the file and run elm make
or elm reactor
, we will have the word brneak
.
The number of commonly used operations with String
is a lot, but here I will only list some operations that I pay attention to at the JS
syntax level and refer to Elm
.
1 2 3 4 5 6 7 8 9 10 11 12 | -- "Check if a string is empty in JS" == "" String.isEmpty "Check in Elm" -- "JS String" + " concatenation" "Elm String" ++ " concatenation" -- "A" + "ppend a character in JS" (String.fromChar 'A') ++ "ppend a character in Elm" -- [ ... "JS String to Array" ] String.toList "Elm String to List Char" |
The remaining operations are provided by JS
as a sub-program
, here Elm
is also quite complete and the way to use it is no different. However, with the Higher Order Functions group, I note that it will be temporarily unused in this Sub-Series and for the next Sub-Series on Functional Programming
.
compare : comparable -> comparable -> Order
Now we will talk about String
comparison at the end of the previous article. The logic that compare
uses is very simple; That is, take out each pair of characters in turn in the same order of positions in the strings to compare by character code
. As soon as a pair of characters with different codes is encountered, the check will be stopped and the comparison result will be used either GT
(greater than) or LT
(less than), or if all pairs of characters are duplicated, the result will be matched. argument is EQ
(equal). The only caveat is that at the end of a string, all programming languages use the �
character with the character code 0
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | compare "elm" "Elm" -- GT Char.toCode 'e' -- 101 Char.toCode 'E' -- 69 compare "el" "elm" -- LT Char.toCode '�' -- 0 Char.toCode 'm' -- 109 compare "0" "" -- GT Char.toCode '0' -- 48 Char.toCode '�' -- 0 compare "blank" "bl nk" -- GT Char.toCode 'a' -- 97 Char.toCode ' ' -- 32 commpare "" " " -- LT |
List
Package:
elm/core/List
In fact, List
and Array
are two different data structures and cannot be compared completely in terms of how to use List
in Elm
and how to use Array
in JS
. The basic difference between these two sequence
types is that List
does not support quick access to an element by index
position value like JSarray[1001]
.
However, we can temporarily focus on other operations, which are supported by JS
or Elm
at the syntax level of the language –
1 2 3 4 5 6 7 8 9 10 11 | -- var concatenated = [ ...["Array", "concatenation"], ...["in", "JS"] ] ["List", "concatenation"] ++ ["in", "Elm"] -- var appended = [ "Append", ...["to", "Array", "in", "JS"] ] "Append" :: ["to", "List", "in", "Elm"] ["Append"] ++ ["to", "List", "in", "Elm"] List.append ["Append"] ["to", "List", "in", "Elm"] -- var prepended = [ ...["JS", "Array", "and"], "Prepend" ] List.append ["Elm", "List", "and"] ["Prepend"] |
Well, the List
in Elm
don’t have the List.prepend
operation, so the code here looks a bit syntactically inconsistent. Although we can also define our own prepend operation based on prepend
if List.append
want; However, I think that the usage design like this must have a reason and we should temporarily put a bit of confusion here until we get used to the operation of using List
in specific situations.
In addition, the operation to extract a part of the content in the sequence
, at the syntactic level of the JS
language, also provides an operation called destructuring
. Here Elm
is only supported at the sub-program
level and has a point that we need to pay attention to in the results obtained.
1 2 3 4 5 6 7 8 | -- var [ head, ...tail ] = ["Head", "Tail", "of", "JS", "Array"] List.head ["Head", "Tail", "of", "Elm", "List"] -- Just "Head" : Maybe String List.tail ["Head", "Tail", "of", "Elm", "List"] -- Just ["Tail","of","Elm","List"] : Maybe (List String) |
These results all have in common that they are of type Maybe
and have a variable data parameter a
. Let’s open the definition of Maybe
: elm/core/Maybe
1 2 | <span class="token keyword">type</span> <span class="token constant">Maybe</span> <span class="token hvariable">a</span> <span class="token operator">=</span> <span class="token constant">Just</span> <span class="token hvariable">a</span> <span class="token operator">|</span> <span class="token constant">Nothing</span> |
We have Maybe a
which is a Union
type. and if a value obtained from a sub-program
whose result is type-hint
is Maybe a
, there is a chance that the value will be of type Just a
or Nothing
. Where Nothing
is undefined and is considered an equivalent value to null
or undefined
in other programming environments; Just
is a simple wrapper designed to hold a value of any type a
.
The general reason is that the extraction operation of a sequence
as above, we have a special case that is when the data source is an empty sequence
–
1 2 3 4 5 | -- var [ head, ...tail ] = [] List.head [] -- Nothing : Maybe a List.tail [] -- Nothing : Maybe (List a) |
In the case of JS
we get a head = undefined
value and an array of tail = []
. In Elm
‘s environment, we get Nothing
values of the same type as the expected value type. Specifically, with List.head
, we want to get a value of a
in List
, and with List.tail
, we want to get a smaller List
.
This design is intended to make the resulting values always meaningful in all instances of the original List
; And we will be able to use these obtained values to navigate the case
logic of the code afterwards. However, we will save the tool to help navigate the case
logic and also iterate looping
until we have finished with the Tuple
and Record
operations.
(unpublished) [Declarative Programming + Elm] Lesson 6 – Tuple & Record