Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interaktív használat: IEx és Livebook

Az IEx

Az Elixir interaktív héja, az iex egy REPL (read-eval-print loop): beolvas egy kifejezést, kiértékeli, és kiírja az értékét. A promptban zárójelben a kifejezés sorszáma áll.

$ iex
Erlang/OTP ...
Interactive Elixir ...
  press Ctrl+C to exit
  (type h() ENTER for help)

iex> 3.2 + 2.1 * 2
7.4

iex> :atom
:atom

iex> Atom
Atom

iex> "string"
"string"

iex> {:ennes,:%,A,:':',9.8}
{:ennes, :%, A, :":", 9.8}

iex> [:lista,:%,A,:':',9.8]
[:lista, :%, A, :":", 9.8]

iex> i :':'
...Data type
    Atom...

Az i segédfüggvény információt ír ki a kapott termről, például a típusát.

Az IEx-ből a Ctrl+C lenyomásával léphetünk ki. Ekkor a BEAM megszakítási menüje jelenik meg; egy újabb Ctrl+C kilép a héjból:

iex> Ctrl+C
BREAK: (a)bort (A)bort with dump (c)ontinue
   (p)roc info (i)nfo (l)oaded (v)ersion
   (k)ill (D)b-tables (d)istribution
Ctrl+C
$

A Ctrl+G a felhasználói parancsmódot (User switch command) nyitja meg; a h kiírja a parancsait, a q kilép:

iex> Ctrl+G
User switch command
--> h
  c [nn]            - connect to job
  i [nn]            - interrupt job
  k [nn]            - kill job
  j                 - list all jobs
  s [shell]         - start local shell
  r [node [shell]]  - start remote shell
  q                 - quit erlang
  ? | h             - this message
  --> q
$

IEx-parancsok

Az IEx segédfüggvényeit (helpers) a h() listázza:

iex> h().
Welcome to Interactive Elixir.
...
c/1            - compiles a file
c/2            - compiles a file and writes bytecode to the given path
cd/1           - changes the current directory
clear/0        - clears the screen
exports/1      - shows all exports (functions + macros) in a module
h/1            - prints help for the given module, function or macro
i/0            - prints information about the last value
i/1            - prints information about the given term
ls/0           - lists the contents of the current directory
ls/1           - lists the contents of the specified directory
pwd/0          - prints the current working directory
r/1            - recompiles the given module's source file
v/0            - retrieves the last value from the history
v/1            - retrieves the nth value from the history
...
To learn more about IEx as a whole, type h(IEx).

Az IEx-ben érdemes kipróbálni a Kernel Elixir-modul és a :math Erlang-könyvtár ismert függvényeit, és figyelni a tabulátorral kérhető szövegkiegészítést (completion).

Saját program fordítása, futtatása

Függvényt csak modulban lehet definiálni. Az alábbi fpea.ex fájl az Fpea modulban definiálja a faktoriális függvényt. A fájlnév konvenció szerint csupa kisbetűs, a szavak között aláhúzással (snake_case); a modulnév egybeírt, a szavak nagy kezdőbetűvel (BumpyCase, CamelCase).

defmodule Fpea do
# Fájlnév csupa kisbetűvel, szavak között aláhúzás (snake_case)
# Modulnév egybe, szavak nagy kezdőbetűvel (BumpyCase, CamelCase)
  @spec fac(n::integer) :: f::integer # Típusspecifikáció
  # f = n! (azaz f az n faktoriálisa) # Fejkomment
  def fac(0), do: 1            # ha az n=0 mintaillesztés sikeres
  def fac(n), do: n * fac(n-1) # ha az n=0 mintaillesztés sikertelen
end

A fájlt az IEx-ben a c paranccsal fordítjuk le; a függvényt a modulnévvel minősítve hívjuk:

iex> c "fpea.ex"  # fordítás
[Fpea]

iex> Fpea.fac(5)  # futtatás
120

iex> fac(5)         # a modulnevet ki kell írni
** (CompileError) iex:3: undefined function fac/1
iex> Fpea.fac 5   # argumentum körül a zárójel sokszor elhagyható
120

Egy már betöltött modul exportált függvényeit az exports Fpea írja ki (itt fac/1), a módosított forrásfájlt pedig az r Fpea fordítja újra.

Modulok és függvények azonosítása

Az Elixirben egy függvényt három dolog azonosít: a neve, az aritása (a paramétereinek száma) és annak a modulnak a neve, amelyben definiálva van. Például a String.slice/2 és a String.slice/3 a String modul két azonos nevű függvénye: az egyiknek két, a másiknak három paramétere van. Ha ugyanabban a modulban hivatkozunk egy függvényre, amelyben definiálva van, a modulnév elmaradhat.

A def exportált (a modulon kívülről is hívható), a defp privát függvényt definiál:

defmodule Dummy do

  def dummy0, do: 2024             # exportált, paraméter nélkül

  def dummy1(p), do: dummy2(p)     # exportált fv.

  defp dummy2(p), do: IO.puts (p)  # privát fv.

end

Dummy.dummy0

Dummy.dummy0 |> IO.inspect()

Dummy.dummy1('karakterlánc')    # karakterkódokból álló lácolt lista, nem sztring!

Dummy.dummy1(~c"karakterlista") # a ~c egy ún. szigil, speciális jelölés az Elixirben

Dummy.dummy1("sztring")

# Dummy.dummy2("sztring")

Az IO.puts/1 mindhárom paramétert szövegként írja ki (karakterlánc, karakterlista, sztring). A kikommentezett Dummy.dummy2("sztring") hívás UndefinedFunctionError hibát adna, mert a privát függvény a modulon kívülről nem látszik. Modulon kívül függvény nem definiálható: a def dummy, do: "halihó" önmagában a cannot invoke def/2 outside module hibát adja.

Livebook

A Livebook az Elixir notebookja, a Python Jupyteréhez hasonló. A gyakorlatok feladatsorai Livebook-formátumban (.livemd) jelennek meg. Az IEx-szel szemben a Livebookban modul is definiálható egy cellában.

A Livebook Elixir-cellái különálló modulokként fordulnak le. Ha egy cellában egy modulnak nevet adtunk, ugyanazt a nevet egy másik cellában már nem használhatjuk: ha az azonos nevű modult tartalmazó második cellát is kiértékeljük, az Elixir hibát jelez. Ennek előnye, hogy a korábbi cellákban definiált függvényeket a modulnév megadásával a későbbi cellákból is hívhatjuk.

Kiírás: IO.inspect, inspect, IO.puts

Egy kifejezéssorozat kiértékelésekor az Elixir (a Livebook is) csak az utolsó kifejezés értékét írja ki. A korábbi kifejezések értékét az IO.inspect/1-gyel íratjuk ki:

[1|[2|[3|[]]]] |> IO.inspect()
[1,2|[3]] # |> IO.inspect()
[1,2,3]

Az alábbi cellában az első kifejezés értékével nem kezdünk semmit, ezért nem is jelenik meg sehol; csak a második, utolsó kifejezés értéke ([1, 2, 3]) látszik:

App3.app([], [])        # E kifejezés értékével nem kezdünk semmit, nem is jelenik meg sehol.
App3.app([], [1, 2, 3])

Az IO.inspect/1-gyel mindkettő kiíratható (az App3.app/2 két listát fűz össze, lásd Típusok):

IO.inspect(App3.app([], []))        # Itt sem kezdünk vele semmit, de kiírjuk a már látott
IO.inspect(App3.app([], [1, 2, 3])) #  IO.inspect/1 függvénnyel, direkt paraméterátadással.

A |> az ún. pipe operátor (mint a Linuxban a |): a bal oldalán álló kifejezés eredményét a jobb oldalán álló függvénynek adja át, mégpedig az első paramétereként, ha több paramétere is van.

Az IO.inspect/1 nemcsak kiírja a kapott kifejezés értékét, hanem eredményként változatlanul vissza is adja, ezért a többi inspect függvénnyel együtt nagyon hasznos hibakeresési eszköz: bárhová beszúrható egy kifejezésbe.

[1 |> IO.inspect(), 2 |> IO.inspect(), 3 |> IO.inspect()] |> IO.inspect()

Ez sorban kiírja az 1, 2, 3 értéket, majd az [1, 2, 3] listát.

Az IO.inspect/2 és a Kernel modulban definiált inspect/2 (a Kernel modulnév elhagyható) között az a különbség, hogy az előbbi kiírja a kapott kifejezést, és az értékét változatlan formában továbbadja, az utóbbi pedig sztringgé konvertálva adja eredményül (a Livebook ezt a sztringet a cella eredményeként jeleníti meg). Az IO.puts/1 a kapott kifejezést sztringgé alakítva írja ki, és az :ok atomot adja vissza. Az inspect függvények működése opciókkal befolyásolható; a listák kiírását szabályozó charlists: opciót a Lista és karakterlánc fejezet mutatja be.

Forrás: dp26a-fp1ea.pdf (35–37. dia), dp26a-fp1gyfel.livemd, dp26a-fp1gy-megoldasok.livemd