通过模式匹配检查长度是否均匀

Mer*_*kos 3 elixir pattern-matching

我看到了这个片段,但我不明白这是如何通过模式匹配来完成的。如果有人可以向我(或其他可能不理解这一点的人)解释一下,那就太好了

def even_length?([]) do
  true
end

def even_length?([_head | tail]) do
  !even_length?(tail)
end
Run Code Online (Sandbox Code Playgroud)

当给出诸如[1, 2]或 之类的输入时,我只是迷失了方向[3, 4, 5]

提前致谢。

代码来源:https://gist.github.com/mauricoabreu/8fdb64bef6a938dd1e34ac15e9268d4d

She*_*yar 5

这是一段非常聪明的代码,但如果您逐步遵循它的执行过程,可能会更容易理解。

在我们看几个例子之前,重要的是你要了解 Elixir 将列表实现为链接列表,并且每个列表都有 ahead和 a tail,其中尾部本身是一个单独的列表术语。每个列表(空列表除外)都可以写成[ head | tail ]

[1] == [ 1 | [] ]
# => true

[3, 2, 1] == [ 3 | [2, 1] ]
# => true

[3, 2, 1] == [ 3 | [ 2 | [ 1 | [] ] ] ]
# => true
Run Code Online (Sandbox Code Playgroud)

1. 空列表[]

调用even_length?([])将匹配第一个签名并直接返回true,因为这是我们的递归函数的基本情况。

2.只有一个元素[x]

当在具有一个元素的列表上调用函数时,VM 将跳过第一个函数定义(因为它不为空),并继续执行第二个函数定义,该函数又在尾部递归调用该函数并反转布尔值。如果我们扩展调用堆栈,它将如下所示:

even_length?([1])          # `1` is head, `[]` is tail
# => !even_length?([])
# => !(true)               # We know value is `true` from base-case
# => false
Run Code Online (Sandbox Code Playgroud)

3. 有两个元素[x, y]

同样的事情,但我们将再次反转结果(因为该函数将被额外调用一次):

even_length?([2, 1])          # `2` is head, `[1]` is tail
# => !even_length?([1])       # `1` is head, `[]` is tail
# => !(!even_length?([]))
# => !(!(true))               # We know value is `true` from base-case
# => !(false)
# => true
Run Code Online (Sandbox Code Playgroud)

4. 三个要素[x, y, z]

even_length?([3, 2, 1])       # `3` is head, `[2, 1]` is tail
# => !even_length?([2, 1])    # `2` is head, `[1]` is tail
# => !(!even_length?([1]))    # `1` is head, `[]` is tail
# => !(!(!even_length?([])))
# => !(!(!(true)))            # We know value is `true` from base-case
# => !(!(false))
# => !(true)
# => false
Run Code Online (Sandbox Code Playgroud)

5. 有 N 个元素[ ... ]

并且这种情况还会继续重复。理解此函数功能的最简单方法是,它定义了包含 0 个元素的 List 应返回true,并且对于每个额外元素,它应反转(布尔值not)先前的值。

  • 很棒的解释。感谢您花时间写这篇文章。我还不能投票赞成这一点,但当我可以的时候,我有一天会这样做。再次感谢!真的很感激。我想我现在能理解了 (2认同)