Current section
Files
Jump to
Current section
Files
lib/exun_ui.ex
defmodule Exun.UI do
alias Exun.Eq
alias Exun.Collect
@defop %{
:deriv => {110, "'"},
:integ => {110, "$"},
:elev => {100, "^"},
:mult => {90, "*"},
:divi => {90, "/"},
:suma => {50, "+"},
:rest => {50, "-"},
:equal => {20, "="},
:numb => {200, nil},
:unit => {200, nil},
:vari => {200, nil},
:fcall => {200, nil},
}
@moduledoc """
Parses a tree and transform to string in User Readable form
"""
@doc ~S"""
Translate tree to human readable math expression:
```
iex(1)> {_tree, _deps} = Exun.parse "4*x^(y+1)/z",%{"z"=>"y+1"}
{{:divi,
{:mult, {:numb, 4}, {:elev, {:vari, "x"}, {:suma, {:vari, "y"}, {:numb, 1}}}},
{:vari, "z"}}, %{{:vari, "z"} => {:suma, {:vari, "y"}, {:numb, 1}}}}
```
"""
def tostr(tree) do
tree
# |> IO.inspect(label: "tostr1,orig")
|> Eq.denorm()
# |> IO.inspect(label: "tostr2,denorm")
|> its()
|> aesthetic()
end
defp aesthetic(str) do
newstr = aest(str)
if str == newstr, do: newstr, else: aest(newstr)
end
defp aest(str) do
%{"+-" => "-", "-+" => "-", "--" => "+", "++" => "+"}
|> Enum.reduce(str, fn {k, v}, str -> String.replace(str, k, v) end)
end
defp its({:mult, {:numb, -1}, a}), do: "-" <> its(a)
defp its({:mult, a, {:numb, -1}}), do: "-" <> its(a)
defp its({:mult, {:divi, {:numb, 1}, a}, b}), do: its({:divi, b, a})
defp its({:mult, a, {:elev, b, {:numb, n}}}) when n < 0, do: its({:divi, a, {:elev, b, {:numb, -n}}})
defp its({:mult, {:elev, b, {:numb, n}}, a}) when n < 0, do: its({:divi, a, {:elev, b, {:numb, -n}}})
defp its({:mult, b, {:divi, {:numb, 1}, a}}), do: its({:divi, b, a})
defp its({:vari, var}), do: var
defp its({:elev, a, {:numb, 1}}), do: its(a)
defp its({:elev, a, {:numb, -1}}), do: its({:divi, {:numb, 1}, a})
defp its({:fcall, name, args}) when is_list(args) do
name <>
"(" <>
Enum.reduce(args, "", fn el, ac ->
case ac do
"" -> its(el)
_ -> ac <> ", " <> its(el)
end
end) <> ")"
end
defp its({:unit, n, tree}), do: its(n) <> "[" <> its(Collect.coll(tree)) <> "]"
defp its({:numb, n}), do: if n == floor(n), do: to_string(floor(n)), else: to_string(n)
defp its({:deriv, a, {:vari, x}}), do: its(a) <> "'" <> x
defp its({:integ, f, var}), do: "$"<>its(f)<>","<>its(var)
defp its({op, l, r}) do
# IO.inspect([op,l,r])
{hpri, hstr} = @defop[op]
{lpri, _} = @defop[l |> elem(0)]
{rpri, _} = @defop[r |> elem(0)]
ltxt = its(l)
rtxt = its(r)
conctostr(hpri, hstr, lpri, ltxt, rpri, rtxt)
end
defp conctostr(hpri, hstr, lpri, ltxt, rpri, rtxt) do
cond do
hpri > lpri and hpri > rpri ->
"(" <> ltxt <> ")" <> hstr <> "(" <> rtxt <> ")"
hpri > lpri ->
"(" <> ltxt <> ")" <> hstr <> rtxt
hpri > rpri ->
ltxt <> hstr <> "(" <> rtxt <> ")"
true ->
ltxt <> hstr <> rtxt
end
end
end