cv.cm

Pemrograman · Bahasa pemrograman

Tutorial Elixir untuk pemula

7 menit baca

Jawaban singkat

Elixir adalah bahasa fungsional dinamis yang berjalan di virtual machine Erlang (BEAM), dirancang untuk sistem yang skalabel, tahan gangguan, dan konkuren. Gagasan intinya adalah data immutable, pattern matching, operator pipe, dan proses ringan yang berkomunikasi lewat pesan. Halaman ini membahas persiapan, tipe, pattern matching, alur kontrol, modul dan fungsi, koleksi, proses, dan penanganan error.

Buka Penguji regex

Apa itu Elixir dan untuk apa dipakai

Elixir adalah bahasa fungsional dinamis yang dibuat oleh José Valim dan pertama kali dirilis pada 2012. Elixir berjalan di BEAM, virtual machine milik Erlang, sehingga mewarisi proses ringan, ketahanan terhadap gangguan, dan dukungan sistem terdistribusi dari Erlang, sambil menambahkan sintaks yang ramah, macro, dan tooling modern.

Elixir dipakai untuk aplikasi web dan API dengan framework Phoenix, fitur real-time seperti chat dan dashboard langsung (Phoenix LiveView), sistem pesan, data pipeline, perangkat embedded dengan Nerves, dan machine learning dengan Nx. Perusahaan memilihnya untuk layanan yang harus menangani banyak koneksi bersamaan dan tetap berjalan ketika sebagian komponennya gagal.

Memasang Elixir dan menjalankan Hello, world

Pasang Elixir dari elixir-lang.org (yang juga memasang atau memerlukan Erlang/OTP). Script memakai ekstensi .exs; file proyek yang dikompilasi memakai .ex. iex memulai shell interaktif.

# hello.exs
IO.puts("Hello, world!")
elixir hello.exs
# Hello, world!
iex                      # interactive shell; type h(Enum.map) for help
mix new my_app           # create a new project with Mix, the build tool

Komentar diawali dengan #. Tanda kurung di sekitar argumen fungsi bersifat opsional di banyak tempat, jadi IO.puts "hi" juga berfungsi.

Tipe dasar dan immutability

Semua data di Elixir bersifat immutable. Mengikat ulang sebuah nama dengan = mengarahkannya ke nilai baru; nilai lama tidak pernah berubah. String adalah binary UTF-8 yang ditulis dengan tanda kutip ganda, dan atom adalah konstanta bernama yang diawali titik dua.

name = "Elixir"
year = 2012
IO.puts("#{name} since #{year}")    # Elixir since 2012
IO.puts(10 / 4)                     # 2.5 (always a float)
IO.puts(div(10, 4))                 # 2
IO.puts(rem(10, 4))                 # 2
IO.puts("ab" <> "cd")               # abcd (string concatenation)
IO.puts(String.length("héllo"))     # 5 (counts characters, not bytes)
IO.inspect(:ok)                     # :ok
IO.inspect(is_atom(true))           # true (booleans are atoms)
TipeContohCatatan
integer42, 1_000_000presisi arbitrer
float3.14presisi ganda 64-bit
atom:ok, :errorkonstanta; true, false, dan nil adalah atom
string"hello"binary UTF-8; interpolasi dengan #{}
list[1, 2, 3]linked list
tuple{:ok, 1}ukuran tetap, disimpan berurutan di memori
map%{"a" => 1}penyimpanan key-value

Pattern matching

Di Elixir, = adalah operator match. Sisi kiri adalah pattern; jika sisi kanan cocok dengannya, variabel dalam pattern akan terikat. Pattern matching dipakai di mana-mana: pada assignment, case, kepala fungsi, dan penanganan error.

{:ok, value} = {:ok, 42}
IO.puts(value)                         # 42

[first | rest] = [1, 2, 3]
IO.inspect({first, rest})              # {1, [2, 3]}

%{name: n} = %{name: "Ann", age: 31}
IO.puts(n)                             # Ann

result = {:error, :not_found}
message =
  case result do
    {:ok, v} -> "got #{v}"
    {:error, reason} -> "failed: #{reason}"
  end
IO.puts(message)                       # failed: not_found

x = 1
^x = 1                                 # pin operator: match the current value

Jika pattern tidak cocok, Elixir memunculkan MatchError. Operator pin ^ berarti "pakai nilai variabel yang sudah ada" alih-alih mengikatnya ulang.

Alur kontrol

Elixir punya case, cond, dan if/unless, dan semuanya mengembalikan nilai. Tidak ada perulangan for/while yang mengubah penghitung; sebagai gantinya Anda memakai rekursi, modul Enum, atau comprehension for.

temp = 22
feel =
  cond do
    temp > 30 -> "hot"
    temp >= 15 -> "mild"
    true -> "cold"
  end
IO.puts(feel)                                   # mild

IO.puts(if(rem(temp, 2) == 0, do: "even", else: "odd"))  # even

squares = for n <- 1..5, rem(n, 2) == 1, do: n * n
IO.inspect(squares)                             # [1, 9, 25]

Hanya false dan nil yang falsy; semua yang lain, termasuk 0 dan "", adalah truthy.

Fungsi, modul, dan operator pipe

Fungsi bernama berada di dalam modul yang didefinisikan dengan defmodule. Sebuah fungsi dapat punya beberapa clause, yang dipilih lewat pattern matching dan guard (when). Fungsi anonim ditulis fn ... end dan dipanggil dengan tanda titik. Operator pipe |> meneruskan hasil satu ekspresi sebagai argumen pertama pada pemanggilan berikutnya.

defmodule Math do
  def factorial(0), do: 1
  def factorial(n) when n > 0, do: n * factorial(n - 1)

  def sign(n) when n < 0, do: :negative
  def sign(0), do: :zero
  def sign(_n), do: :positive
end

IO.puts(Math.factorial(5))          # 120
IO.inspect(Math.sign(-3))           # :negative

double = fn x -> x * 2 end
IO.puts(double.(21))                # 42 (note the dot)

"  Elixir is fun  "
|> String.trim()
|> String.upcase()
|> String.split()
|> IO.inspect()                     # ["ELIXIR", "IS", "FUN"]

Fungsi dikenali dari nama dan arity (jumlah argumen), yang dalam dokumentasi ditulis seperti String.split/1 atau Math.factorial/1.

Koleksi: list, map, keyword list, dan Enum

Modul Enum bekerja dengan koleksi enumerable apa pun dan menyediakan map, filter, reduce, sort_by, group_by, dan banyak lagi. Map adalah struktur key-value utama; keyword list, seperti [size: 10, color: :red], umum dipakai untuk opsi.

nums = [5, 3, 8, 1]
IO.inspect(Enum.sort(nums))                      # [1, 3, 5, 8]
IO.inspect(Enum.map(nums, &(&1 * 10)))           # [50, 30, 80, 10]
IO.inspect(Enum.filter(nums, fn n -> n > 2 end)) # [5, 3, 8]
IO.puts(Enum.reduce(nums, 0, &+/2))              # 17

user = %{name: "Ann", age: 31}
older = %{user | age: 32}                        # update an existing key
IO.puts(user.age)                                # 31 (unchanged)
IO.puts(older.age)                               # 32
with_city = Map.put(user, :city, "Oslo")
IO.puts(with_city.city)                          # Oslo
IO.inspect(Map.get(user, :email, "none"))        # "none"

Operator capture & membuat fungsi anonim singkat: &(&1 * 10) berarti fn x -> x * 10 end, dan &+/2 merujuk ke fungsi + dengan dua argumen.

Proses dan konkurensi

Fitur khas Elixir adalah proses BEAM: unit eksekusi yang sangat ringan dan terisolasi dengan memorinya sendiri. Proses hanya berkomunikasi dengan mengirim pesan, dan satu mesin dapat menjalankan ratusan ribu proses. Supervisor me-restart proses yang crash, dan inilah dasar pendekatan "let it crash" Elixir untuk ketahanan terhadap gangguan.

parent = self()

spawn(fn ->
  send(parent, {:result, 6 * 7})
end)

receive do
  {:result, value} -> IO.puts("Got #{value}")   # Got 42
after
  1_000 -> IO.puts("timeout")
end

tasks = for n <- 1..3, do: Task.async(fn -> n * n end)
IO.inspect(Task.await_many(tasks))               # [1, 4, 9]

Di aplikasi nyata Anda jarang memanggil spawn secara langsung. Anda memakai abstraksi dari OTP seperti Task, GenServer, Agent, dan Supervisor.

Penanganan error

Elixir yang idiomatis mengembalikan tagged tuple seperti {:ok, value} atau {:error, reason} untuk kegagalan yang sudah diperkirakan dan memakai case atau with untuk menanganinya. Fungsi yang namanya berakhiran !, seperti File.read!/1, memunculkan exception sebagai gantinya. Exception dapat ditangkap dengan try/rescue, tetapi ini jarang dilakukan.

case File.read("missing.txt") do
  {:ok, text} -> IO.puts(text)
  {:error, reason} -> IO.puts("Cannot read: #{reason}")   # Cannot read: enoent
end

with {a, ""} <- Integer.parse("40"),
     {b, ""} <- Integer.parse("2") do
  IO.puts(a + b)                                         # 42
else
  _ -> IO.puts("not a whole number")
end

try do
  String.to_integer("abc")
rescue
  e in ArgumentError -> IO.puts("Error: #{Exception.message(e)}")
end

with merangkai beberapa match dan berhenti pada yang pertama tidak cocok, lalu mengembalikan nilai tersebut. Ini menghindari ekspresi case yang bersarang dalam.

Program lengkap kecil: frekuensi kata

Script ini menghitung kata dalam sebuah teks dan mencetak tiga kata yang paling sering muncul. Ini adalah pipeline Elixir yang khas, disusun dari fungsi String dan Enum.

defmodule WordFreq do
  def top(text, n) do
    text
    |> String.downcase()
    |> String.split(~r/[^a-z']+/, trim: true)
    |> Enum.frequencies()
    |> Enum.sort_by(fn {word, count} -> {-count, word} end)
    |> Enum.take(n)
  end
end

"The cat and the dog. The dog sat, and the cat ran."
|> WordFreq.top(3)
|> Enum.each(fn {word, count} -> IO.puts("#{word}: #{count}") end)
# the: 4
# and: 2
# cat: 2

Langkah selanjutnya

  • Panduan resmi Getting Started di hexdocs.pm dan situs elixir-lang.org.
  • HexDocs, tempat dokumentasi Elixir dan setiap paket Hex dipublikasikan.
  • Panduan framework Phoenix untuk pengembangan web.
  • Elixir School, kurikulum komunitas yang gratis, dan jalur Elixir di Exercism untuk berlatih.

FAQ

Apa perbedaan Elixir dan Erlang?

Keduanya berjalan di virtual machine BEAM yang sama dan dapat saling memanggil kode. Elixir menambahkan sintaks yang terinspirasi Ruby, macro, operator pipe, dan tool seperti Mix dan Hex, sedangkan Erlang adalah bahasa yang lebih tua tempat OTP dibangun.

Apakah Elixir bagus untuk pengembangan web?

Ya. Framework Phoenix cepat dan menangani banyak koneksi simultan, dan LiveView memungkinkan Anda membangun halaman interaktif dengan HTML yang dirender server dan sedikit JavaScript.

Apakah Elixir bertipe statis?

Elixir bertipe dinamis. Versi terbaru menambahkan sistem tipe bertahap berbasis teori himpunan ke dalam compiler, dan banyak tim juga memakai Dialyzer dengan typespec untuk menemukan error tipe.

Apa arti |> di Elixir?

|> adalah operator pipe. x |> f(y) sama dengan f(x, y), sehingga rangkaian transformasi dapat dibaca dari atas ke bawah.

Apa itu file .ex dan .exs?

File .ex dikompilasi sebagai bagian dari proyek, sedangkan file .exs adalah script yang diinterpretasikan saat dijalankan, umum dipakai untuk test dan konfigurasi.

Semua tutorial pemrograman