# Run as: iex --dot-iex path/to/notebook.exs # Title: Welcome to Livebook # ── Basic usage ── # Livebook is a tool for crafting **interactive** and **collaborative** code notebooks. # Each notebook consists of a number of cells, which serve as primary building blocks. # There are **Markdown** cells (such as this one) that allow you to describe your work # and **Code** cells to run your Elixir code! # To insert a new cell move your cursor between cells and click one of the revealed buttons. 👇 # This is a Code cell - as the name suggests that's where the code goes. # To evaluate this cell, you can either press the "Evaluate" button above # or use `Ctrl + Enter` (or Cmd + Enter on a Mac)! message = "hey, grab yourself a cup of 🍵" # Subsequent cells have access to the bindings you've defined: String.replace(message, "🍵", "☕") # Note however that bindings are not global, so each cell *sees* only stuff # that goes above itself. This approach helps to keep the notebook clean and # predictable as you keep working on it. Furthermore, Livebook tracks which # variables are used by each cell in order to detect which cells become # stale. For example, try changing the `message` variable and you will see # the status indicator on the bottom right of the second cell become yellow. # ── Sections ── # You can leverage so called **sections** to nicely group related cells together. # Click on the "Outline" icon () in the sidebar # to reveal a list of all sections. As you can see, this approach helps to easily # jump around the notebook, especially once it grows. # Let's make use of this section to see how output is captured! cats = ~w(😼 😹 😻 😺 😸 😽) for _ <- 1..3 do cats |> Enum.take_random(3) |> Enum.join(" ") |> IO.puts() end # ── Branching sections ── (⎇ from Sections) # Additionally, you can make a section **branch out** from any # previous regular section. Hover over the section name to reveal # available actions and click on the branch icon to select the # parent section. # You still have access to all the previous data: # {message, cats} # The important characteristic of a branching section is that # it runs independently from other sections and as such is well # suited for running long computations "in background". # Process.sleep(300_000) # Having this cell running, feel free to insert another Code cell # in the section below and see it evaluates immediately. Crashes # in branched sections also have limited scope and will affect only # the branched section. # ── Saving notebooks ── # By default, notebooks are stored in a temporary directory, which is fine for # interactive hacking, but oftentimes you will want to save your work for later. # Such can be done by clicking on the "Disk" icon () # in the bottom-right corner and selecting the file location. # Once saved, you can access the location of the current `.livemd` file and # its current directory using `__ENV__` and `__DIR__` variables: IO.puts(__ENV__.file) IO.puts(__DIR__) # Notebooks are stored in **live markdown** format, which is the Markdown you know, # with just a few assumptions on how particular elements are represented. Thanks to this # approach you can easily keep notebooks under version control and get readable diffs. # You can also easily preview those files and even edit them in a text editor. # ── Keyboard shortcuts ── # Once you start using notebooks more, it's gonna be beneficial # to optimise how you move around. Livebook leverages the concept of # **navigation**/**insert** modes and offers many shortcuts for common operations. # Make sure to check out the shortcuts by clicking the "Keyboard" icon # () in the sidebar or # by pressing ?. # ── Autocompletion ── (⎇ from Sections) # Code cells also support autocompletion. Autocompletion happens # automatically as you type but you can explicitly trigger # it with ctrl + . You must start the runtime, # by executing any cell at least once, for the autocompletion engine # to load. # Let's try autocompleting the code below to `System.version()`. # First put the cursor after the `System` below and type `.`: # System # You should have seen the editor listing many different options, # which you can use to find `version`. Executing the code will # return the Elixir version. # Note you can also press tab to cycle across the completion # alternatives. # ── Markdown extensions ── # Livebook also include supports for links, mathematical expressions, and Mermaid diagrams. # ### Links # It is possible to link between Livebooks using Markdown's link syntax. # For example, `[next chapter](chapter_2.livemd)` could be used to link # to a Livebook named `chapter_2.livemd` in the same directory as the current # notebook. Once clicked, Livebook will automatically open up a new session # to execute the linked notebook. # ### Math expressions # Livebook uses $\TeX$ syntax for math inside your Markdown cells. # It supports both inline math, like $e^{\pi i} + 1 = 0$, as well as display math: # $$ # S(x) = \frac{1}{1 + e^{-x}} = \frac{e^{x}}{e^{x} + 1} # $$ # To write your own, put your math expressions between \$ signs for inline math # or \$\$ if you want display math. You can double click the formulas above to see # how they are written. # You can explore all supported expressions in the [KaTeX documentation](https://katex.org/docs/supported.html). # ### Mermaid diagrams # [Mermaid](https://mermaid-js.github.io/) is a library for creating diagrams # and visualizations using text and code. You can define those diagrams in # your Markdown cells via ```` ```mermaid ```` blocks. Let's see an example: # ```mermaid # graph TD; # A-->B; # A-->C; # B-->D; # C-->D; # ``` # ── Erlang support ── # Livebook also allows developers to write Erlang code. To do so, # click on the submenu option on the right side of the "Elixir" cell # button and choose Erlang. # Your Erlang code will run alongside your Elixir cells. This means # you can leverage all of the dependency management and smart cell features # outlined in the previous sections. In particular, integration between # Erlang and Elixir will happen as follows: # * Variables in Elixir are available in Erlang cells in camel-case # fashion. `x` in Elixir becomes `X` in Erlang. `foo_bar` becomes # `FooBar`; # * Variables in Erlang are available in Elixir cells in underscored # fashion. `X` in Erlang becomes `x` in Elixir. `FooBar` becomes # `foo_bar`; # For example, to print all of the cats defined at the top of the notebook, # but in Erlang: # [io:format("~ts", [Cat]) || Cat <- Cats]. # ### Defining modules # You can also define Erlang modules, one per cell, as you would in an `.erl` file. # -module(direction). # -export([north/0, east/0, west/0, south/0]). # north() -> {ok, north}. # east() -> {ok, east}. # west() -> {ok, west}. # south() -> {ok, south}. # Macros, includes, and similar module feature are supported. # Once the module is defined, you can call the functions as usual: # {ok, N} = direction:north(), # {ok, E} = direction:east(), # {ok, W} = direction:west(), # {ok, S} = direction:south(), # {N, E, W, S}. # We are just beginning the Erlang integration and contributions to # further enrich it are welcome. # ── Evaluation vs compilation ── # Livebook automatically shows the execution time of each Code # cell on the bottom-right of the cell. After evaluation, the total # time can be seen by hovering the green dot. # However, it is important to remember that all code outside of # a module in Erlang or Elixir is *evaluated*, and therefore # executes much slower than code defined inside modules, which # are *compiled*. # Let's see an example. Run the cell below: Enum.reduce(1..1_000_000, 0, fn x, acc -> x + acc end) # We are adding all of the elements in a range by iterating them # one by one. However, executing it likely takes some reasonable # amount of time, as the invocation of the `Enum.reduce/3` as well # as the anonymous function argument are evaluated. # However, what if we move the above to inside a function? Let's do # that: defmodule Bench do def sum do Enum.reduce(1..1_000_000, 0, fn x, acc -> x + acc end) end end # Now let's try running it: Bench.sum() # The latest cell should execute at least an order of magnitude faster # than the previous `Enum.reduce/3` call. While the call `Bench.sum()` # itself is evaluated, the one million iterations of `Enum.reduce/3` # happen inside a module, which is compiled. # Another benefit is compiling code is that exceptions often have # better stacktraces and error messages. Therefore, if a notebook is # performing slower than expected or you need more information in case # of failures, consider moving the bulk of the execution to inside # modules. # ── Running tests ── # There are two main ways of running tests inside Livebook. # ### Doctests # Doctests allow developers to provide and test examples directly # from their documentation. Doctests are defined with the `iex>` # prompts under the `@moduledoc` and `@doc` attributes of your # modules. Let's see an example: defmodule MyModule do @moduledoc """ This is an example of doctests: iex> 2 + 2 5 iex> 6 + 7 13 """ end # Livebook automatically detects doctests for any defined modules # and automatically executes them when you evaluate the cell. # Doctests which fail are marked in red in the gutter and show # the failure information right below them. Otherwise they are tagged # in green. For more information on doctests and their limitations, # see [`ExUnit.Doctest`](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html). # ### ExUnit integration # It is also possible to run `ExUnit` suites directly from your notebooks. # The key is to disable `ExUnit`'s autorun feature and then explicitly # run the test suite after all test cases have been defined: ExUnit.start(autorun: false) defmodule MyTest do use ExUnit.Case, async: true test "it works" do assert true end end ExUnit.run() # This is perfect for testing more complex logic that does not fit under # doctests. # ── Next steps ── # That's our quick intro to Livebook! Where to go next? # * If you are not familiar with Elixir, there is a fast paced # introduction to the language in the [Distributed portals # with Elixir](/learn/notebooks/distributed-portals-with-elixir) # notebook; # * [Write and deploy a chat application](/learn/notebooks/deploy-apps) # using Livebook and learn more about our [use cases](https://hexdocs.pm/livebook/use_cases.html) # * Go back [to the Learn page](/learn) and see how to use Livebook to # deploy apps, explore data, plot graphs, and much more; # * Finally, remember Livebook is an open source project, so feel free to # look into [the repository](https://github.com/livebook-dev/livebook) # to contribute, report bugs, suggest features or just skim over the # codebase. # Now go ahead and build something cool! 🚢