55
C# como você nunca viu! Conceitos avançados de programação functional em .NET Elemar Júnior @elemarjr [email protected] [email protected] elemarjr.com

TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

Embed Size (px)

Citation preview

Page 1: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

C# como você nunca viu! Conceitos avançados de

programação functional em .NETElemar Júnior

@[email protected]@gmail.com

elemarjr.com

Page 2: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

Olá, eu sou Elemar Jr

Page 3: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

Programação functional com C#

Mas, vamos falar de

Page 4: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

Func<int, int> square = x => x*x;var range = Enumerable.Range(1, 10);var sqs = range.Select(square);

Funções são 1st class citzens

Page 5: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

Func<int, bool> isEven = x => x%2 == 0;var original = new[] {4, 7, 9, 3, 2};

var sorted = original.OrderBy(x => x);var filtered = original.Where(isEven);

Direcionamento a imutabilidade

Page 6: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using System.Threading.Tasks;

using static System.Linq.Enumerable;using static System.Console;class Program{ static void Main() { Title = "Concurrent problems";

var data = Range(-10000, 20001).Reverse().ToList(); // [10000, 9999, .. -9999, -10000]

Action t1 = () => WriteLine($"T1 = {data.Sum()}"); Action t2 = () => { data.Sort(); WriteLine($"T2 = {data.Sum()}"); };

Parallel.Invoke(t1, t2); }}

Page 7: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using System.Threading.Tasks;

using static System.Linq.Enumerable;using static System.Console;class Program{ static void Main() { Title = "Concurrent problems";

var data = Range(-10000, 20001).Reverse().ToList(); // [10000, 9999, .. -9999, -10000]

Action t1 = () => WriteLine($"T1 = {data.Sum()}"); Action t2 = () => { data.Sort(); WriteLine($"T2 = {data.Sum()}"); };

Parallel.Invoke(t1, t2); }}

Page 8: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using System.Threading.Tasks;

using static System.Linq.Enumerable;using static System.Console;class Program{ static void Main() { Title = "Concurrent problems";

var data = Range(-10000, 20001).Reverse().ToList(); // [10000, 9999, .. -9999, -10000]

Action t1 = () => WriteLine($"T1 = {data.Sum()}"); Action t2 = () => { data.Sort(); WriteLine($"T2 = {data.Sum()}"); };

Parallel.Invoke(t1, t2); }}

Page 9: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using System.Threading.Tasks;

using static System.Linq.Enumerable;using static System.Console;class Program{ static void Main() { Title = "Concurrent problems";

var data = Range(-10000, 20001).Reverse().ToList(); // [100, 99, .. -99, -100]

Action t1 = () => WriteLine($"T1 = {data.Sum()}"); Action t2 = () => WriteLine($"T2 = {data.OrderBy(x => x).Sum()}"); Parallel.Invoke(t1, t2); }}

Page 10: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

class Rectangle{ public double SideA { get; set; } public double SideB { get; set; }

public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; }

public double Area => SideA*SideB;}

Page 11: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

class Rectangle{ public double SideA { get; set; } public double SideB { get; set; }

public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; }

public double Area => SideA*SideB;}

Page 12: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

struct class Rectangle{ public double SideA { get; } public double SideB { get; }

public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; }

public double Area => SideA*SideB;}

Page 13: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

struct Rectangle{ public double SideA { get; } public double SideB { get; }

public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; }

public Rectangle WithSideA(double newSideA) => new Rectangle(newSideA, SideB);

public Rectangle WithSideB(double newSideB) => new Rectangle(SideB, newSideB);

public double Area => SideA*SideB;}

Page 14: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate){ foreach (var e in source) { if (predicate(e)) yield return e; }}

Você já conhece High-order functions

Page 15: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using static System.Diagnostics.Debug;class Program{ static void Main() { Func<int, int, int> divide = (a, b) => a/b;

var divideBy = divide.SwapArgs();

Assert(divide(8, 2) == divideBy(2, 8)); }}

static class Extensions{ public static Func<T2, T1, TResult> SwapArgs<T1, T2, TResult>( this Func<T1, T2, TResult> f ) => (t2, t1) => f(t1, t2);}

Page 16: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using static System.Console;

class Resource : IDisposable{ public Resource() { WriteLine("created ..."); } public void Foo() => WriteLine("Foo"); public void Fee() => WriteLine("Fee"); public void Dispose() => WriteLine("cleanup..."); }

public class Program{ public static void Main() { using (var r = new Resource()) { r.Foo(); r.Fee(); } }}

Page 17: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using static System.Console;

class Resource //: IDisposable{ private Resource() { WriteLine("created ..."); } public void Foo() => WriteLine("Foo"); public void Fee() => WriteLine("Fee"); void Dispose() => WriteLine("cleanup...");

public static void Use(Action<Resource> block) { var r = new Resource(); // pooling? try { block(r); } finally { r.Dispose(); } }}

public class Program{ public static void Main() { Resource.Use(r => { r.Foo(); r.Fee(); }); }}

Page 18: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public class Program{ public static void Main() { using (var reader = new StreamReader("file.txt")) { WriteLine(reader.ReadToEnd()); } }}

Page 19: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public class Program{ public static void Main() { string content; using (var reader = new StreamReader("file.txt")) { content = reader.ReadToEnd(); } //.. }}

Page 20: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

using System;using System.IO;

using static Functional;using static System.Console;public class Program{ public static void Main() { Using(new StreamReader("file.txt"), reader => { WriteLine(reader.ReadToEnd()); }); }}public static class Functional{ public static void Using<T>( T input, Action<T> action ) where T : IDisposable { using (input) action(input); }}

Page 21: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static TR Using<T, TR>( T input, Func<T, TR> func ) where T : IDisposable{ using (input) return func(input);}

Page 22: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public class Program{ public static void Main() { var content = Using(new StreamReader("file.txt"), reader => reader.ReadToEnd() ); }}

Page 23: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static class Functional{ public static void Using<T>( T input, Action<T> action ) where T : IDisposable { using (input) action(input); }

public static TR Using<T, TR>( T input, Func<T, TR> func ) where T : IDisposable { using (input) return func(input); }}

O problema com o Void

Page 24: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public class Program{ public static void Main() { Using(new StreamReader("file.txt"), reader => { WriteLine(reader.ReadToEnd()); return Unit(); }); }}

public struct Unit { }public static class Functional{ static readonly Unit unit = new Unit(); public static Unit Unit() => unit;

public static TR Using<T, TR>( T input, Func<T, TR> func ) where T : IDisposable { using (input) return func(input); }}

Page 25: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static Func<T, Unit> ToFunc<T>(Action<T> action) => o =>{ action(o); return Unit();};

Action<StreamReader> print = (s) => WriteLine(s.ReadToEnd());Using(new StreamReader("file.txt"), ToFunc(print));

Page 26: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public interface IRepository<T, TId>{ T GetById(TId id);}

O problema com o null

Page 27: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public struct Option<T>{ internal T Value { get; } public bool IsSome { get; } public bool IsNone => !IsSome;

internal Option(T value, bool isSome) { IsSome = isSome; Value = value; }

public TR Match<TR>(Func<T, TR> some, Func<TR> none) => IsSome ? some(Value) : none();}public static class Option{ public static Option<T> Of<T>(T value) => new Option<T>(value, value != null);

}

Page 28: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public struct Option<T>{ internal T Value { get; } public bool IsSome { get; } public bool IsNone => !IsSome;

internal Option(T value, bool isSome) { IsSome = isSome; Value = value; }

public TR Match<TR>(Func<T, TR> some, Func<TR> none) => IsSome ? some(Value) : none();}public static class Option{ public static Option<T> Of<T>(T value) => new Option<T>(value, value != null);

}

public static void Main(){ string _ = null, s = "Elemar";

var o1 = Option.Of(_); // None var o2 = Option.Of(s); // Some("Elemar")}

Page 29: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public struct Option<T>{ internal T Value { get; } public bool IsSome { get; } public bool IsNone => !IsSome;

internal Option(T value, bool isSome) { IsSome = isSome; Value = value; }

public TR Match<TR>(Func<T, TR> some, Func<TR> none) => IsSome ? some(Value) : none();}public static class Option{ public static Option<T> Of<T>(T value) => new Option<T>(value, value != null);

}

public static void Main(){ string _ = null, s = "Elemar";

var o1 = Option.Of(_); // None var o2 = Option.Of(s); // Some("Elemar")}

public void SayHello(string name) => WriteLine(GreetingFor(name));

public string GreetingFor(string name) => Option.Of(name).Match( some: n => $"Hello {n}", none: () => "Sorry..." );

Page 30: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public struct NoneType { }public static class Functional{ public static Option<T> Some<T>(T value) => Option.Of(value); public static readonly NoneType None = new NoneType();

public struct Option<T>{

...

public static readonly Option<T> None = new Option<T>();

public static implicit operator Option<T>(T value) => Some(value);

public static implicit operator Option<T>(NoneType _) => None;}

Page 31: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public class Program{ public static void Main() { SayHello("Elemar"); SayHello(null); }

public static void SayHello(string name) => WriteLine(GreetingFor(name));

public static string GreetingFor(Option<string> name) => name.Match( some: n => $"Hello {n}", none: () => "Sorry..." );}

Page 32: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static class Option{ public static Option<T> Of<T>(T value) => new Option<T>(value, value != null);

public static Option<TR> Map<T, TR>( this Option<T> @this, Func<T, TR> func) => @this.IsSome ? Some(func(@this.Value)) : None;}

public static void Main(){ string _ = null, s = "Elemar";

Func<string, string> greetingFor = name => $"Hello {name}";

var o1 = Option.Of(_).Map(greetingFor); // None var o2 = Option.Of(s).Map(greetingFor); // Some("Hello Elemar")}

Page 33: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static class Option{ public static Option<T> Of<T>(T value) => new Option<T>(value, value != null);

public static Option<TR> Map<T, TR>( this Option<T> @this, Func<T, TR> func) => @this.IsSome ? Some(func(@this.Value)) : None;}

Option<string> _ = null, s = "Elemar";_.Map(n => $"Hello {n}");s.Map(n => $"Hello {n}");

Page 34: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static Option<Unit> ForEach<T>( this Option<T> @this, Action<T> action) => Map(@this, ToFunc(action));

Option<string> _ = null, s = "Elemar";_.Map(n => $"Hello {n}").ForEach(WriteLine);s.Map(n => $"Hello {n}").ForEach(WriteLine);

Page 35: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

var host = AppSettings["RavenDB.Host"] ?? "localhost";

int port;if (!int.TryParse(AppSettings["RavenDB.Port"], out port)) port = 8080;

// ..

Page 36: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static class Parsing{ public static Option<int> ParseInt(this string s) { int result; return int.TryParse(s, out result) ? Some(result) : None; }}

Page 37: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static T GetOrElse<T>( this Option<T> @this, Func<T> fallback) => @this.Match( some: value => value, none: fallback );

public static T GetOrElse<T>( this Option<T> @this, T @else) => GetOrElse(@this, () => @else);

Page 38: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

var host = AppSettings["RavenDB.Host"] ?? "localhost";var port = AppSettings["RavenDB.Port"].ParseInt().GetOrElse(8080);

Page 39: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static Option<T> Where<T>( this Option<T> @this, Func<T, bool> predicate ) => @this.IsSome && predicate(@this.Value) ? @this : None;

Page 40: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

var host = AppSettings["RavenDB.Host"] ?? "localhost";var port = AppSettings["RavenDB.Port"].ParseInt() .Where(p => p > 0) .GetOrElse(8080);

Page 41: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public interface IRepository<T, TId>{ Option<T> GetById(TId id);}

Page 42: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public void Run(){ WriteLine("Starting..."); var f30 = Fibonacci(30); var f35 = Fibonacci(35); var f40 = Fibonacci(40); var f45 = Fibonacci(45); WriteLine("Results: {0}, {1}, {2}, {3}", f30, f35, f40, f45); WriteLine("Done!");}

public int Fibonacci(int n){ if (n == 0) return 0; if (n == 1) return 1; return Fibonacci(n - 1) + Fibonacci(n - 2);}

Page 43: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public void Run2(){ Func<int, int> fibonacci = Fibonacci;

WriteLine("Starting..."); var f30 = fibonacci(30); var f35 = fibonacci(35); var f40 = fibonacci(40); var f45 = fibonacci(45); WriteLine($"Results: {f30}, {f35}, {f40}, {f45}"); WriteLine("Done!");}

Page 44: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public void Run3(){ Func<int, int> fibonacci = Fibonacci;

WriteLine("Starting..."); var f30 = fibonacci(30); WriteLine($"Input: 30 Result: {f30}");

var f35 = fibonacci(35); WriteLine($"Input: 35 Result: {f35}");

var f40 = fibonacci(40); WriteLine($"Input: 40 Result: {f40}");

var f45 = fibonacci(45); WriteLine($"Input: 50 Result: {f45}");

WriteLine($"Results: {f30}, {f35}, {f40}, {f45}"); WriteLine("Done!");}

Page 45: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static class Combinators{ public static Func<T, TResult> Print<T, TResult>(Func<T, TResult> func) { return (input) => { var result = func(input); WriteLine($"Input: {input} Result: {result}"); return result; }; }}

Page 46: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public void Run4(){ var fibonacci = Combinators.Print<int, int>(Fibonacci);

WriteLine("Starting..."); var f30 = fibonacci(30); var f35 = fibonacci(35); var f40 = fibonacci(40); var f45 = fibonacci(45); WriteLine($"Results: {f30}, {f35}, {f40}, {f45}"); WriteLine("Done!");}

Page 47: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static Func<T, TResult> Time<T, TResult>(Func<T, TResult> func){ return (input) => { var before = DateTime.Now; var result = func(input); WriteLine($"Time to this input: {DateTime.Now - before}"); return result; };}

Page 48: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public void Run5(){ var fibonacci = Combinators.Time( Combinators.Print<int, int>(Fibonacci) );

WriteLine("Starting..."); var f30 = fibonacci(30); var f35 = fibonacci(35); var f40 = fibonacci(40); var f45 = fibonacci(45); WriteLine($"Results: {f30}, {f35}, {f40}, {f45}"); WriteLine("Done!");}

Page 49: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static double Divide(double a, double b){ if (Math.Abs(b) < 0.00001) { throw new ArgumentException("b could not be 0."); }

return a/b;}

O problema com o Exceptions

Page 50: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public struct Either<TL, TR>{ internal TL Left { get; } internal TR Right { get; }

public bool IsLeft => !IsRight; public bool IsRight { get; }

internal Either(TL left) { IsRight = false; Left = left; Right = default(TR); }

internal Either(TR right) { IsRight = true; Right = right; Left = default(TL); }

public static implicit operator Either<TL, TR>(TL left) => new Either<TL, TR>(left);

public static implicit operator Either<TL, TR>(TR right) => new Either<TL, TR>(right);}

Page 51: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public static Either<string, double> Divide(double a, double b){ if (Math.Abs(b) < 0.00001) { return "b could not be 0."; }

return a/b;}

Page 52: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

public TR Match<TR>(Func<L, TR> left, Func<R, TR> right) => IsLeft ? left(Left) : right(Right);

public Unit Match<TR>(Action<L> left, Action<R> right) => Match(ToFunc(left), ToFunc(right));

Page 53: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

WriteLine(Divide(a, b).Match( right: res => $"Result {res}", left: error => $"Error {error}") );

Page 55: TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de programação funcional em .NET

C# como você nunca viu! Conceitos avançados de

programação functional em .NETElemar Júnior

@[email protected]@gmail.com

elemarjr.com