Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

MyVal (version 2)

MyVal2.livemd

MyVal (version 2)

Documentation on @types, @specs, StreamData, & TypeCheck

Types & Specs:

StreamData:

TypeCheck:

Mix.install([
  {:type_check, "~> 0.10.0"},
  {:stream_data, "~> 0.5.0"}
])

Add functions to the MyVal module

defmodule MyVal do
  use TypeCheck
  defstruct [:history]

  @type! t :: %MyVal{history: list(number())}

  def new(val), do: %MyVal{history: [{val, {nil, nil}}]}

  def val(%MyVal{history: []}), do: nil

  def val(%MyVal{history: [{hd_val, {_hd_op, _hd_operand}} | _tl]}), do: hd_val

  def peek(%MyVal{history: [{hd_val, {_hd_op, _hd_operand}} | _tl]} = my_val) do
    IO.inspect(hd_val, label: "current value of MyVal instance")
    my_val
  end

  def add(%MyVal{history: hist} = my_val, new_val) when is_list(hist) do
    cur_val = my_val |> val()
    %{my_val | history: [{cur_val + new_val, {:+, new_val}} | hist]}
  end

  def subtract(%MyVal{history: hist} = my_val, new_val) when is_list(hist) do
    cur_val = my_val |> val()
    %{my_val | history: [{cur_val - new_val, {:-, new_val}} | hist]}
  end

  def multiply(%MyVal{history: hist} = my_val, new_val) when is_list(hist) do
    cur_val = my_val |> val()
    %{my_val | history: [{cur_val * new_val, {:*, new_val}} | hist]}
  end

  def divide(%MyVal{history: hist} = my_val, new_val) when is_list(hist) do
    cur_val = my_val |> val()
    %{my_val | history: [{cur_val / new_val, {:/, new_val}} | hist]}
  end

  def view(%MyVal{history: _hist} = my_val) do
    %{val: MyVal.val(my_val), my_val: my_val}
  end

  def history(%MyVal{history: hist}) do
    hist
    |> Enum.reverse()
  end

  def show_history(%MyVal{history: _hist} = my_val) do
    {{first, {nil, nil}}, rest} = first_rest(my_val)

    rest
    |> Enum.reduce(
      ["#{first}"],
      &stringify_next_line/2
      # fn {val, {op, operand}}, acc -> ["#{op} #{operand} = #{val}" | acc] end
    )
    |> Enum.reverse()
  end

  def show_history2(%MyVal{history: hist}) do
    hist
    |> Enum.reverse()
    |> Enum.reduce(
      [],
      &stringify_next_line/2
      # fn {val, {op, operand}}, acc -> ["#{op} #{operand} = #{val}" | acc] end
    )
    |> Enum.reverse()
  end

  def recalculate(%MyVal{history: _hist} = my_val) do
    {{first, {nil, nil}}, rest} = first_rest(my_val)

    Enum.reduce(rest, first, fn {_val, {op, operand}}, acc ->
      apply(Kernel, op, [acc, operand])
      # Kernel.+(acc, operand)
    end)
  end

  defp stringify_next_line({val, {nil, nil}} = entry, acc) do
    [stringify_entry(entry) | acc]
  end

  defp stringify_next_line({_val, {_op, _operand}} = entry, acc) do
    [stringify_entry(entry) | acc]
  end

  defp stringify_entry({val, {nil, nil}}) do
    "#{val}"
  end

  defp stringify_entry({val, {op, operand}}) do
    "#{op} #{operand} = #{val}"
  end

  defp first_rest(%MyVal{history: _hist} = my_val) do
    # returns value like {{first, {nil, nil}}, rest}
    my_val
    |> history()
    |> List.pop_at(0)
  end
end

(Failed) attempt to get Elixir to display MyVal instances as just their current value

defimpl Inspect, for: MyVal do
  def inspect(my_val) do
    # %MyVal{my_value: #{my_val.value}, history: #{my_val.history}}
    """
    #{my_val |> MyVal.val()}
    """
  end
end
defimpl String.Chars, for: MyVal do
  def to_string(my_val) do
    # %MyVal{my_value: #{my_val.value}, history: #{my_val.history}}
    """
    #{my_val |> MyVal.val()}
    """
  end
end
String.Chars.impl_for([])

Use MyVal module

MyVal.new(-8)
|> MyVal.add(11)
|> MyVal.add(4)
|> MyVal.add(8)
|> MyVal.view()

# |> (fn my_val -> %{val: MyVal.val(my_val), my_val: my_val} end).()
# |> inspect()
MyVal.new(-8)
|> MyVal.add(11)
|> MyVal.add(4)
|> MyVal.subtract(8)
|> MyVal.add(11)
|> MyVal.multiply(10)
|> MyVal.subtract(10)
|> MyVal.divide(10)
|> MyVal.view()
MyVal.new(-8)
|> MyVal.add(11)
|> MyVal.add(4)
|> MyVal.subtract(8)
|> MyVal.add(11)
|> MyVal.multiply(10)
|> MyVal.subtract(10)
|> MyVal.divide(10)
|> MyVal.show_history()
MyVal.new(-8)
|> MyVal.add(11)
|> MyVal.add(4)
|> MyVal.subtract(8)
|> MyVal.add(11)
|> MyVal.multiply(10)
|> MyVal.subtract(10)
|> MyVal.divide(10)
|> MyVal.show_history2()
MyVal.new(88)
|> MyVal.multiply(17)
|> MyVal.add(1_000_000)
|> MyVal.peek()
|> MyVal.divide(100)
|> MyVal.val()