通过模式匹配检查偶数长度

时间:2018-10-26 23:54:20

标签: pattern-matching elixir

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

def even_length?([]) do
  true
end

def even_length?([_head | tail]) do
  !even_length?(tail)
end

在输入[1, 2][3, 4, 5]之类的输入时,我简直迷失了

谢谢。

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

2 个答案:

答案 0 :(得分:2)

这是一段非常聪明的代码,尽管如果逐步执行它可能会更容易理解。

在我们看一些示例之前,务必了解Elixir实现了Lists as Linked Lists,并且每个列表都有一个head和一个tail,其中尾部本身是一个单独的列表项。 每个列表(空列表除外)都可以写为[ head | tail ]

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

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

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

1。空列表[]

调用even_length?([])会匹配第一个签名,并直接返回true,因为这是我们递归函数的base case

2。只有一个元素[x]

在具有一个元素的列表上调用该函数时,VM会跳过第一个函数定义(因为它不为空),然后移至第二个,依次反过来仅在尾部调用该函数并反转布尔值。如果我们扩展调用堆栈,它将如下所示:

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

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

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

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

这将继续重复。理解此函数的功能的最简单方法是,定义具有0个元素的List应该返回true,并且对于每个额外的元素,它应该将先前的值求反(布尔值not)。

答案 1 :(得分:0)

当您致电even_length?([1, 2])时,它会匹配:even_length?([_head | tail]) 其中_head 1 ,而tail [2]

然后,它递归调用:!even_length?([2])even_length?([_head | tail])匹配,其中_head 2 ,而tail [] < / strong>。

由于tail [] ,因此它将调用:!even_length?([]),它与第一个函数even_length?([])相匹配,并返回 true