Прочитав первые несколько статей из цикла Влюбляемся в F#, я и в самом деле, если не влюбился в него, то по меньшей мере заинтересовался. Настолько, что не вытерпел ожидания следующей дозы и решил продолжить изучение самостоятельно.
В процессе луркинга я наткнулся на чрезвычайно увлекательный сайт Project Euler, который на мой взгляд, как нельзя лучше подходит, чтобы постепенно изучить все, или по крайней мере большинство тонкостей F#. Сейчас я предлагаю для начала рассмотреть решение самой первой задачи с этого сайта. Она очень простая, и ее решение думаю не вызовет сложностей даже у тех, кто знаком с F# только по вышеприведенной статье. Итак…
Условие звучит следующим образом:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Решение этой задачи выглядит крайне лаконично:
Думаю, что в целом здесь нет ничего сложного, однако следует обратить внимание на несколько вещей, которые еще не упоминались в цикле статей о F#.
Во-первых, это оператор "|>", который формально определяется следующим образом:
а говоря попросту, передает посчитанное перед ним значение в качестве аргумента следующей функции. Этот простой оператор позволяет в многих случаях существенно сократить код.
Во-вторых, здесь применяется лямбда-функция для определения чисел, делящихся на 3 или на 5, уже знакомая даже большинству программистов-императивщиков благодаря LINQ. Синтаксис ее отличается от LINQ разве что наличием fun перед определением функции, и использованием -> вместо =>.
В-третьих, здесь используются две встроенные функции для работы со списками: List.filter и List.fold_left. Первая из них фильтрует список в соответствии с заданной булевой функцией, в качестве которой мы и используем нашу лямбду. Вторая в нашем случае суммирует все элементы списка. Ноль, стоящий вторым аргументом в списке, задает начальное значение аккумулятора. Таким образом, для перемножения всех элементов списка код будет выглядеть так: List.fold_left (*) 1.
Естественно, обе эти функции можно написать и самому, например для фильтрации она может выглядеть как-то так:
но думаю, уже все давно пришли к убеждению, что изобретать велосипед стоит далеко не всегда.
Таким образом, вся программа состоит по сути из двух последовательных шагов, которые незамедлительно приносят искомый результат. Довольно красиво, не правда ли?
UPD: Друзья, если вы минусуете топик или карму, прошу, напишите парус строчек, за что. К критике отношусь спокойно, а в следующий раз постараюсь сделать лучше. Спасибо.
В процессе луркинга я наткнулся на чрезвычайно увлекательный сайт Project Euler, который на мой взгляд, как нельзя лучше подходит, чтобы постепенно изучить все, или по крайней мере большинство тонкостей F#. Сейчас я предлагаю для начала рассмотреть решение самой первой задачи с этого сайта. Она очень простая, и ее решение думаю не вызовет сложностей даже у тех, кто знаком с F# только по вышеприведенной статье. Итак…
Условие звучит следующим образом:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Решение этой задачи выглядит крайне лаконично:
#light
let _ =
[1..999]
|> List.filter (fun x -> x%3=0 or x%5=0)
|> List.fold_left (+) 0
|> printfn("The answer is %d")
Думаю, что в целом здесь нет ничего сложного, однако следует обратить внимание на несколько вещей, которые еще не упоминались в цикле статей о F#.
Во-первых, это оператор "|>", который формально определяется следующим образом:
let (|>) a f = f a
а говоря попросту, передает посчитанное перед ним значение в качестве аргумента следующей функции. Этот простой оператор позволяет в многих случаях существенно сократить код.
Во-вторых, здесь применяется лямбда-функция для определения чисел, делящихся на 3 или на 5, уже знакомая даже большинству программистов-императивщиков благодаря LINQ. Синтаксис ее отличается от LINQ разве что наличием fun перед определением функции, и использованием -> вместо =>.
В-третьих, здесь используются две встроенные функции для работы со списками: List.filter и List.fold_left. Первая из них фильтрует список в соответствии с заданной булевой функцией, в качестве которой мы и используем нашу лямбду. Вторая в нашем случае суммирует все элементы списка. Ноль, стоящий вторым аргументом в списке, задает начальное значение аккумулятора. Таким образом, для перемножения всех элементов списка код будет выглядеть так: List.fold_left (*) 1.
Естественно, обе эти функции можно написать и самому, например для фильтрации она может выглядеть как-то так:
let rec filter filter_fun lst =
match lst with
|[] -> []
|head::tail -> if filter_fun head then head::(filter filter_fun tail)
else filter filter_fun tail
но думаю, уже все давно пришли к убеждению, что изобретать велосипед стоит далеко не всегда.
Таким образом, вся программа состоит по сути из двух последовательных шагов, которые незамедлительно приносят искомый результат. Довольно красиво, не правда ли?
UPD: Друзья, если вы минусуете топик или карму, прошу, напишите парус строчек, за что. К критике отношусь спокойно, а в следующий раз постараюсь сделать лучше. Спасибо.