Tia*_*ões 1 functional-programming elixir pattern-matching
一般来说,函数式编程以更清晰和简洁而自豪。您没有副作用/状态管理的事实使开发人员更容易推理他们的代码并确保行为。这个真理能达到多远?
我仍在学习 Elixir,但给出了 Coding Gnome 的代码:
def make_move(game = %{ game_state: state }, _guess)
when state in [:won, :lost] do
...
end
def make_move(game = %{ game_state: state }, _guess)
when state in [:pending] do
...
end
def make_move(game, guess) do
...
end
Run Code Online (Sandbox Code Playgroud)
人们可以在 Javascript 中毫不费力地将其编写为:
def make_move(game = %{ game_state: state }, _guess)
when state in [:won, :lost] do
...
end
def make_move(game = %{ game_state: state }, _guess)
when state in [:pending] do
...
end
def make_move(game, guess) do
...
end
Run Code Online (Sandbox Code Playgroud)
不考虑 Elixir 编译器提供的所有类型/结构安全性,Elixir 程序员必须先阅读整个文件,然后才能确保没有具有不同签名的函数劫持另一个函数,对吗?我觉得这会增加程序员的开销,因为这是你必须考虑的另一件事,甚至在查看函数的实现之前。
除此之外,我觉得这是一种误导,因为make_move除非您事先知道所有其他函数和签名类型,否则您无法 100% 确定某个案例最终会在该通用函数中结束,而使用条件,您有更清晰的路径流动。
这可以用更好的方式重写吗?这些抽象在什么时候开始对程序员产生影响?
我认为这主要归结为偏好,并且通常带有简单条件的模式匹配的简单练习不会显示“清晰”模式匹配可以提供的范围。但我怀疑是因为我更喜欢模式匹配,无论如何,我会咬牙切齿。
在这种情况下,可以说 switch 更具可读性和直接性,但请注意,没有什么可以阻止您在 Elixir(或 erlang)中编写非常相似的东西
def make_move(game = %{ game_state: state }, _guess) do
case state do
state when state in [:won, :lost] -> # do things
:pending -> # do things
_else -> # do other things
end
end
Run Code Online (Sandbox Code Playgroud)
关于相同函数名的不同函数子句的放置,如果它们没有组合在一起,elixir 将发出警告,因此最终只是您有责任以正确的顺序将它们组合在一起(它也会警告您,如果根据定义,任何分支都是不可到达的,就像在任何具有匹配项的特定分支之前放置一个 catch all 一样)。
但是我认为,例如,如果您对pending状态的匹配要求稍作更改,那么在我看来,以 erlang/elixir 方式编写它开始变得更加清晰。假设当处于状态时,pending有两种不同的执行路径,这取决于是轮到您还是其他什么。
现在你可以只用函数签名来编写 2 个特定的分支:
def make_move(game = %{ game_state: :pending, your_turn: true }, _guess) do
# do stuff
end
def make_move(game = %{ game_state: :pending }, _guess) do
# do stuff
end
Run Code Online (Sandbox Code Playgroud)
要在 JS 中做到这一点,你需要有另一个开关,或者另一个 if。如果您有更复杂的匹配模式,那么它很容易变得难以遵循,而在长生不老药上,我认为路径非常清晰。
如果其他条件可能更棘手,比如它是什么时候,:pending并且stack保存列表的键上没有任何东西,然后再次匹配变为:
def make_move(game = %{ game_state: :pending, your_turn: true, stack: [] }, _guess) do
或者,如果有另一个分支取决于堆栈中的第一项是否特定:
def make_move(game = %{ game_state: :pending, your_turn: true, player_id: your_id, stack: [%AnAlmostTypedStruct{player: your_id} | _] }, _guess) do
这里 erlang/elixir 只会匹配它,如果your_id它在模式中使用的两个地方都相同。
而且,您在 JS 中说“没有幻想”,但是在 Elixir/Erlang 中,不同的函数头/arity/模式匹配没什么特别的,就像该语言在低得多的级别支持基于 switch/case 的语句一样(在模块编译级别?)。
我希望在 JS 中有有效的模式匹配和不同的函数子句(不仅仅是解构)。