СоХабр закрыт.
С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.
user@host:~/$ iex
Erlang/OTP 19 [erts-8.0.2] [source-753b9b9] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
iex(1)> data_in = "123456"
"123456"
"123456"
в массив из из строк, но по одному символу — ["1", "2", "3", "4", "5", "6"]
, а после этого, уже каждый элемент массива преобразуем в целое число: [1, 2, 3, 4, 5, 6]
. Сделаем это, используя каналы (pipe operator):iex(2)> [a,b,c,d,e,f] = data_in \
...(2)> |> String.split("", trim: true) \
...(2)> |> Enum.map(fn(x)-> String.to_integer(x) end)
[1, 2, 3, 4, 5, 6]
String.split
имеет 3 параметра, но в первый будет подставлено data_in
. Результат этого преобразования будет передан в следующую функцию Enum.map
. Первый параметр — опять же не виден, и будет подставлен автоматически. Второй параметр — ничего страшного. Там указывается функция, которая будет вызываться для преобразования каждого элемента массива. Только функцию, мы сразу же определили и передали в качестве параметра. Это называется — функции высшего порядка. Видим, что теперь в переменных a, b, c, d, e, d
находятся числа:iex(4)> a
1
iex(5)> b
2
"+", "-", "*", "/"
).defmodule RC do
def permute([]), do: [[]]
def permute(list) do
for x <- list, y <- permute(list -- [x]), do: [x|y]
end
end
iex(7)> c("perm.ex")
warning: redefining module RC (current version loaded from Elixir.RC.beam)
perm.ex:1
[RC]
iex(9)> RC.permute([1, 2, 3])
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
def comb(0,_), do: [[]]
def comb(_,[]), do: []
def comb(n, [x|xs]) do
(for y <- comb(n - 1, xs), do: [x|y]) ++ comb(n, xs)
end
iex(12)> RC.comb(2, [1,2,3,4])
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
iex> for i <- [:a, :b, :c], j <- [1, 2], do: {i, j}
[a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]
iex(14)> digs1 = RC.permute([a,b,c])
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
iex(14)>digs2 = RC.permute([d,e,f])
[[4, 5, 6], [4, 6, 5], [5, 4, 6], [5, 6, 4], [6, 4, 5], [6, 5, 4]]
iex(19)> vari1 = for i <- ops, j <- digs1, do: {i, j}
[{["+", "-"], [1, 2, 3]}, {["+", "-"], [1, 3, 2]}, {["+", "-"], [2, 1, 3]},
{["+", "-"], [2, 3, 1]}, {["+", "-"], [3, 1, 2]}, {["+", "-"], [3, 2, 1]},
{["+", "*"], [1, 2, 3]}, {["+", "*"], [1, 3, 2]}, {["+", "*"], [2, 1, 3]},
{["+", "*"], [2, 3, 1]}, {["+", "*"], [3, 1, 2]}, {["+", "*"], [3, 2, 1]},
{["+", "/"], [1, 2, 3]}, {["+", "/"], [1, 3, 2]}, {["+", "/"], [2, 1, 3]},
{["+", "/"], [2, 3, 1]}, {["+", "/"], [3, 1, 2]}, {["+", "/"], [3, 2, 1]},
{["-", "*"], [1, 2, 3]}, {["-", "*"], [1, 3, 2]}, {["-", "*"], [2, 1, 3]},
{["-", "*"], [2, 3, 1]}, {["-", "*"], [3, 1, 2]}, {["-", "*"], [3, 2, 1]},
{["-", "/"], [1, 2, 3]}, {["-", "/"], [1, 3, 2]}, {["-", "/"], [2, 1, 3]},
{["-", "/"], [2, 3, 1]}, {["-", "/"], [3, 1, 2]}, {["-", "/"], [3, 2, 1]},
{["*", "/"], [1, 2, 3]}, {["*", "/"], [1, 3, 2]}, {["*", "/"], [2, 1, 3]},
{["*", "/"], [2, 3, 1]}, {["*", "/"], [3, 1, 2]}, {["*", "/"], [3, 2, 1]}]
iex(22)> vari2 = for k <- ops, l <- digs2, do: {k, l}
[{["+", "-"], [4, 5, 6]}, {["+", "-"], [4, 6, 5]}, {["+", "-"], [5, 4, 6]},
{["+", "-"], [5, 6, 4]}, {["+", "-"], [6, 4, 5]}, {["+", "-"], [6, 5, 4]},
{["+", "*"], [4, 5, 6]}, {["+", "*"], [4, 6, 5]}, {["+", "*"], [5, 4, 6]},
{["+", "*"], [5, 6, 4]}, {["+", "*"], [6, 4, 5]}, {["+", "*"], [6, 5, 4]},
{["+", "/"], [4, 5, 6]}, {["+", "/"], [4, 6, 5]}, {["+", "/"], [5, 4, 6]},
{["+", "/"], [5, 6, 4]}, {["+", "/"], [6, 4, 5]}, {["+", "/"], [6, 5, 4]},
{["-", "*"], [4, 5, 6]}, {["-", "*"], [4, 6, 5]}, {["-", "*"], [5, 4, 6]},
{["-", "*"], [5, 6, 4]}, {["-", "*"], [6, 4, 5]}, {["-", "*"], [6, 5, 4]},
{["-", "/"], [4, 5, 6]}, {["-", "/"], [4, 6, 5]}, {["-", "/"], [5, 4, 6]},
{["-", "/"], [5, 6, 4]}, {["-", "/"], [6, 4, 5]}, {["-", "/"], [6, 5, 4]},
{["*", "/"], [4, 5, 6]}, {["*", "/"], [4, 6, 5]}, {["*", "/"], [5, 4, 6]},
{["*", "/"], [5, 6, 4]}, {["*", "/"], [6, 4, 5]}, {["*", "/"], [6, 5, 4]}]
iex(24)> length(vari1)
36
{операции, числа}
. По количеству параметров, с помощью механизма матчинга функций, будет выбрана единственная функция. В ней, значения из кортежа будут «сматчены» в две переменных ops
и stack
и уже вызовется функция с двумя параметрами. В Elixir, как и в Erlang, вместо if
и else if
, используется матчинг в функции, по значению входящих параметров. Причем, сработает та функция, которая описана раньше. В нашем случае, пока в первом параметре не будет пустой массив ([]), будет выполняться третья функция. Но как только массив будет пустым, сработает вторая функция, которая выдаст нам результат. Этот пример — типичный пример реализации хвостовой рекурсии. Все вычисления происходят в третьей функции, где от массива операций берется первая операция и «хвост». Из массива с числами, который исполняет у нас роль стека, выбыраются два числа и хвост. Потом функция вызывается рекурсивно, пока данные не закончатся. Реализация циклов через рекурсию — тоже типичный подход. А непосредственно для рассчетов, вызывается calс с тремя параметрами (функция и два числа). При выполнении деления на ноль, мы получаем ошибку. Поэтому, до функции выполнения деления, вместо условий, добавим функцию, которая с помощью матчинга «поймает» ноль на входе делителя, и выдаст атом :err в качестве результата. Соответственно, перед всеми операциями, добавим матчинг на предмет того, что первый или второй вариант может быть :err, в этом случае итог будет тот же. def calc({ops,stack}), do: calc(ops,stack)
def calc([], stack), do: hd(stack)
def calc(ops, stack) do
[op|ops_tail] = ops
[a,b|stack_tail] = stack
calc(ops_tail, [calc(op, a, b)|stack_tail])
end
def calc(_, :err,_), do: :err
def calc(_, _,:err), do: :err
def calc("*", a, b), do: a * b
def calc("/", _, 0), do: :err
def calc("/", a, b), do: a / b
def calc("+", a, b), do: a + b
def calc("-", a, b), do: a - b
iex(27)> vari_all = for m <- vari1, n <- vari2, do: {m, n}
iex(30)> vari_all \
...(30)> |> Enum.filter(fn({left, right})-> RC.calc(left) == RC.calc(right) end)
[{{["+", "-"], [1, 3, 2]}, {["+", "/"], [4, 6, 5]}},
{{["+", "-"], [1, 3, 2]}, {["+", "/"], [6, 4, 5]}},
{{["+", "-"], [2, 3, 1]}, {["-", "*"], [6, 5, 4]}},
{{["+", "-"], [3, 1, 2]}, {["+", "/"], [4, 6, 5]}},
{{["+", "-"], [3, 1, 2]}, {["+", "/"], [6, 4, 5]}},
{{["+", "-"], [3, 2, 1]}, {["-", "*"], [6, 5, 4]}},
{{["+", "*"], [2, 3, 1]}, {["+", "-"], [4, 6, 5]}},
{{["+", "*"], [2, 3, 1]}, {["+", "-"], [6, 4, 5]}},
{{["+", "*"], [3, 2, 1]}, {["+", "-"], [4, 6, 5]}},
{{["+", "*"], [3, 2, 1]}, {["+", "-"], [6, 4, 5]}}, ...
def expr_to_str({ops, stack}), do: expr_to_str(ops, stack)
def expr_to_str(ops, stack) do
[d1, d2, d3] = Enum.map(stack, fn(x)-> Integer.to_string(x) end)
[op1, op2] = ops
to_string(["(", d1, op1, d2, ")", op2, d3])
end
iex(37)> vari_all \
...(37)> |> Enum.filter(fn({left, right})-> RC.calc(left) == RC.calc(right) end) \
...(37)> |> Enum.map(fn({left, right})-> \
...(37)> RC.expr_to_str(left) <> " = " <> \
...(37)> RC.expr_to_str(right) \
...(37)> end)
["(1+3)-2 = (4+6)/5", "(1+3)-2 = (6+4)/5", "(2+3)-1 = (6-5)*4",
"(3+1)-2 = (4+6)/5", "(3+1)-2 = (6+4)/5", "(3+2)-1 = (6-5)*4",
"(2+3)*1 = (4+6)-5", "(2+3)*1 = (6+4)-5", "(3+2)*1 = (4+6)-5",
"(3+2)*1 = (6+4)-5", "(1+3)/2 = (4+6)/5", "(1+3)/2 = (6+4)/5",
"(2+3)/1 = (4+6)-5", "(2+3)/1 = (6+4)-5", "(3+1)/2 = (4+6)/5",
"(3+1)/2 = (6+4)/5", "(3+2)/1 = (4+6)-5", "(3+2)/1 = (6+4)-5",
"(1-3)*2 = (5-6)*4", "(2-1)*3 = (4+5)-6", "(2-1)*3 = (5+4)-6",
"(3-1)*2 = (6-5)*4", "(1*3)/2 = (4+5)/6", "(1*3)/2 = (5+4)/6",
"(2*3)/1 = (5-4)*6", "(3*1)/2 = (4+5)/6", "(3*1)/2 = (5+4)/6",
"(3*2)/1 = (5-4)*6"]
iex(39)> data_in = "666013"
"666013"
iex(40)> [a,b,c,d,e,f] = data_in \
...(40)> |> String.split("", trim: true) \
...(40)> |> Enum.map(fn(x)-> String.to_integer(x) end)
[6, 6, 6, 0, 1, 3]
iex(41)> ops = RC.comb(2, ["+","-","*","/"])
[["+", "-"], ["+", "*"], ["+", "/"], ["-", "*"], ["-", "/"], ["*", "/"]]
iex(42)> digs1 = RC.permute([a,b,c])
[[6, 6, 6], [6, 6, 6], [6, 6, 6], [6, 6, 6], [6, 6, 6], [6, 6, 6]]
iex(43)> digs2 = RC.permute([d,e,f])
[[0, 1, 3], [0, 3, 1], [1, 0, 3], [1, 3, 0], [3, 0, 1], [3, 1, 0]]
iex(44)> vari1 = for i <- ops, j <- digs1, do: {i, j}
...
iex(45)> vari2 = for k <- ops, l <- digs2, do: {k, l}
iex(46)> vari_all = for m <- vari1, n <- vari2, do: {m, n}
iex(47)> vari_all \
...(47)> |> Enum.filter(fn({left, right})-> RC.calc(left) == RC.calc(right) end) \
...(47)> |> Enum.map(fn({left, right})-> \
...(47)> RC.expr_to_str(left) <> " = " <> \
...(47)> RC.expr_to_str(right) \
...(47)> end)
["(6+6)/6 = (0+3)-1", "(6+6)/6 = (3+0)-1", "(6+6)/6 = (0+3)-1",
"(6+6)/6 = (3+0)-1", "(6+6)/6 = (0+3)-1", "(6+6)/6 = (3+0)-1",
"(6+6)/6 = (0+3)-1", "(6+6)/6 = (3+0)-1", "(6+6)/6 = (0+3)-1",
"(6+6)/6 = (3+0)-1", "(6+6)/6 = (0+3)-1", "(6+6)/6 = (3+0)-1",
"(6-6)*6 = (1+3)*0", "(6-6)*6 = (3+1)*0", "(6-6)*6 = (1-3)*0",
"(6-6)*6 = (3-1)*0", "(6-6)*6 = (0*1)/3", "(6-6)*6 = (0*3)/1",
"(6-6)*6 = (1*0)/3", "(6-6)*6 = (3*0)/1", "(6-6)*6 = (1+3)*0",
"(6-6)*6 = (3+1)*0", "(6-6)*6 = (1-3)*0", "(6-6)*6 = (3-1)*0",
"(6-6)*6 = (0*1)/3", "(6-6)*6 = (0*3)/1", "(6-6)*6 = (1*0)/3",
"(6-6)*6 = (3*0)/1", "(6-6)*6 = (1+3)*0", "(6-6)*6 = (3+1)*0",
"(6-6)*6 = (1-3)*0", "(6-6)*6 = (3-1)*0", "(6-6)*6 = (0*1)/3",
"(6-6)*6 = (0*3)/1", "(6-6)*6 = (1*0)/3", "(6-6)*6 = (3*0)/1",
"(6-6)*6 = (1+3)*0", "(6-6)*6 = (3+1)*0", "(6-6)*6 = (1-3)*0",
"(6-6)*6 = (3-1)*0", "(6-6)*6 = (0*1)/3", "(6-6)*6 = (0*3)/1",
"(6-6)*6 = (1*0)/3", "(6-6)*6 = (3*0)/1", "(6-6)*6 = (1+3)*0",
"(6-6)*6 = (3+1)*0", "(6-6)*6 = (1-3)*0", "(6-6)*6 = (3-1)*0",
"(6-6)*6 = (0*1)/3", "(6-6)*6 = (0*3)/1", ...]
комментарии (16)