Learn You Scala for Great Good! Часть 3

Learn You Scala for Great Good! Часть 3

Сегодня я продолжу разговор, начатый здесь (пример про Гарды и калькулятор лишнего веса), и продолженный здесь (вычисление максимального числа из списка) и здесь (пример про максимум для произвольного списка). Все это касалось изучения функционального программирования по книге Learn You a Haskell for Great Good!

Функция replicate

Следующая функция из главы, посвященной рекурсии, называется replicate. Она получает в качестве первого аргумента число повторений, а в качестве второго — элемент, который нужно повторить нужное число раз. И возвращает список, состоящий из повтореного нужное число раз элемента.

Итак, Haskell:


    replicate :: (Num i, Ord i) => i -> a -> [a]  
    replicate n x  
        | n <= 0    = []  
        | otherwise = x:replicate (n-1) x

Как и в предыдущем примере, мы видим typeclass Ord, которого нет в Scala (но не в сторонних библиотеках).

Сперва напишем пример для целых чисел:


    def replicate(i:Int, x: Int):List[Int] = {
      i match {
        case n if n <= 0 => Nil
        case n => x::replicate(n-1, x)
      }
    }
    println(replicate(7, 9))

Но мы можем легко привести эту функцию к общему виду, заменив Int на Any:


    def replicate(i:, x: Any):List[Any] = {
      i match {
        case n if n <= 0 => Nil
        case n => x::replicate(n-1, x)
      }
    }

    println(replicate(12, 'a'))

Хотя правильнее будет записать это так:


    def replicate[A](i:, x: A):List[A] = {
      i match {
        case n if n <= 0 => Nil
        case n => x::replicate(n-1, x)
      }
    }

    println(replicate(12, 'a'))

Теперь функция будет работать с определенным типом, а не с Any.

 Функция take

Эта функция принимает число n и список l и возвращает другой список, содержащий первые n элементов списка  l.
Haskell:


    take :: (Num i, Ord i) => i -> [a] -> [a]  
    take n _  
        | n <= 0   = []  
    take _ []     = []  
    take n (x:xs) = x : take (n-1) xs  

В Scala это выглядит так:


    def take[A](n:Int, l:List[A]): List[A] = {
      (n, l) match {
        case (n, _) if n <= 0 => Nil
        case (_, Nil) => Nil
        case (n, x::xs) => x::take(n-1, xs)
      }
    }

    println(take(3, List(5, 34, 99, 8, 567, 222)))
    println(take(5, List("5", "34", "99", "8", "567", "222")))

Используется сравнение с образом (pattern matching):

  • Если n равно или меньше нуля, мы получаем пустой лист.
  • Если второй аргумент — пустой лист, то возвращается пустой лист.
  • Если же второй аргумент список x::xs, то функция вызывается снова x::take(n-1, xs)

 

Функция reverse

Данная функция просто «переворачивает» список:

Haskell:


    reverse :: [a] -> [a]  
    reverse [] = []  
    reverse (x:xs) = reverse xs ++ [x]

Scala:


    def reverse[A](l: List[A]):List[A] = {
      l match {
        case Nil => Nil
        case x::xs => (reverse(xs) ::: x::Nil)
      }

    }

    println(reverse(1::2::3::4::4::5::6::7::Nil))

Все очень просто: функция берет первый элемент списка и бросает его в конец, затем вызывается рекурсивно к оставшейся части.

 

Learn You Scala for Great Good! Часть 3 обновлено: Ноябрь 18, 2016 автором: Alquimisto

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *