Enum.member? leads to "protocol Enumerable not implemented for :ok"

Here’s a simple module that’s supposed to print the first letter that appears more than once.

defmodule O do
  def check(str) do
    str
    |> String.graphemes
    |> Enum.reduce([], fn(x, acc) ->
      case Enum.member?(acc, x) do
        true -> IO.puts x
        false -> [x | acc]
      end
    end)
  end
end

O.check("ABCBAA")

And here’s the error that I’m getting after printing the results.
What’s wrong here? Thanks

[Desktop] elixir demo.exs
B
** (Protocol.UndefinedError) protocol Enumerable not implemented for :ok
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:166: Enumerable.member?/2
    (elixir) lib/enum.ex:1538: Enum.member?/2
    demo.exs:7: anonymous fn/2 in O.check/1
    (elixir) lib/enum.ex:1925: Enum."-reduce/3-lists^foldl/2-0-"/3

Elixir 1.7.2 (compiled with Erlang/OTP 21)

This returns :ok. You want to return acc most likely.

2 Likes

But now it says
** (Protocol.UndefinedError) protocol Enumerable not implemented for “B”

Works fine for me

defmodule O do
  def check(str) do
    str
    |> String.graphemes
    |> Enum.reduce([], fn(x, acc) ->
      case Enum.member?(acc, x) do
        true -> 
          IO.puts x
          acc
        false -> [x | acc]
      end
    end)
  end
end

O.check("ABCBAA")
3 Likes

Is it possible to return only the first occurrence (just B instead of BAA)?

the only way I see it is

defmodule O do
  def check(str) do
    str 
    |> String.graphemes
    |> Enum.reduce_while([], fn(x, acc) ->
      if Enum.member?(acc, x) do
        new_acc = Enum.reject(acc, fn(el) -> el != x end)
        {:halt, new_acc}
      else
        {:cont, [x | acc]}
      end
    end)
  end
end

IO.puts O.check("ABCBAA")

is this a better approach?

defmodule O do
  def check(str) do
    str
    |> String.graphemes
    |> check_list()
  end

  defp check_list([h|t], acc \\ []) do
    case Enum.member?(acc, h) do
      true -> h
      false -> check_list(t, [h | acc])
    end
  end
end