0

I started like 2-3 days ago doing some Elixir and I picked up an exercise to implement a BST.

So far all have been smooth with the learning but I dont get why I am having an error on my add method with my input BST.add([5, 7, 6, 3, 4], 12) |> BST.pre_order()

Here a snipper of the code.

def new([]), do: []
def new([head | tail]) do
  insert(nil, head)
  |> insert_recursive(tail)
end
def add(pre_order_tree, element) when is_list(pre_order_tree) do
  [pre_order_tree | element]
    |> new
end

defp insert_recursive(root, []), do: root
defp insert_recursive(root, [head | tail]) do
  insert(root, head)
  |> insert_recursive(tail)
end

defp insert(tree, value) when is_nil(tree) do
  %Leaf{value: value}
end
defp insert(tree = %Leaf{}, value) do
  if value > tree.value do
    %Leaf{tree | right_leaf: insert(tree.right_leaf, value)}
  else
    %Leaf{tree | left_leaf: insert(tree.left_leaf, value)}
  end
end

BST.new([5, 7, 6, 3, 4]) |> BST.pre_order()

This code works without issues, but when I call it with the new methods I get an error and the list that I pass is treated as a single element.

iex(32)> BST.add([5, 7, 6, 3, 4], 12) |> BST.pre_order()
** (FunctionClauseError) no function clause matching in BST.insert_recursive/2
    The following arguments were given to BST.insert_recursive/2:
        # 1
        %Leaf{left_leaf: nil, right_leaf: nil, value: [5, 7, 6, 3, 4]}
        # 2
        12
    b_s_t.ex:32: BST.insert_recursive/2
glennsl
  • 28,186
  • 12
  • 57
  • 75
Patrick Vibild
  • 351
  • 4
  • 16
  • Can you please add your `insert_recursive` definition? – Guru Stron Aug 22 '20 at 11:20
  • I have added more functions that is been used in my module. I have trying to see what happens and [pre_order_tree | element] is making a [[1,2,3], 5] I try to flatten it with the Module List but I am getting some errors. – Patrick Vibild Aug 22 '20 at 11:24

1 Answers1

1

I fixed the code changing the next function.

def add(pre_order_tree, element) when is_list(pre_order_tree) do
    Enum.concat(pre_order_tree, [element])
      |> new
  end

I really don't know what is exactly the difference with the previous function.

def add(pre_order_tree, element) when is_list(pre_order_tree) do
  [pre_order_tree | element]
    |> new
end

So if someone could explain to me that It would be pretty appreciated.

Patrick Vibild
  • 351
  • 4
  • 16
  • 2
    I'm pretty sure when you use `[x | y]` syntax in Elixir, `x` has to be a single element and `y` has to be a list. – Peaceful James Aug 22 '20 at 11:37
  • Check out the pattern matching section here: https://elixir-lang.org/getting-started/pattern-matching.html, as James said you need to look for the [head | tail] bit, the head represents the first element, with y representing the remaining – Mark Aug 22 '20 at 11:46
  • 1
    "y has to be a list": indeed, but in case it is not it doesn't crash, it will build an "improper list" instead. I believe this is what was happening. [This thread](https://stackoverflow.com/a/1922724/13979518) explains improper lists quite well (in Erlang but it's literally the same thing). Side note: often in Elixir you want to use prepend and not append/++/concat, but you might have to reverse the list at the end. – sabiwara Aug 22 '20 at 12:26