【发布时间】:2021-12-05 23:34:37
【问题描述】:
我正在阅读教科书使用 Elixir 学习函数式编程,我对示例问题的一些给出的答案不满意。问题的中心是检查井字游戏的获胜者,但我会尝试将其归结为本质。假设我们要检查一些值元组的有效性并返回一些东西,例如
iex(1)> some_function({:some, :list, :of, :values})
{:ok}
iex(2)> some_function({:some, :other, :list, :of, :values})
{:error}
教科书的解决方案是完全匹配允许的值:
def some_function({_, _, :of, _}), do: {:ok}
def some_function(_everything_else), do: {:error}
但是,我不喜欢这种解决方案,因为在大量案例中它变得非常重复。我试图更直接地对逻辑进行编码,但我想不出一种惯用的方法来做到这一点。我试过了:
def some_function(input) do
test1(input) or
test2(input) or
{:error}
end
def test1({:some, :case}), do: false
def test1({:some, :other, :case}), do: {:ok}
def test2({:some, :case}), do: false
def test2({:some, :other, :case}), do: {:ok}
这在所有测试都失败时有效,但是当其中任何一个测试通过时,您会收到一个错误,您无法将 {:ok} 与布尔值进行比较。虽然我意识到这很可怕,但我最终做的是
def some_function(input) do
cond do
test1(input) -> test1(input)
test2(input) -> test2(input)
fail(input) -> {:error}
end
end
def test1({:some, :case}), do: false
def test1({:some, :other, :case}), do: {:ok}
def test2({:some, :case}), do: false
def test2({:some, :other, :case}), do: {:ok}
def fail(_input), do: true
从黑盒的角度来看,这实际上表现得非常完美,但是代码带有重复性(尤其是每个测试必须评估两次才能确定真实性并捕获值)。给定一系列要评估的测试用例,是否有一种惯用的方式返回第一个真值?我精通 python 和 C,但我试图避免使用 if 并以“功能”风格进行。
【问题讨论】:
-
“我不喜欢这个解决方案,因为在很多情况下它会变得非常重复” -> 如果它清晰、简单且中肯,那么重复没有错。例如,我认为代表有效获胜状态的函数子句列表非常清晰。
-
@AdamMillerchip 我想这是一个公平的对比。我内心的程序员声音说这太不雅了,但鉴于函数式代码(至少对我而言)比命令式代码更难以推理,也许我应该在“明确和清晰”方面犯错更多" 而不是 "优雅"
标签: functional-programming elixir pattern-matching