Шпаргалка по F#
Начал изучать F# и решил набросать шпаргалку. Буду дополнять по мере изучения.
Базовый синтаксис
Отступы значимы. Причем отступы должны быть пробельными — табуляция не подойдет.
Определить переменную:
let sampleInteger = 176
Определить функцию:
let func1 x = x*x + 3
Функции могут быть вложенными.
Функция всегда возвращает результат последнего вычисления.
let add3ints x y z = let add2ints x y = x + y add2ints x (add2ints y z) System.Console.WriteLine(add3ints 1 2 3) System.Console.ReadLine()
Операции со списками
Создание списка:
let mylist = [1; 2; 3; 4; 5]
Получение нового списка путем преобразования старого:
let multipliedList = List.map (fun x -> x * 3) mylist
Фильтрация списка:
let biglist = List.filter (fun x -> x > 7) multipliedList
Оператор |> позволяет использовать функции в Linq стиле. Он передает выражение слева последним аргументом в выражение справа. На примере будет понятнее:
let biglist2 = [1; 2; 3; 4; 5] |> List.map (fun x -> x * 3) |> List.filter (fun x -> x > 7)
Конкатенация списков:
let newlist = [1] @ [4..5]
Сворачивание списков:
let newlist = [1 .. 3] let sumofsquares = newlist |> List.reduce (fun acc x -> acc + x * x)
Списки являются однонаправленными, т.е. получение первого элемента намного быстрее, чем получение последнего. Если вам нужен последний элемент списка — скорее всего нужно пересмотреть алгоритм.
Рекурсия
Для того, чтобы функция была рекурсивной, нужно в объявление функции добавить ключевое слово rec
let rec fib n = if (n < 3) then 1 else fib(n-1) + fib(n-2)
F# оптимизирует хвостовую рекурсию. Нужно стараться делать рекурсию хвостовой.
Оптимизация хвостовой рекурсии по умолчанию отключена при сборке в Debug.
Параллельные вычисления
open System.Net open Microsoft.FSharp.Control.WebExtensions let urlList = [ "Microsoft.com", "http://www.microsoft.com/" "MSDN", "http://msdn.microsoft.com/" "Bing", "http://www.bing.com" ] let fetchAsync(name, url:string) = async { try printfn "Start reading %s" name let uri = newSystem.Uri(url) let webClient = newWebClient() webClient.Proxy<- newWebProxy("localhost", 3128) let! html = webClient.AsyncDownloadString(uri) printfn "Read %d characters for %s"html.Length name with | ex ->printfn"%s" (ex.Message); } let runAll() = urlList |>Seq.mapfetchAsync |>Async.Parallel |>Async.RunSynchronously |>ignore runAll() printfn "Hello from main thread"
let! – отличается от обычного let тем, что не останавливает текущий поток во время выполнения.
async{} – асинхронное выражение.
Async.Parallel – объединяет последовательность асинхронных выражений для параллельного выполнения.
Async.RunSynchronously – запускает параллельное выполнение и ожидает завершения.
В результате загрузка каждого урла происходит в отдельном потоке.
Вывод в консоль:
Start rSStart reading tart reading MSDN eading Microsoft.com Bing Read 40370 characters for Bing Read 1020 characters for Microsoft.com Read 25059 characters for MSDN Hello from main thread
Использование кода на C# из F#
Код на C#:
namespace MyClasses { public class Class1 { public int Id { get; set; } public string Name { get; set; } public virtual string Title { get { return "Class1 " + this.Name; } } } public class Class2 : Class1 { public override string Title { get { return "Class2 " + this.Name; } } } }
Использование на F#:
open MyClasses let q1 = new Class1() q1.Name <- "qwerty" let q2 = new Class2() q2.Name <- "qwerty" System.Console.WriteLine(q1.Title) System.Console.WriteLine(q2.Title) System.Console.ReadLine()
Строгая типизация
В F# нет неявного преобразования между типами.
Конвертация типов:
let int10 = int 10.0 let float10 = float 10
Тип функции и тип аргумента:
let f1 (x:int) :float = float x
Приведение типов:
:> — приведение к предку
:?> — приведение к потомку
Использование кода на F# из C#
Создаем F# Library, в созданном файле пишем такой код:
namespace Library1 module IntFunctions= let private add_ints x y = x + y let addints x y = add_ints x y
Здесь объявлены 2 функции: одна приватная и одна публичная.
Подключаем эту библиотеку к проекту на C# и используем:
using System; using Library1; namespace ConsoleApplication22 { classProgram { staticvoid Main(string[] args) { var q = IntFunctions.addints(3, 4); Console.WriteLine(q.ToString()); Console.ReadLine(); } } }
Если перейти к определению класса IntFunctions, то увидим следующее:
using System; namespace Library1 { public static class IntFunctions { public static int addints(int x, int y); } }
Модуль виден как статический класс, функция видна как статический метод.
Pattern Matching
Сопоставление с образцом. Выражение по очереди подставляется в каждый из вариантов. Если есть совпадение – возвращается соответствующий результат.
let rec fibn = match n with | 0 -> 0 | 1 -> 1 | _ ->fib (n - 1) + fib (n - 2)
Для образцов можно задавать условные ограничения:
let sign x = match x with | 0 -> 0 | x when x < 0-> -1 | x -> 1
Каррирование
Определение с википедии:
Каррирование или карринг (англ. currying) в информатике — преобразование функции от многих аргументов в функцию, берущую свои аргументы по одному.
Все функции в F# каррированы.
Рассмотрим функцию:
let add x y = x + y
ее тип x:int ->y:int ->int
Функциям в F# не обязательно передавать все аргументы сразу. Аргументы они принимают по очереди. Например:
let add3 = add 3
Тип этой функции int ->int
System.Console.WriteLine(add3 4); // выведет 7