From 95f97fd3c44e49d86a7b44860df93af92c59bf37 Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Tue, 15 Sep 2026 11:42:20 -0700 Subject: [PATCH] lecture 02 --- lectures/02/filename.txt | 3 + lectures/02/lec2.ex | 91 +++++++++++++++++++++++ lectures/02/notes.ex | 157 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 lectures/02/filename.txt create mode 100644 lectures/02/lec2.ex create mode 100644 lectures/02/notes.ex diff --git a/lectures/02/filename.txt b/lectures/02/filename.txt new file mode 100644 index 0000000..43aff52 --- /dev/null +++ b/lectures/02/filename.txt @@ -0,0 +1,3 @@ +hello +world +hello diff --git a/lectures/02/lec2.ex b/lectures/02/lec2.ex new file mode 100644 index 0000000..5794e0b --- /dev/null +++ b/lectures/02/lec2.ex @@ -0,0 +1,91 @@ +defmodule ArithmeticServer do + # --- Server Implementation --- + def start() do + spawn(&loop/0) # capture variable? + end + + defp loop() do + receive do + {from, :square, x} -> + send(from, x * x) + {from, :square_root, x} -> + send(from, (if x < 0, do: :error, else: :math.sqrt(x))) + end + loop() + end + + # --- Client API --- + def square(pid, x) do + send(pid, {self(), :square, x}) + receive do + x -> x + end + end + + def sqrt(pid, x) do + send(pid, {self(), :square_root, x}) + receive do + x -> x + end + end +end + +defmodule Counter do + # --- Server Implementation --- + def start(n \\ 0) do ## double backslash indicated default value, so n defaults to 0 + spawn(fn -> loop(n) end) + end + + defp loop(n) do + receive do + {from, :value} -> + send(from, n) + loop(n) + :inc -> + loop(n + 1) + end + end + + ## --- Client API --- + def value(pid) do + send(pid, self(), :value) + receive do + x -> x + end + end + + def inc(pid) do + send(pid, :inc) + end +end + +# Registered processes dont need to remember process ID +# we can refer to a process by the name when its registered +defmodule RegisteredCounter do + # --- Server Implementation --- + def start(n \\ 0) do + Processs.register(spawn(fn -> loop(n) end), __MODULE__) ## __MODULE__ refers to current module name + end + + defp loop(n) do + receive do + {from, :value} -> + send(from, n) + loop(n) + :inc -> + loop(n + 1) + end + end + + # --- Client API --- + def value() do + send(__MODULE__, {self(), :value}) + receive do + x -> x + end + end + + def inc() do + send(__MODULE__, :inc) + end +end diff --git a/lectures/02/notes.ex b/lectures/02/notes.ex new file mode 100644 index 0000000..8ef5599 --- /dev/null +++ b/lectures/02/notes.ex @@ -0,0 +1,157 @@ +### Bit Strings +# takes last 3 bits of 12 +# takes last 5 bits of 55 +<<12::3, 55::5>> # result: <<71::size(8)>> +# 12 = 0b1100 +# 55 = 0b110111 +# becomes 0b10010111 = 151 + +<<71::7>> # short form of <<71::size(7)>> + +is_binary(<<12::3, 55::4>>) # -> false +# a binary is a bit string where its # of bits is a multiple of 8 +is_binary(<<12::3, 55::5>>) # -> true +is_binary("hello") + +# you can pattern match using bit strings +<> = <<151>> # 151 = 0b10010111 +# x = 4 = 0b100 +# y = 23 = 0b10111 + +<> = <<151, 255, 55, 66>> +# works -> x, y pull its from 151 +# z = <<255, 55, 66>> remaining since its a binary + + +<> = <<151, 255, 55, 66>> +# works -> x, y pull bits from 151 and 255 since looking for 9 bits +# but since 255, 55, 66 are non binary, we canot use z::binary it will fail +# instead we can use z::bits where z takes up the last remaining bits even +# if its non-binary (not a multiple of 8) + +<<_, x, _, y, __::binary>> = "hello!" + +# character(s) 'abc' is okay, but elixir wants you to use +# ~c"" to specify a char list or a single char +~c"abc" + +String.to_charlist("hello") +# returns: ~c"hello" + +s = "안녕하세요" +String.to_charlist(s) # -> [50504, 45397, 54616, 49464, 50836] +Stirng.codepoints(s) # -> ["안", "녕", "하", "세", "요"] + +byte_size(s) # -> 15 bytes + +## concat with a 0 byte at end +s <> <<0>> +# -> since it cant display the unicodes, it will fallback to actually showing +# the 15 bytes and the 0 byte +# -> <<236, 149, 136, 235, 133, 149, 237, 149, 152, 236, 132, 184, 236, 154, 148, 0>> + +# valid ascii code will show as a charlist +[97, 98, 99] # -> ~c"abc" +?a # -> 97 returns a code +?b # -> 98... + +<<_, ?e, x, _::binary>> = "hello" +x # -> 108 + +### LIST COMPREHENSION +for x <- [3, 2, 7, 6, 8], do: (x + 1) +for x <- [3, 2, 7, 6, 8], rem(x, 2) == 0, do: (x * x) + +### MAPS +m = %{"a" => 1, :b => "hello", {1, 2} => "world"} +m[{1, 2}] +m["a"] +m[:b] + +# though typically the keys are atoms +# and can be written like this +m = %{a: 1, b: 2, c: 3} +m[:a] +m.a # or since keys are atoms + +# pattern matchin on a Map +%{c: x} = m +x # -> 3 + +%{m | c: 4} # returns a new map, but does not assign to original m + +for {_, v} <- m, do: v +# -> [3, 1, 2] returns values as list + +# you can use pipe to pipe value to *first argument* of a function +for {_, v} <- m, do: v |> Enum.sum +# -> 6 + +# lets say we want to convert this list to a map +data = ["homer", 55, "bart", 33, "lisa", 99] +Enum.chunk_every(data, 2) # -> [["homer", 55], ["bart", 33], ["lisa", 99]] +for [n, s] <- Enum.chunk_every(data, 2), into: %{}, do: {n, s} + + +s = "नमस्ते" +for <>, do: c +# gets the 18 bytes + + +### CREATING PROCESSES +slow = fn x -> Process.sleep(1000); IO.puts(x) end # simulated slow method +slow.(1) + +f = fn x -> spawn(fn -> slow.(x) end) end +f.(1) + +# lets execute slow 10 times +Enum.each(1..10, slow) # will take 10 seconds, 1->10 +Enum.each(1..10, f) # will spawn a process for each 1->10 so only takes 1 second + +pid = spawn(fn -> Process.sleep(1000); IO.puts("hello") end) +# send(pid, "msg") -> send processes message +# find pid of own processes -> self() + +# lets send ourself hello, all processes have a mailbox +send(self(), "hello") + +# we can read from mailbox +receive do + x -> x +end + +send(self(), {1, 2}) +receive do + {x, y} -> x + y +end + +# flush will empty the mailbox, and shows +# all contents the mailbox before flush +flush + +# not advised since processes can be running different elixir versions +f = fn x -> x * x end +send(self, f) # function brackets are optional, so self is same as self() + +receive do + g -> g.(3) +end + + +# ALIASES +# alias , as: +# e.g. +# alias ArithmeticServer, as: AS + +### FILES +{:ok, content} = File.read("filename.txt") +content |> String.split |> Enum.frequencies |> Enum.sort_by(fn {_, v} -> v end, :desc) +# -> [{"hello", 2}, {"world", 1}] + +elem({1, "hello"}, 0) # -> 1 +elem({1, "hello"}, 1) # -> "hello" + +# pattern match result to only show most common word, i.e. discard word count +[{w, _} | _] = content |> String.split |> Enum.frequencies |> Enum.sort_by(fn {_, v} -> v end, :desc) +w