Monday, February 3, 2014

Введение в F#

Совсем недавно мне довелось познакомиться с таким уникальным языком разработки, как F#. Его гибкость и возможности поразили меня. Признаюсь, знакомство с F# началось у меня около года назад, но тогда этот язык просто не "зацепил" меня. Наконец я попробовал снова сосредоточить на нем внимание, изменив при этом свой подход к изучению. Основная проблема, которая иногда у меня проявляется при знакомстве с новым языком, кроется в попытке проецировать возможности известного языка разработки на изучаемый. Следует рассматривать язык как уникальную единицу, призванную решать свои задачи, и если пробовать нагружать на него специфику известного языка, станут заметны несоответствия и может сложиться мнение, что изучаемый язык "недоразвит". Проблема кроется зачастую не в языке, а в нас: мы зачастую пытаемся проецировать то, что есть в нашей памяти, на все новое, пытаясь найти аналогии, и это касается не только разработки. Такое поведение можно наблюдать, например, при изучении иностранных языков. 
Отойдем от рассуждений и попробуем беспристрастно взглянуть на этот язык. Мне понравилась книга "Chad Fowler, The Passionate Programmer", советы из которой стараюсь применять каждый день, чтобы повышать свой уровень. Один из таких советов звучит: "Чтобы понять, действительно ли Вы знаете что-либо, попробуйте обучить этому кого-то еще". Нет лучшего способа закрепить свои знания, чем заставить себя ясно сформулировать их кому-то еще. Обычное формулирование чего-либо является популярным средством для "очищения" разума. Общение с куклами или другими неодушевленными предметами как способ решения проблем является довольно известным элементом программистского фольклора (источник). Поэтому давайте попробуем учиться вместе. Надеюсь, что данный язык Вам понравится своими возможностями и мои старания не прошли даром. Для начала создадим новое приложение, как показано на рисунке ниже.
После этого увидим код: 
[<EntryPoint>]
let main argv =
    printfn "%A" argv
    0 // return an integer exit code
Это пример обычного консольного приложения, в котором [<EntryPoint>] – это точка входа в программу.
let main argv =
Указываем, что функция main является точкой в программу, argv – это аргументы этой функции. Как можно увидеть в Intellicence, функция возвращает int.
Функция printfn аналогична функциям из языка C и Python, только в C# она называется иначе. Например, ту же логику, какую делает эта функция, можно проделать на C# функцией string.Format или для консольного приложения передать необходимые параметры в функцию Console.WriteLine.
Попробуем написать простенькую функцию, которая будет суммировать два числа, и одну функцию, которая будет воспроизводить число в квадрате.
open System

let square x = x * x

let add x y =
    x + y

[<EntryPoint>]
let main argv =
    let z = 5
    printfn "Test square function %i" (square 5)
    printfn "An int: %i" z
    printf "Test add function %i" (add 5 7)
    Console.ReadLine() |> ignore
    0 // return an integer exit code
Для паузы в программе я использовал функцию Console.ReadLine(), но поскольку мне не важен результат, который возвращает данная функция, я указал для данной функции игнорировать результат возвращаемого значения.
Console.ReadLine() |> ignore
Открываем пространство имен System для F# с помощью кода
open System
Теперь поближе остановимся на самих функциях
let square x = x * x
Функция square принимает на вход один параметр. Посмотрите на рисунок ниже, чтобы понять, как работают функции в F#.
Соответственно, функция add принимает на вход два аргумента – x, – и возвращает сумму этих аргументов. Если мы переносим результат выполнения функции на новую строку, то у нас должен быть с левой стороны как минимум один пробел, так как F# не будет понимать, что Вы создали функцию.
Рассмотрим, как нам можно создать кастомный тип данных.
type Person = { Name: string; Age: int}

let mass = [|
                {Name = "Test"; Age = 32};
                {Name = "Test2"; Age = 25}
                |]
Выше мы создали тип данных Person, который имеет два члена Name и Age. А ниже  двумерный массив нашего типа Person. К сожалению, типы данных в C# являются неизменяемыми, поэтому мы не можем написать код на подобии такого для изменения некоего значения данного поля.
let person = {Name = "Test"; Age = 32}
person.Name <- "1234567890"
Но мы легко можем создать новый тип Person, в котором обновить нужное значение.
let person = {Name = "Test"; Age = 32}
let partDeux = { person with Name = "Expert F# 2.0" }
Давайте попрактикуемся в создании функций в отдельных модулях. Для этого выберем в Visual Studio создание нового файла, как показано на рисунке ниже.
Затем перенесем наши функции в этот файл.
module Calculation
    let square x = x * x

    let add x y =
        x + y
После этого нужно немного модифицировать код, чтобы можно использовать эти функции.
open System

[<EntryPoint>]
let main argv =
    let z = 5
    printfn "Test square function %i" (Calculation.square 5)
    printfn "An int: %i" z
    printf "Test add function %i" (Calculation.add 5 7)

  
    Console.ReadLine() |> ignore
    0 // return an integer exit code
Но как Вы увидите, Intellicence будет подчеркивать данный код как ошибку. Все дело в том, что порядок следования файлов в языке F# имеет значение. Нам достаточно выделить добавленный нами файл и нажать Move Up, как показано на рисунке ниже.
Вам необходимо переместить добавленный файл Calculation.fs, чтобы он оказался перед файлом Program.fs. После запуска мы можем запустить приложение и увидеть, что оно работает.
Что же делать, если нам нужно несколько модулей, как разделить их, ведь в одном файле они работать не будут. Для этого в F# существует разделение по пространствам имен namespace. Добавим еще один модуль в файл Calculation.fs и назовем его Multiply. Затем те два модуля, которые у нас получились, добавим в пространство имен CalculationOperation.Code. Пример приведен ниже.
namespace CalculationOperation.Code
    module Calculation =
        let square x = x * x

        let add x y =
            x + y
    module Multiply =
        let div x y = x / y

Теперь посмотрим, как использовать то, что мы написали. J
open System
open CalculationOperation.Code

[<EntryPoint>]
let main argv =
    let z = 5
    printfn "Test square function %i" (Calculation.square 5)
    printfn "An int: %i" z
    printf "Test add function %i" (Calculation.add 5 7)
    printf "Test div function %i" (Multiply.div 4 2)
  
    Console.ReadLine() |> ignore
    0 // return an integer exit code

Итоги
В приведенной статье мы рассмотрели простенькие примеры использования возможностей языка F#. Надеюсь, что примеры были несложные и это не отпугнет Вас от дальнейшего изучения данного языка. В следующей статье попробуем создать на F# приложение Windows Forms и WPF. Для первого раза, думаю, будет достаточно, чтобы не отбить у читателей охоту изучать F# в дальнейшем.

No comments:

Post a Comment