Интеграция C# и F#
- modified:
- reading: 3 minutes
Перед использованием F# задаешься вопросом, а можно ли использовать функции F# в приложениях, написанных на C#.
Ознакомиться с функциональным языком F# можно, к примеру, по этому адресу: http://msdn.microsoft.com/ru-ru/magazine/cc164244.aspx
Но вот, по моему мнению, F# как функциональный язык хорош для написания различных математических функций (извиняюсь за тавтологию), но зачем отбирать хлеб у объектно-ориентированных языков, зачем городить непонятный код для работы с WinForms контролами или WebForms страницами на F#? Потому я сразу же задался вопросом, как вызывать функции из F# сборок. Сразу хочу сказать, что так как в функциональных языках есть сложности с типизациями при написании кода, то в случае использования F# функций из сборок C# эти трудности только увеличиваются. Приступим к делу.
Создаем проект, который включает в себя, к примеру, C# консольное приложение и сборку F#.
В сборке F# нам нужен один файл MyFunctions.fs. Там мы описываем некоторые функции, которые по нашему мнению нам проще написать на функциональном языке. К примеру, пускай это будет функция перевода массива битовой картинки из цветового пространства RGB в YCbCr (это просто пример). Запись в F# может быть примерно такая:
open System
// Перевод в цветовое пространство YCbCr
let RGB_to_YCbCr (r : double,g : double,b : double) =
let y = 0.299 * r + 0.587 * g + 0.114 * b in
let Cb = (-0.1687) * r - 0.3313 * g + 0.5 * b + 128.0 in
let Cr = 0.5 * r - 0.4187 * g - 0.0813 * b + 128.0 in
(y,Cb,Cr);
let RGB_to_YCbCr_v (v : _ array) =
RGB_to_YCbCr (v.[0], v.[1], v.[2]);
let Process (image : _ array) =
let lenght = Array.length image in
let imageYCbCr = Array.create lenght (0.0, 0.0, 0.0) in
for index = 0 to lenght - 1 do
imageYCbCr.[index] <- RGB_to_YCbCr_v (image.[index])
done
imageYCbCr
После сборки мы можем заметить, что добраться до функций не просто, namespace имеют непонятный вид, и как их использовать тоже не представляется ясным. Посмотреть расположение функций в сборке мы можем при помощи Reflector.
Для того, чтобы описать namespace и класс необходимо добавить следующую строку сразу после #light:
module FSharp.Sample.MyFunctions
Которая говорит, о том что все функции написанные ниже будут содержаться в классе MyFunctions пространства имен FSharp.Sample.
Собрав проект еще раз, мы увидим, что в сборке есть четкий namespace FSharp.Sample, который имеет класс MyFunctions со статическими методами, которые мы описали выше.
Дальше в нашем консольном приложении мы устанавливаем Reference на сборки FSharp.Sample - имя моей сборки на F#, и FSharp.Core - для того, чтобы использовать типы (классы) F# типа Triple. И пишем следующий код:
using System;
using FSharp.Sample;
namespace CSharp.Sample.Console
{
class Program
{
static void Main()
{
double[][] image = new double[1000][];
Random rand = new Random();
for (int i = 0; i < 1000; i ++ )
{
image[i] = new double[3];
image[i][0] = rand.Next();
image[i][1] = rand.Next();
image[i][2] = rand.Next();
}
foreach (var doubles in MyFunctions.Process(image))
{
System.Console.WriteLine(doubles);
}
}
}
}
Где изначально мы указываем на использование namespace FSharp.Sample. В коде мы генерируем массив данных и передаем его в функцию MyFunction.Process, которая преобразовывает нам его по выбранному алгоритму. Данные нам возвращаются в виде массива данных типов "Microsoft.FSharp.Core.Tuple`3".