Проверка на четную длину с сопоставлением с образцом - PullRequest
0 голосов
/ 27 октября 2018

Я видел этот фрагмент, и я не понимаю, как это делается с сопоставлением с образцом. Было бы замечательно, если бы кто-то мог объяснить это мне (или кому-то еще, кто мог бы не понимать это также)

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 голосов
/ 27 октября 2018

Это очень умный кусок кода, хотя его будет проще понять, если вы будете следить за его выполнением шаг за шагом.

Прежде чем мы рассмотрим несколько примеров, важно, чтобы вы понимали, что Elixir реализует Списки в виде связанных списков , и каждый список имеет 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, поскольку это базовый случай нашей рекурсивной функции.

2,С одним элементом [x]

При вызове функции из списка с одним элементом виртуальная машина пропустит первое определение функции (поскольку оно не пустое) и перейдет ко второму, которое в свою очередь вызываетрекурсивно функционирует только на хвостовой части и инвертирует логическое значение.Если мы расширим стек вызовов, это будет выглядеть так:

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 элементами должен возвращать true, а для каждого дополнительного элемента он должен инвертировать (логическое not) предыдущее значение.

0 голосов
/ 27 октября 2018

Когда вы звоните even_length?([1, 2]), оно соответствует: even_length?([_head | tail]) где _head равно 1 и tail равно [2] .

Затем, рекурсивно, он вызывает: !even_length?([2]), что соответствует even_length?([_head | tail]), где _head равно 2 , а tail равно [] .

Так как tail равен [] , то он вызывает: !even_length?([]), который соответствует первой функции even_length?([]), где возвращается true .

...