2015-03-17 3 views
0

Вот моя попытка 3-й задачи (P03) из 99 проблем в Scala (http://aperiodic.net/phil/scala/s-99/):Scala Pattern Matching Энигма

import scala.annotation._ 

// Find the nth element of a list. 
// nth(2, List(1, 1, 2, 3, 5, 8)) = 2 

object P03 { 
    @tailrec def nth[A](n: Int, ls: List[A]): A = (n, ls) match { 
    case (0, h :: t :: Nil) => h 
    case (n, _ :: t)  => nth(n - 1, t) 
    case _     => println(n); throw new IllegalArgumentException 
} 

Загадка в том, что этот код печатает -4 и бросает IllegalArgumentException

решение, конечно, изменить первый рисунок на:

case (0, h :: _) => h 

Это печатает правильный ответ 2

Вопрос: почему? Что такое тонкое различие между:

case (0, h :: t :: Nil) => h 

&

case (0, h :: _) => h 

Спасибо!

+1

Разница в том, что 'h :: t :: Nil' соответствует только списку с двумя элементами (' h' и 't',' Nil' является маркером для конца списка), а 'h :: _' соответствует каждому непустому списку, то есть списку, который имеет хотя бы один элемент. –

+0

Можете ли вы добавить это как ответ вместо комментария. Я хотел бы отметить это как ответ и закрыть его :). Благодарю. – iyerland

ответ

4

Разница заключается в том, что только h :: t :: Nil матчах список с двумя элементами (h и t, Nil является маркером конца списка (я не 100% уверен, что это точная номенклатура)) в то время как h :: _ матчей каждый не пустой список, то есть список, который содержит, по меньшей мере, один элемент, если вы проверяете :: класс вы увидите:

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B] 

который имеет голову и хвост, где первый является первым элементом списка а второй - это остальное, совпадение по h :: t :: Nil означает получение первого элемента списка, чем первый из хвоста и th en должно быть Nil, совпадение на h :: _ означает получение головы, а затем вам все равно, что осталось, пока есть голова.