Skip to content

Instantly share code, notes, and snippets.

@carloscasalar
Last active November 6, 2022 12:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carloscasalar/feb808371364ea8a1d7ce67467a764ef to your computer and use it in GitHub Desktop.
Save carloscasalar/feb808371364ea8a1d7ce67467a764ef to your computer and use it in GitHub Desktop.
Elixir tips and links
defmodule FibonacciWithCache do
def fib(0), do: 0
def fib(1), do: 1
def fib(n) do
cache_pid = init_cache()
value = fib(cache_pid, n)
clean_cache(cache_pid)
value
end
defp fib(cache_pid, 0) do
get_from_cache(cache_pid, 0)
end
defp fib(cache_pid, 1) do
get_from_cache(cache_pid, 1)
end
defp fib(cache_pid, n) do
calculate_fib_storing_in_cache(cache_pid, n, get_from_cache(cache_pid, n))
end
defp calculate_fib_storing_in_cache(cache_pid, n, nil) do
value = fib(cache_pid, n - 1) + fib(cache_pid, n - 2)
update_cache_and_get_value(cache_pid, n, value)
end
defp calculate_fib_storing_in_cache(_cache_pid, _n, value), do: value
defp init_cache do
{:ok, cache_pid} = Agent.start_link(fn -> %{0 => 0, 1 => 1} end)
cache_pid
end
defp clean_cache(cache_pid) do
Agent.stop(cache_pid)
end
defp update_cache_and_get_value(cache_pid, n, value) do
Agent.get_and_update(cache_pid, fn cache_value ->
{value, Map.merge(cache_value, %{n => value})}
end)
end
defp get_from_cache(cache_pid, n) do
Agent.get(cache_pid, fn cache_value -> cache_value[n] end)
end
end
defmodule Lists do
def len([]), do: 0
def len([_head|tail]), do: 1 + len(tail)
def total_sum([]), do: 0
def total_sum([head | tail]), do: head + total_sum(tail)
def double([]), do: []
def double([ head | tail ]), do: [ 2 * head | double(tail)]
def sum_pairs([]), do: []
def sum_pairs([ h1, h2 | t]), do: [ h1 + h2 | sum_pairs(t) ]
def has_even_length([]), do: true
def has_even_length([_singleElement | []]), do: false
def has_even_length([_firstElement, _secondElement | tail]), do: has_even_length(tail)
end
defmodule Nodedemo do
def reverse do
receive do
msg ->
result = msg |> String.reverse()
# Will print the result in the target node
IO.puts(result)
reverse()
end
end
def reverse_and_respond do
receive do
{from_pid, msg} ->
result = msg |> String.reverse()
# Will print the result in the calling node
send(from_pid, result)
reverse()
end
end
end

Exercise with Nodes

Create two nodes:

iex --sname one
iex --sname two

Connect them:

one@ragnamac> Node.connect(:two@ragnamac)
one@ragnamac> Node.list()

Spawn the demo in node two:

two@ragnamac> c "nodedemo.exs"
two@ragnamac> pid = spawn Nodedemo, :reverse, []
two@ragnamac> send pid, "hello"

I can give a name for the process and instead of call id we can use the name

two@ragnamac> Process.register pid, :rev
two@ragnamac> send :rev, "hello"

Now I can also call this process from the node one

one@ragnamac> send {:rev, :two@ragnamac}, "hello"

"olleh " will be printed in the node two because is where IO.puts is being executed even though the return value of the function ("hello") will be printed in node one.

If we want to send back a message we need to provide the calling pid:

two@ragnamac> pid = spawn Nodedemo, :reverse, []
two@ragnamac> Process.register pid, :rev1
two@ragnamac> send :rev1, {self(), "a phrase"}
two@ragnamac> flush()

Now is the pid the one who contains the output. To see it we need to call flush().

defmodule Procs do
def greeter(count) do
receive do
{:boom, reason \\ "dont know why"} ->
exit(reason)
{:reset} ->
greeter(0)
{:add, amount} ->
greeter(amount)
msg ->
IO.puts "#{count}: #{inspect msg}"
greeter(count)
end
end
end

Elixir tips and links

Save struct to yaml

Pasted from https://elixirforum.com/t/convert-elixir-maps-or-structs-to-yaml/6772/10

def to_yaml(yaml_map, indentation \\ "") do
    yaml_map
    |> Map.keys
    |> Enum.map(
      fn key ->
        value = Map.fetch!(yaml_map, key)
        cond do
          is_bitstring(value) -> "#{indentation}#{key}: #{value}"
          is_number(value) -> "#{indentation}#{key}: #{value}"
          is_map(value) -> "#{indentation}#{key}:\n#{to_yaml(value, "#{indentation}  ")}"
        end
      end
    )
    |> Enum.join("\n")
end

Example usage with yaml-elixir:

YamlElixir.read_from_file!("file.yaml")
|> Map.put(:some_key, %{some_nested_key: 123})
|> to_yaml

Example of Fibonacci implementation using Agent to lowerin the big O

defmodule FibonacciWithCache do
  def fib(0), do: 0

  def fib(1), do: 1

  def fib(n) do
    cache_pid = init_cache()
    value = fib(cache_pid, n)
    clean_cache(cache_pid)
    value
  end

  defp fib(cache_pid, 0) do
    get_from_cache(cache_pid, 0)
  end

  defp fib(cache_pid, 1) do
    get_from_cache(cache_pid, 1)
  end

  defp fib(cache_pid, n) do
    calculate_fib_storing_in_cache(cache_pid, n, get_from_cache(cache_pid, n))
  end

  defp calculate_fib_storing_in_cache(cache_pid, n, nil) do
    value = fib(cache_pid, n - 1) + fib(cache_pid, n - 2)
    update_cache_and_get_value(cache_pid, n, value)
  end

  defp calculate_fib_storing_in_cache(_cache_pid, _n, value), do: value

  defp init_cache do
    {:ok, cache_pid} = Agent.start_link(fn -> %{0 => 0, 1 => 1} end)
    cache_pid
  end

  defp clean_cache(cache_pid) do
    Agent.stop(cache_pid)
  end

  defp update_cache_and_get_value(cache_pid, n, value) do
    Agent.get_and_update(cache_pid, fn cache_value ->
      {value, Map.merge(cache_value, %{n => value})}
    end)
  end

  defp get_from_cache(cache_pid, n) do
    Agent.get(cache_pid, fn cache_value -> cache_value[n] end)
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment