Skip to content

Latest commit

 

History

History
415 lines (314 loc) · 9.27 KB

day_3.md

File metadata and controls

415 lines (314 loc) · 9.27 KB

Erlang tutorial day 3

Table of Contents

  1. Lists
  2. Strings
  3. Exercises

1 Lists

The list data structure (Starting out (for real))

  • Lists are heterogeneous and immutable:

    A = [1, 2, 3]

    Representation:

      A
    +---+---+     +---+---+      +---+---+
    | 1 | ----->  | 2 | ----->   | 3 | ----->    []
    +---+---+     +---+---+      +---+---+
    
  • Manipulating the beginning of a list is cheap:

    > B = [0|A]
    [0, 1, 2, 3]

    Representation:

      B             A
    +---+---+     +---+---+     +---+---+      +---+---+
    | 0 | ----->  | 1 | ----->  | 2 | ----->   | 3 | ----->    []
    +---+---+     +---+---+     +---+---+      +---+---+
    
  • Manipulating the end of a list is expensive:

    > C = A ++ [0]
    [1, 2, 3, 0]

    Representation:

      A
    +---+---+     +---+---+      +---+---+
    | 1 | ----->  | 2 | ----->   | 3 | ----->    []
    +---+---+     +---+---+      +---+---+
    
      C
    +---+---+     +---+---+      +---+---+      +---+---+
    | 1 | ----->  | 2 | ----->   | 3 | ----->   | 0 | ----->    []
    +---+---+     +---+---+      +---+---+      +---+---+
    
  • Heads and tails:

    > B = [0, 1, 2, 3].
    
    > hd(B).
    0
    
    > tl(B).
    [1,2,3]
    
    > [Head|Tail] = B.
    [0,1,2,3]
    
    > Head
    0
    
    > Tail
    [1,2,3]
  • Operations on lists:

    > length([1, 2, 3]).
    3
    
    > [1, 2] ++ [3, 4].
    [1,2,3,4]
    
    > [1, 2, 3, 4] -- [2, 4].
    [1,3]
    
    > lists:member(2, [1,2,3]).
    true
    
    > lists:reverse([1, 2, 3]).
    [3,2,1]
    
    > lists:flatten([[1, 2], [3], [[4]]]).
    [1,2,3,4]
    
    > lists:append([[1, 2], [3], [[4]]]).
    [1,2,3,[4]]
  • Pattern matching on lists:

    case List of
        % Empty list
        [] ->
            ...
        % Non-empty list
        [H|T] ->
            ...
    end
    
    case List of
        % List with one element
        [Item] ->
            ...
        % List that starts with [1, 2, 3]
        [1, 2, 3] ++ _ ->
            ...
    
        % Long list
        _ when length(List) > 100 ->
            ...
    
    end
  • Type specifications:

    [integer()]  % A list of integers
    [term()]     % A list of anything
    [any()]      % A list of anything
    list()       % A list of anything
    []           % Empty list
    
    [integer()] | [float()]  % A list of integers or a list of floats
    [integer() | float()]    % A list of numbers

    Note:

    • {atom(), integer()} = A tuple with two elements. There is no equivalent syntax for lists.
    • [atom()] = A list of atoms. There is no equivalent syntax for tuples.

1.2 Recursion with lists (Recursion)

  • Lists and recursion. (mylist.erl contains the full source code.)

    Naive recursion:

    %% Return the length of a list (same as `length/1`)
    -spec len([term()]) -> non_neg_integer().
    len([]) ->
        0;
    len([_H|T]) ->
        1 + len(T).

    Tail recursive recursion:

    %% Return the length of a list (same as `length/1`)
    %% (tail recursive solution)
    -spec len2([term()]) -> non_neg_integer().
    len2(List) ->
        len2(List, 0).
    
    %% Calculate `len2(List) + Acc`
    -spec len2([term()], non_neg_integer()) -> non_neg_integer().
    len2([], Acc) ->
        Acc;
    len2([_H|T], Acc) ->
        len2(T, Acc + 1).

    Tail recursive recursion when the accumulator is a list:

    %% Reverse a list (same as `lists:reverse/1`)
    -spec reverse([term()]) -> [term()].
    reverse(List) ->
        reverse(List, []).
    
    %% Calculate `reverse(List) ++ Acc`
    -spec reverse([term()], [term()]) -> [term()].
    reverse([], Acc) ->
        Acc;
    reverse([H|T], Acc) ->
        reverse(T, [H|Acc]).

    This function works by building up the Acc variable as it is deconstructing the original List parameter:

    ======================================================================
     List
    +---+---+     +---+---+      +---+---+
    | 1 | ----->  | 2 | ----->   | 3 | ----->    []
    +---+---+     +---+---+      +---+---+
    
                                                 Acc
                                                 []
    ======================================================================
                   List
                  +---+---+      +---+---+
                  | 2 | ----->   | 3 | ----->    []
                  +---+---+      +---+---+
    
                                  Acc
                                 +---+---+   
                                 | 1 | ----->    []
                                 +---+---+   
    ======================================================================
                                  List
                                 +---+---+
                                 | 3 | ----->    []
                                 +---+---+
                    Acc
                   +---+---+     +---+---+   
                   | 2 | ----->  | 1 | ----->    []
                   +---+---+     +---+---+   
    ======================================================================
                                                 List
                                                 []
     Acc
    +---+---+      +---+---+     +---+---+   
    | 3 | ----->   | 2 | ----->  | 1 | ----->    []
    +---+---+      +---+---+     +---+---+   
    ======================================================================
    
  • Characters are numbers:

    > $a.
    97
  • Strings are lists:

    > [97, 98, 99].
    "abc"
    > [$a, $b, $c].
    "abc"
    > "".
    []
  • Using io:format to print lists:

    % ~p: Try to be smart
    > io:format("~p~n", ["abc"]).
    "abc"
    > io:format("~p~n", ["ab\0"]).
    [97,98,0]
    
    % ~w: Always print as list of numbers
    > io:format("~w~n", ["abc"]).
    [97,98,99]
    > io:format("~w~n", ["ab\0"]).
    [97,98,0]
    
    % ~s: Always print as string
    > io:format("~s~n", ["abc"]).
    abc
    > io:format("~s~n", ["ab\0"]).
    ab^@
  • Pattern matching on strings:

    case Str of
        % Empty string (i.e. empty list)
        "" ->
            ...
        % String that starts with "version-1.0-"
        "version-1.0-" ++ _ ->
            ...
    end

    My favorite real-world example:

    case lists:reverse(Filename) of
        "piz.dorptset." ++ _ ->
            do_something();
        _ ->
            do_something_else()
    end
  • Binaries are usually better for strings than lists:

    > <<"abc">>.
    <<"abc">>
    • They are quicker to handle (except when modified)
    • They use much less memory
  • Regular expressions:

    Search:

    > re:run("abc", "b").
    {match,[{1,1}]}
    
    > re:run("abc", "b", []).
    {match,[{1,1}]}
    
    > re:run("abc", "b", [{capture, none}]).
    match

    Replace:

    > re:replace("abcd", "c", "[&]", [{return, list}]).
    "ab[c]d"
    
    > re:replace("abcd", "c", "[&]", [{return, binary}]).
    <<"ab[c]d">>
    
    > S = re:replace("abcd", "c", "[&]", []).
    [<<"ab">>,[<<"[">>,<<"c">>,<<"]">>]|<<"d">>]
    
    > io:format("~s~n", [S]).
    ab[c]d
  • iodata():

    • Faster to construct than either binaries or strings.
    • Conversion to string: unicode:characters_to_list(IoData)
    • Conversion to binary: unicode:characters_to_binary(IoData)
  • Conversions:

    > list_to_integer("42").
    42
    > list_to_float("3.14").
    3.14
    
    > string:to_integer("42").
    {42,[]}
    > string:to_float("3.14").
    {3.14,[]}

    They behave differently if the string is not a valid number.

  • Reading input:

    > io:get_line("What is your name? ").
    What is your name? Joe
    "Joe\n"
  • Type specifications:

    char()    % 0..1114111
    string()  = [char()]
    
    binary()  % A sequence of bytes
    
    byte()    % 0..255
    iolist()  = [byte() | binary() | iolist()]   % Simplified
    iodata()  = iolist() | binary()

    Note:

    • white | black = Either the white or the black atom. There is no equivalent syntax for strings (or binaries).

3 Exercises