Введение в F#: интервью с Доном Саймом

Введение


В одной из наших новостей мы рассказывали о новом языке для платформы .NET Framework - F#. Этот язык появился совсем недавно, его автором стал Дон Сайм (Don Syme). Пока что о статусе языка ничего не было известно: будет ли он коммерческим или свободно распространяемым, будет ли для него собственная среда разработки или с кодом на F# можно работать прямо в Visual Studio .NET, каков вообще синтаксис F# и для чего понадобилось изобретать новый язык. Но ответы на все эти вопросы есть у его создателя - Дона Сайма, который любезно согласился поделитьcя с нами своими знаниями.



На наши вопросы отвечает Дон Сайм, создатель языка F#

Дон Сайм начал работать в Microsoft Research с 1998 года. К тому времени он уже защитил докторскую диссертацию по вычислительной технике (Computer Science) в Кембриджском Университете (University of Cambridge) и окончил Австралийский Национальный Университет (Australian National University). В свое время Дон был одним из ведущих исследователей и проектировщиков технологии .NET. Сейчас он тратит много времени на разработку поддержки обобщенного программирования в С# (эта новая мощная возможность появится в C# в следующем году). У Дона довольно много публикаций о проектировании языков программирования и вообще по "компьютерной лингвистике".

Интервью


TanaT: Расскажите, пожалуйста, как создавался язык F#?

Дон Сайм: Я работал над F# в течение последних 18 месяцев прямо здесь, в Microsoft Research в Кембридже. Хотя функциональные языки известны уже давно, аж с 1970-ых, программистам всегда не хватало таких прагматических возможностей, как библиотеки и поддержка времени выполнения. Одним из лучших функциональных языков является Caml, разработанный INRIA во Франции в 1990-ых годах. Но у Caml другая проблема - он до сих пор борется за совместимость с популярными библиотеками, доступными сегодня для таких платформ как Java и .NET.
Структура F# во многом схожа со структурой Caml с той лишь разницей, что первая реализована поверх библиотек и среды исполнения .NET. Такой подход в корне решает проблему совместимости библиотек и проблему взаимодействия языков между собой: не забывайте, что .NET разрабатывалась еще и для того, чтобы разные языки могли легко взаимодействовать друг с другом, вот и сейчас код на F# может быть легко использован в С# и наоборот.

От автора: Функциональным языком называется язык, программа на котором представляет собой совокупность функций. Функции могут определяться через другие функции или рекурсивно. Не путайте императивные языки (С, Fortran, Algol) с функциональными языками. В императивных языках программа представляет собой набор команд (среди которых могут встречаться вызовы функций).


TanaT: F# можно называть Caml.NET?

Дон Сайм: Думаю, что использовать термин (и название) Caml.NET не следует. Хотя эти языки сильно перекрывают друг друга, многие языковые конструкции из Caml просто не реализованы в F#.

От автора: Caml был создан в январе 1996 года. К общим особенностями языка можно отнести легкость в его изучении и использовании. В то же самое время, спектр возможностей языка довольно широк. С 1984 года разработкой и распространением языка занимался INRIA (основной Исследовательский Институт Франции по Вычислительной Технике). Язык свободно распространяется для UNIX, PC и Macintosh. У Caml есть две "пикантных" стороны: Caml Light и Objective Caml. Caml Light - это подмножество Objective Caml, созданное специально для того, чтобы преподавать программирование и обучаться ему. В дополнение к основному языку Caml Light, возможности Objective Caml включают мощную систему модулей, полную поддержку объектно-ориентированной парадигмы и оптимизирующий компилятор. Более подробно смотрите здесь: линк


TanaT: Каковы цели создания F#? Какие задачи решает этот язык?

Дон Сайм: F# - это язык программирования общего назначения. С его помощью можно решать задачи любого типа. Код на языке F# является безопасным в отношении типов (подробнее о безопасности типов смотрите во врезке ниже, прим. автора), как и код на других .NET-языках (к примеру, С#). Единственное, код на F# часто бывает более компактным, чем аналогичный код на других .NET-языках, за счет приведения типов. Вы это увидите на нескольких примерах далее. Более того, такие возможности, как обобщенное программирование и процедуры-функции позволяют вам писать абстрактные обобщенные алгоритмы, которые управляют параметризованными структурами данных (например, массивами, списками, графами, деревьями), но не просто управляют, а управляют безопасным в отношении типов образом. (Подробнее об абстрактных обобщенных алгоритмах и параметризованных структурах данных смотрите во врезке ниже, прим. автора).
Мне хочется думать, что F# реализован по принципу "чем меньше, тем лучше": F# дает программисту в распоряжение несколько возможностей, которые отлично взаимодействуют друг с другом. Программисту вовсе не обязательно знать абсолютно все о классах, интерфейсах, структурах, наследовании и т.п. Ему просто следует освоить несколько простых конструкций. Хотя знания объектно-ориентированных концепций сильно пригодятся при использовании библиотек .NET Framework.
Одна из основных идей F# заключается в том, чтобы удостовериться, что ваш код и ваши типы в функциональном языке программирования могут быть легко доступны из других .NET-языков. F# - единственный функциональный язык программирования для .NET, в котором абсолютно все, что вы пишите, будет сразу доступно для использования в других языках.

От автора: Даже если вы, наш уважаемый читатель, являетесь программистом с многолетним опытом работы, это вовсе не означает, что вы по-прежнему помните массу сугубо теоретических компьютерных терминов. Поэтому я на всякий случай объясню, о чем только что шла речь.
Под обобщенным программированием понимается использование шаблонов и контейнеров. Шаблоны позволяют создавать параметризованные типы данных, где параметром является тип используемых в дальнейшем данных. Контейнером называется структура данных, содержащая набор элементов некоторого типа. Например, если эта структура является классом, то контейнер иногда называют класс-контейнером. Примером, контейнера может служить стек, содержащий элементы произвольного типа. Понятия контейнера и шаблона сильно связаны, так как фактически контейнеры создаются с помощью такого средства языка, как шаблоны.
Абстрактным типом данных называется тип, созданный самим пользователем. Когда Дон говорил об "абстрактных обобщенных алгоритмах", то имел в виду алгоритмы, способные управлять данными разных типов, которые в свою очередь определенны программистом. Под "параметризованными структурами данных" понимаются все те же контейнеры.
Безопасность типов проявляется в том, что CLR (Common Language Runtime - Общеязыковая Исполняющая Среда в .NET Framework) во время выполнения кода на CIL (Common Intermediate Language - Общий Промежуточный Язык) будет проверять безопасность использования типов в коде, что гарантирует корректное обращение к существующим типам. Если входной параметр метода объявлен как 4-байтное значение, CLR обнаружит и предотвратит применение 8-байтного значения для этого параметра. Безопасность типов также означает, что управление может передаваться только в определенные точки (точки входа методов). Невозможно указать произвольный адрес и заставить программу исполняться, начиная с этого адреса. Совокупность всех этих защитных мер избавляет от многих распространенных ошибок.


TanaT: Расскажите о синтаксисе F#.

Дон Сайм: Синтаксис F# построен на математической нотации, а программирование чем-то похоже на алгебру. Например, когда вы определяете новый тип, то можете указать, что переменными этого типа будут "целые или строки". Вот как это выглядит "в жизни":

type myType = IntVal of int | StringVal of string

Код представляет собой математическую нотацию тоже. По сравнению с С# вы сразу заметите уменьшение числа ключевых слов, модификаторов и типов.

let f x = x + 1

F# работает следующим образом: тип "f" представляет собой "int -> int", то есть функция получает на вход целое и выдает на выход целое.

Тем не менее, код - это по-прежнему код. Вы можете выводить что-то на принтер, программировать работу с сетью и т.п.

let print x =
match x with
| IntVal i -> System.Console.WriteLine(“Integer: {0}”, box i)
| StringVal s -> System.Console.WriteLine(“String: {0}”, s)

Здесь "match" - это конструкция, представляющая более мощный эквивалент по сравнению со "switch" из С#. В ней вы можете сочетать данные друг с другом самым непостижимым образом.


TanaT: Вы говорили, что F# пригоден для любых задач. Тем не менее, возникает ощущение, что, например, для создания кода ASP.NET он подходит не очень. Я прав?

Дон Сайм: Понимаете, F# может делать то же, что и другие .NET-языки. К тому же многие современные задачи, в конечном счете, сводятся к математической нотации. А ее символьное представление и есть хлеб с солью языка F#.


TanaT: Что бы вы еще отнесли к возможностям F#? Как он смотрится рядом с собратьями из .NET-семейства?

Дон Сайм: F# - это исследовательский прототип, не являющийся официальным языком от Microsoft. У нас нет планов делать его коммерческим. Если подвести итог, то это - стабильная реализация языка, созданного специально для исследовательских проектов в Microsoft Research (в основном для Abstract IL SDK). Я вижу предназначение F# в том, чтобы показать всему миру, что и функциональный язык может быть реализован, и довольно неплохо, для работы под .NET Framework. При этом он будет достаточно прост в реализации и вполне пригоден для изучения в университетах. Некоторые задачи намного более ясны при решении их с помощью F# (а не C#), особенно те, что используют математический стиль программирования. Например, написание компилятора требует работы со структурами данных и преобразованиями над ними.


TanaT: Но при этом F# позволяет программисту получить доступ ко всем возможностям BCL?

Дон Сайм: F# позволяет получить доступ абсолютно ко всему, что есть в BCL (подробнее о BCL смотрите во врезке ниже, прим. автора) . Синтаксис для работы с библиотеками .NET в этом смысле максимально близок к синтаксису С#. Тем не менее, проблемы могут возникнуть при написании кода, использующего весь спектр возможностей F#. К примеру, следующий код отображает функцию (функции похожи на делегатов) с помощью списка:

let rec map f l =
match l with
| [] -> []
| h::t -> f h :: map f t

let myList = [1;3;5]
let newList = map (fun x -> x + 1) myList

// В newList теперь находится [2;4;6]

Подсказка: "(fun x -> x + 1)" определяет функцию, также известную как свертка. Это как "анонимный делегат" в C# (подробнее о делегатах, смотрите во врезке ниже, прим. автора).

Программисты сразу заметят, что переменные, которые уже определены, не могут меняться. Например, вы не можете написать так:

let x = 1
x := 3

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

От автора: Снова рассмотрим несколько терминов из мира .NET. Прежде всего, BCL (Basic Class Library - Базовая Библиотека Классов) - это стандартная для .NET Framework библиотека, содержащая несколько тысяч запрограммированных классов. Каждый из них уже готов к использованию. BCL является отличным подспорьем для написания любых программ под .NET Framework. Так как F# имеет доступ к BCL, его пользователям не придется изобретать велосипед заново.


Теперь поговорим о делегатах. Microsoft .NET Framework поддерживает механизм функций обратного вызова (в нашем примере функция вызывается несколько раз) при помощи делегатов. В отличие от механизмов обратного вызова из других платформ, таких как неуправляемый С++, функциональность делегатов намного богаче. Например, делегаты обеспечивают безопасность типов при исполнении метода обратного вызова (способствуя решению одной из важнейших задач CLR). Делегаты также поддерживают последовательный вызов нескольких методов и позволяют вызывать как статические, так и экземплярные методы.
В неуправляемом С/С++ адрес функции - это всего лишь адрес в памяти, не несущий дополнительной информации. Он не позволяет узнать ни сколько параметров ожидает функция, ни их тип или тип значения, возвращаемого функцией, ни правила вызова функции. Короче, в неуправляемом С/С++ функции обратного вызова не обеспечивают безопасность типов.
В .NET Framework используется механизм делегатов. Делегат задает методы обратного вызова. В некотором смысле, делегат очень напоминает typedef из неуправляемого С/С++, представляющий адрес функции.
Для того, чтобы на практике использовать делегаты в C#, необходимо определить делегат ключевым словом delegate, создать его экземпляр с помощью оператора new и вызвать метод обратного вызова, пользуясь известным вам синтаксисом "метода вызова", в котором вместо имени метода стоит переменная, ссылающаяся на объект делегата.


TanaT: Если сравнить F# с полностью объектно-ориентированными языками (как Java, SmallTalk и C#), полностью процедурными языками (как Algol, Fortran и C) или чем-то средним (как C++), к чему он ближе?

Дон Сайм: Как я уже говорил выше, F# не вобрал в себя многих аспектов объектно-ориентированного программирования. Многие преподаватели соглашаются друг с другом в том, что механизмы абстракции в функциональных языках программирования не менее мощны, но зато гораздо более просты в изучении, чем аналогичные им в объектно-ориентированных языках.


TanaT: Получается, ближе всего к С++?

Дон Сайм: Да, к С++. Хотя ML-языки (речь по-прежнему идет о промежуточных языках, прим. автора) лежат где-то посреди предложенных вами границ. F#, например, не реализует некоторые сложные аспекты объектно-ориентированных языков. Но в отличие от С++, F# добился своей цели не путем добавления новых возможностей в C. F# основывается на простом теоретическом функциональном фундаменте. Именно на этом фундаменте стоят механизмы абстракции данных.


TanaT: Расскажите, как обстоят дела у F# с оптимизацией?

Дон Сайм: В F# доступен целый ряд оптимизирующих возможностей, включая перекрестную модульную оптимизацию. Производительность ваших программ зависит в основном от стиля, который вы используете. Некоторые стили функционального программирования поддерживаются лучше других.


TanaT: А где можно скачать компилятор F#?

Дон Сайм: Компилятор F# свободно доступен по адресу: линк. Информация об его релизе лежит здесь.


TanaT: Можете рассказать о структуре компилятора F#?


Архитектура компилятора


Дон Сайм: Да, но только вкратце. Все начинается с синтаксического анализатора, он выделяет операторы, функции, переменные и т.п. На следующем этапе происходит проверка типов переменных, проверяются результаты операции присваивания, а также типы параметров в функциях. Следующим в нашей структуре идет оптимизатор, он старается подправить программу так, чтобы на выходе получился более быстрый код. Следующая часть компилятора производит ILX-код (нечто среднее между обобщенным IL-кодом и кодом еще не откомпилированной программы). Далее ILX-код конвертируется в обобщенный IL-код для CLR v1.1 или, с помощью промежуточного шага, в IL-код для CLR v1.0. Красота CLR в том, что сделать собственный компилятор, производящий IL-код, не так сложно. Компилятор получится небольшим и компактным.


Краткое сравнение языковых средств F# и OCaml
 Возможность* F# OCaml
 Primitive types + +
 Unicode strings and wide chars + - 
 Floating point + +
 Functions as values + +
 Structured function types + +
 Discriminated unions + +
 Generics / Parametric Polymorphism / Type parameters + +
 "Interior" bindings + +
 Records + +
 Pattern matching + +
 Type aliases + +
 Structures + +
 Signatures + +
 Substructures / Namespaces / Packages - +
 Functors - +
 Inheritance (authoring) - +
 Structured classes - +
 Variance on type parameters - +
 Labels - +
 Default parameters - +
 "Printf" style formatting - +
 Overloading - -

* Языковые возможности специально не переведены на русский, так как в английском написании они легче в понимании.


TanaT: Как вы видите будущее F#?

Дон Сайм: F# вызвал большой интерес. Мы не собираемся делать язык коммерческим, мы бы хотели, чтобы его использовали в академических целях. Также он должен заинтересовать людей, которые хотели бы расширить границы программирования для .NET.


TanaT: А какие инструменты доступны сегодня для разработки приложений на F#?

Дон Сайм: Отладчик из Visual Studio отлично подходит и для кода на F#, да и вообще, большинство .NET-инструментов работают с F# без жалоб. Например, Lex и Yacc (синтаксические анализаторы), написанные Малькольмом Кроувом (Malcolm Crowe) работают с F#, так же, как и прекомпилятор NGEN и несколько коммерческих средств профилировки .NET-кода.


TanaT: Что вы собираетесь выпустить в помощь программистам на F#?

Дон Сайм: Я бы очень хотел сделать plug-in в Visual Studio для F#. Но у меня совсем нет времени этим заняться.


TanaT: Можете привести пример программы "hello world" на F#?

Дон Сайм: Вот один вариант с использованием библиотеки F#:

let _ = print_endline(“Hello World”)

А вот другой вариант с использованием BCL:

open System
let _ = Console.WriteLine(“Hello World”)

В обоих случаях "let _ = " означает лишь: "игнорировать результаты того, что мы делаем в правой части символа "=" (равно)". Библиотека F# - это лишь простейшая оболочка для BCL, позволяющая пользоваться базовыми возможностями BCL, не зная ее самой. (Некоторые программисты на F# знакомы больше с Caml, чем с .NET). Две библиотеки можно применять в одном приложении: в конечном счете, они используют одни типы.


TanaT: А для С# вы что-нибудь разрабатываете?

Дон Сайм: Наша команда провела 4 года, проектируя поддержку C# Generics для Common Language Runtime. Более подробная информация доступна в объявлении Андерса Хейлcберга (Anders Hejlsberg) о C# Generics: линк.
С# еще не поддерживает такого средства языка, как шаблоны. Их не поддерживает и CLR. Ребята из Microsoft Research в Кембридже уже давно трудятся над разработкой этой новой возможности (судите сами, четыре года назад еще не было никакой .NET). Надеемся, что им удастся завершить свой проект к намеченному сроку (в следующем году). Тогда функциональность и возможности управляемых языков возрастут еще больше.

TanaT: Спасибо, что уделили нам время. Удачи вам и успеха вашим проектам!

Коллекция ссылок


Если язык F# вас заинтересовал, вам, безусловно, захочется узнать о нем больше. Далее приведен целый ряд ссылок, позволяющих найти исчерпывающую информацию об этом языке. Должен признаться, Microsoft недавно поменяла дизайн всего раздела Microsoft Research, посвященного F#. Теперь вас ждут красивые зеленые странички :).

Руководство по основам программирования на F#: линк.

Руководство по использованию уже готовых управляемых .NET-библиотек в F#: линк.

Руководство по использованию библиотек на F# в языке C#: линк.

Руководство по основной библиотеке F#: линк.

Руководство по использованию некоторых .NET-конструкций, доступных лишь в последнем релизе компилятора F#: линк.

Руководство по написанию высоко производительного кода на F#: линк.