我如何克服长生不老药中的Protocol.UndefinedError?

How do I overcome Protocol.UndefinedError in elixir?

我正在为奶牛和公牛游戏编写代码。到目前为止,这是我的代码。

defmodule Demo do

    def game() do
        guess = 1234
        secret = Enum.take_random(1..9, 4)
        count(guess, secret)
    end

    defp count(guess, secret) do
        Enum.zip(guess, secret)
                |> Enum.reduce({0, 0}, fn {g, s}, {c, b} ->
                        cond do
                            g == s -> {c, b + 1}
                            g in secret -> {c + 1, b}
                            true  -> {c, b}
                        end
                end)
    end 
end

当我 运行 使用 IO.puts Demo.game 文件时,出现以下错误

(Protocol.UndefinedError) protocol Enumerable not implemented for 1234
(elixir) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) lib/enum.ex:141: Enumerable.reduce/3
(stdlib) lists.erl:1338: :lists.foreach/2
(elixir) lib/stream.ex:1157: Stream.do_zip/3
(elixir) lib/enum.ex:2802: Enum.zip/1
prog.ex:10: Demo.count/2
prog.ex:20: (file)

帮我了解我哪里出错了,以及如何清除错误

编辑:

我把条件改成了你建议的。但是我没有使用 Integer.digits 而是将随机生成的列表转换为字符串以使其可枚举,但我遇到了一个错误。代码如下所示。

defmodule Demo do

def game() do
    guess = Integer.digits(1234)
    secret = Enum.take_random(1..9, 4) |> Enum.map(&to_string/1)
    numOfBullsCows(guess, secret)
end


def numOfBullsCows(guess, secret) do
    Enum.zip(guess, secret)
            |> Enum.reduce({0, 0}, fn 
                    {g, g}, {c, b} -> {c, b + 1}
                    {g, _}, {c, b} when g in secret -> {c + 1, b}
                    _, {c, b}-> {c, b}
            end)
end

结束

错误:

(ArgumentError) invalid args for operator "in", it expects a compile-time proper list or compile-time range on the right side when used in guard expressions, got: secret
(elixir) expanding macro: Kernel.in/2
prog.ex:14: Demo.numOfBullsCows/2
(elixir) expanding macro: Kernel.|>/2
prog.ex:12: Demo.numOfBullsCows/2

我还尝试了另一种方法,我创建了两个单独的函数来检查重复项,然后生成一个没有重复数字的随机数。

defmodule Main do
  def noDuplicates(num) do
    num_li = Integer.digits(num)
    length(num_li) == length(Enum.uniq(num_li))
  end

  def generateNum() do
    num = Enum.random(1000, 9999)
    if noDuplicates(num) == true do
        IO.puts(num)
    else
        generateNum()
    end
  end
end

但是我收到这样的错误

(UndefinedFunctionError) function Enum.random/2 is undefined or private. Did you mean one of:

  * random/1

(elixir) Enum.random(1000, 9999)
prog.ex:8: Main.generateNum/0
prog.ex:17: (file)
(elixir) lib/code.ex:767: Code.require_file/2
        

      

Enum.zip/2 需要两个枚举作为参数,然后你传递 1234, [3, 5, 1, 6] 或类似的(后者是随机生成的 secret,大小为 4 的列表)。

使用 Integer.digits/2 将整数拆分为数字,以便 Enum.zip/2 满意。


旁注:而不是使用cond/1,使用多个函数子句

更符合习惯
...
|> Enum.reduce({0, 0}, fn
 # ⇓  ⇓ same name matches when they are equal
  {g, g}, {c, b} -> {c, b + 1}
 #               ⇓⇓⇓⇓ guard   
  {g, _}, {c, b} when g in secret -> {c + 1, b}
 # catch-all
  _, {c, b}  -> {c, b}
end)