Erlang basics · Lesson 06 (open contents)
01 · Open erl02 · Meet common terms03 · Tell two kinds of text apart04 · Bind a variable once05 · Split and filter a list06 · Parse a number safely07 · Choose one path with case08 · Let a function keep going09 · Put code in a module10 · Compare terms and Boolean results11 · Read and update nested maps12 · Build and inspect UTF-8 binaries13 · Let clauses choose the function path14 · Solve a list twice15 · Choose with patterns, guards, and errors16 · Describe a module and one record17 · Put one tested module in Rebar318 · Return success or failure as data19 · Read and write one file safely20 · Build a data pipeline with functions21 · Keep records behind a module boundary22 · Define a module contract23 · Describe the data contract24 · Test small rules and whole flows25 · Shape builds and make a command26 · Write the project promise27 · Parse one real line28 · Keep the public API small29 · Make the promise executable30 · Package the edge and leave clues31 · Prove the project is done
ERLANG · SCRATCH · LESSON 0630 minutes

Parse a number safely

Trim a binary, turn it into an integer, and catch invalid input.

01 · Start with the whole example

Parse valid text and catch invalid text

string:trim/1 names a function in documentation. string:trim(Text) calls it with one argument.

Erlang
%% Bind a complete parser to ParseInteger
ParseInteger =
  fun(Text) ->
    try binary_to_integer(string:trim(Text)) of
      Number -> {ok, Number}
    catch
      error:badarg -> {error, not_an_integer}
    end
  end.

%% Run both paths
{ParseInteger(<<" 42 ">>), ParseInteger(<<"not-a-number">>)}.
Check the result first
  • The valid input is trimmed to <<"42">>, parsed, and returned as {ok, 42}.
  • The invalid input raises error:badarg inside the try expression.
  • The catch clause turns that error into {error, not_an_integer}.
02 · Take the code apart

Read from the first line down

  1. string:trim/1 and binary_to_integer/1 are name-and-arity forms used in documentation. Calls use parentheses and do not include /1.
  2. A successful integer reaches the of clause and becomes {ok, Number}.
  3. Invalid text raises error:badarg, so the matching catch clause returns {error, not_an_integer}.
  4. Both paths return tagged tuples that the next piece of code can match.
03 · Meet the new symbols

Symbols are not secret signs

string:trim/1

The name-and-arity form used in documentation: module string, function trim, one argument.

binary_to_integer/1

A one-argument function that parses an integer binary or raises badarg.

fun(Text) -> ... end

Create a full anonymous function whose argument is called Text.

catch error:badarg ->

Handle only an error whose class is error and whose reason is badarg.

04 · Ideas inside the code

Match each name to its meaning

01

arity

The number of arguments a function takes. /1 says that string:trim/1 and binary_to_integer/1 each take one argument.

02

anonymous function

A function written with fun ... end and bound to a variable such as ParseInteger.

03

try/of/catch

Run an expression, handle its normal result after of, and handle a named error after catch.

05 · Make the idea clear

Why these forms are useful

string:trim/1 removes whitespace from both ends of a text binary. binary_to_integer/1 turns clean integer text into an integer.

Invalid integer text makes binary_to_integer/1 raise the error reason badarg. A try ... of ... catch ... end expression can turn that expected error into data.

Bind the full anonymous function to ParseInteger. Valid and invalid calls then return tagged tuples instead of making the shell stop at an exception.

DESIGN DECISION

Why this shape?

Why put /1 after a function name?

Choice

BEAM identifies an entry point by module, function name, and argument count. trim/1 means the trim function that takes one argument.

Cost and boundary

The same name with another argument count is another function. Default arguments generate arities at compile time; they do not make calls loosely sized.

A FAMILIAR POINT OF VIEW

Coming from Java, Python, or JavaScript

Java

Familiar starting point
Methods can overload by parameter types and count.
What BEAM changes
BEAM first finds a name and arity, then clauses can match data shapes.
False friend
run/1 and run/2 are distinct entry points.

Python

Familiar starting point
One function often uses defaults or *args.
What BEAM changes
Arity is part of a function's identity and appears in exports and docs.
False friend
Leaving out an argument does not discover another arity automatically.

JavaScript

Familiar starting point
Functions often tolerate missing or extra arguments.
What BEAM changes
A BEAM call must find the exact arity.
False friend
&1 is a capture placeholder; it is not another spelling of /1.
06 · Change it yourself

Close the answer and try

Complete SafeNumber so <<" 7 ">> returns {ok, 7} and <<"seven">> returns {error, not_an_integer}.

Practice starting point
SafeNumber =
  fun(Text) ->
    try ____(string:____(Text)) of
      Number -> {ok, Number}
    catch
      ____ -> {error, not_an_integer}
    end
  end.

{SafeNumber(<<" 7 ">>), SafeNumber(<<"seven">>)}.

Target result: The result should be {{ok, 7}, {error, not_an_integer}}.

Stuck? Read one hint

Use binary_to_integer, trim, and the catch pattern error:badarg.

After you run it, see one answer
One answer
%% Handle only the conversion error we expect
SafeNumber =
  fun(Text) ->
    try binary_to_integer(string:trim(Text)) of
      Number -> {ok, Number}
    catch
      error:badarg -> {error, not_an_integer}
    end
  end.

{SafeNumber(<<" 7 ">>), SafeNumber(<<"seven">>)}.
Think about it: Why does the catch clause use `error:badarg` instead of `_ : _`?

The parser expects one conversion error. Matching only error:badarg keeps unrelated errors visible so they can be fixed.

Take with you

Remember these three lines

  1. 1

    module:function/arity or function/arity names a function in documentation; parentheses make a call.

  2. 2

    Bind a full anonymous function with fun ... end.

  3. 3

    Catch the expected error:badarg and return a tagged result.

Lesson completeRun the code once, then mark this lesson as done.