MyVal (version 2)
Documentation on @types, @specs, StreamData, & TypeCheck
Types & Specs:
- https://hexdocs.pm/elixir/typespecs.html
- https://elixir-lang.org/getting-started/typespecs-and-behaviours.html
- https://hexdocs.pm/elixir/1.13.2/typespecs.html
StreamData:
- https://hexdocs.pm/stream_data/StreamData.html
- https://elixirschool.com/en/lessons/libraries/stream-data/
- https://github.com/whatyouhide/stream_data
TypeCheck:
- https://github.com/Qqwy/elixir-type_check
- https://hexdocs.pm/type_check/readme.html
- https://hexdocs.pm/type_check/type-checking-and-spec-testing-with-typecheck.html
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()