我看到了这个代码片段,但我不明白模式匹配是如何完成的。有人可以向我解释(或其他可能也不太理解)的人,那就太好了
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
答案 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
[]
调用even_length?([])
会匹配第一个签名,并直接返回true
,因为这是我们递归函数的base case。
[x]
在具有一个元素的列表上调用该函数时,VM会跳过第一个函数定义(因为它不为空),然后移至第二个,依次反过来仅在尾部调用该函数并反转布尔值。如果我们扩展调用堆栈,它将如下所示:
even_length?([1]) # `1` is head, `[]` is tail
# => !even_length?([])
# => !(true) # We know value is `true` from base-case
# => false
[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
[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
[ ... ]
这将继续重复。理解此函数的功能的最简单方法是,定义具有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 。