问题描述
我是函数式编程的忠实粉丝,我确实了解模式匹配和多重分派,这就是我发现谓词分派的方式,并且一直想知道它是否与模式匹配有关。
我确实阅读了这个 SO 线程:What is Predicate Dispatch 但仍然无法得到有关模式匹配和谓词调度之间关系的答案。我相信模式匹配和谓词调度确实相似,如果不等价的话,但想听听一些意见。
考虑这个 Elixir 代码:
block in invoke_with_call_chain' C:/Ruby266-x64/lib/ruby/2.6.0/monitor.rb:235:in
看起来函数是在运行时根据输入参数的属性选择的,这正是谓词分派。 invoke_with_call_chain' C:/Ruby266-x64/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:243:in
部分看起来类似于本文中提出的谓词分派方式:http://web.cs.ucla.edu/~todd/research/oopsla04.pdf
请分享您对此事的了解/意见。
解决方法
我没听说过“谓词分派”,但我可以和你分享一些关于 Elixir 如何处理函数子句中模式匹配的见解。
Elixir 函数中的模式匹配有点像 Web 应用程序中的路由:函数被尝试按照列出的顺序,直到可以进行匹配,然后执行该函数。这意味着最特定的匹配应该列在第一,而最不特定的(或全部)应该列在最后。事实上,如果您以一种无法访问的方式构造函数,如果您使用适当的 linter/语言服务器,您将看到警告。
例如,这些定义是有问题的:
def something(_) do
# This would always match
end
def something(%{foo: nil}) do
# so this can never match; the previous function def is too broad
end
我们可以稍微重写您的示例以仅使用模式匹配(而不是使用模式匹配和保护):
def function(%{x: true} = struct) do
# do something when x == true
end
def function(%{y: nil}) do
# do something else when x != true AND y == nil
end
def function(struct) do
# default case
end
编译器实际上将所有这些转换为一系列条件,但函数子句提供了很好的表达语法。