C# como você nunca viu!
Conceitos avançados de
programação functional em .NET
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com
Olá, eu sou Elemar Jr
Programação functional com C#
Mas, vamos falar de
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
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
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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;
}
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;
}
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;
}
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;
}
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
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);
}
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();
}
}
}
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();
});
}
}
public class Program
{
public static void Main()
{
using (var reader = new StreamReader("file.txt"))
{
WriteLine(reader.ReadToEnd());
}
}
}
public class Program
{
public static void Main()
{
string content;
using (var reader = new StreamReader("file.txt"))
{
content = reader.ReadToEnd();
}
//..
}
}
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);
}
}
public static TR Using<T, TR>(
T input,
Func<T, TR> func
) where T : IDisposable
{
using (input) return func(input);
}
public class Program
{
public static void Main()
{
var content = Using(new StreamReader("file.txt"), reader =>
reader.ReadToEnd()
);
}
}
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
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);
}
}
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));
public interface IRepository<T, TId>
{
T GetById(TId id);
}
O problema com o null
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 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 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..."
);
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;
}
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..."
);
}
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")
}
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}");
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);
var host = AppSettings["RavenDB.Host"] ?? "localhost";
int port;
if (!int.TryParse(AppSettings["RavenDB.Port"], out port))
port = 8080;
// ..
public static class Parsing
{
public static Option<int> ParseInt(this string s)
{
int result;
return int.TryParse(s, out result)
? Some(result)
: None;
}
}
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);
var host = AppSettings["RavenDB.Host"] ?? "localhost";
var port = AppSettings["RavenDB.Port"].ParseInt().GetOrElse(8080);
public static Option<T> Where<T>(
this Option<T> @this,
Func<T, bool> predicate
)
=> @this.IsSome && predicate(@this.Value) ? @this : None;
var host = AppSettings["RavenDB.Host"] ?? "localhost";
var port = AppSettings["RavenDB.Port"].ParseInt()
.Where(p => p > 0)
.GetOrElse(8080);
public interface IRepository<T, TId>
{
Option<T> GetById(TId id);
}
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);
}
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!");
}
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!");
}
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;
};
}
}
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!");
}
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;
};
}
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!");
}
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
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);
}
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;
}
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));
WriteLine(Divide(a, b).Match(
right: res => $"Result {res}",
left: error => $"Error {error}")
);
elemarjr.com
@elemarjr
linkedin.com/in/elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
Mantenha contato!
C# como você nunca viu!
Conceitos avançados de
programação functional em .NET
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com

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

  • 1.
    C# como vocênunca viu! Conceitos avançados de programação functional em .NET Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com
  • 2.
    Olá, eu souElemar Jr
  • 3.
    Programação functional comC# Mas, vamos falar de
  • 4.
    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
  • 5.
    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
  • 6.
    using System; using System.Threading.Tasks; usingstatic 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); } }
  • 7.
    using System; using System.Threading.Tasks; usingstatic 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); } }
  • 8.
    using System; using System.Threading.Tasks; usingstatic 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); } }
  • 9.
    using System; using System.Threading.Tasks; usingstatic 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); } }
  • 10.
    class Rectangle { public doubleSideA { get; set; } public double SideB { get; set; } public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; } public double Area => SideA*SideB; }
  • 11.
    class Rectangle { public doubleSideA { get; set; } public double SideB { get; set; } public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; } public double Area => SideA*SideB; }
  • 12.
    struct class Rectangle { publicdouble SideA { get; } public double SideB { get; } public Rectangle(double sideA, double sideB) { SideA = sideA; SideB = sideB; } public double Area => SideA*SideB; }
  • 13.
    struct Rectangle { public doubleSideA { 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; }
  • 14.
    static IEnumerable<T> Where<T>( thisIEnumerable<T> source, Func<T, bool> predicate ) { foreach (var e in source) { if (predicate(e)) yield return e; } } Você já conhece High-order functions
  • 15.
    using System; using staticSystem.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); }
  • 16.
    using System; using staticSystem.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(); } } }
  • 17.
    using System; using staticSystem.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(); }); } }
  • 18.
    public class Program { publicstatic void Main() { using (var reader = new StreamReader("file.txt")) { WriteLine(reader.ReadToEnd()); } } }
  • 19.
    public class Program { publicstatic void Main() { string content; using (var reader = new StreamReader("file.txt")) { content = reader.ReadToEnd(); } //.. } }
  • 20.
    using System; using System.IO; usingstatic 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); } }
  • 21.
    public static TRUsing<T, TR>( T input, Func<T, TR> func ) where T : IDisposable { using (input) return func(input); }
  • 22.
    public class Program { publicstatic void Main() { var content = Using(new StreamReader("file.txt"), reader => reader.ReadToEnd() ); } }
  • 23.
    public static classFunctional { 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
  • 24.
    public class Program { publicstatic 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); } }
  • 25.
    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));
  • 26.
    public interface IRepository<T,TId> { T GetById(TId id); } O problema com o null
  • 27.
    public struct Option<T> { internalT 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); }
  • 28.
    public struct Option<T> { internalT 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") }
  • 29.
    public struct Option<T> { internalT 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..." );
  • 30.
    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; }
  • 31.
    public class Program { publicstatic 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..." ); }
  • 32.
    public static classOption { 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") }
  • 33.
    public static classOption { 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}");
  • 34.
    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);
  • 35.
    var host =AppSettings["RavenDB.Host"] ?? "localhost"; int port; if (!int.TryParse(AppSettings["RavenDB.Port"], out port)) port = 8080; // ..
  • 36.
    public static classParsing { public static Option<int> ParseInt(this string s) { int result; return int.TryParse(s, out result) ? Some(result) : None; } }
  • 37.
    public static TGetOrElse<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);
  • 38.
    var host =AppSettings["RavenDB.Host"] ?? "localhost"; var port = AppSettings["RavenDB.Port"].ParseInt().GetOrElse(8080);
  • 39.
    public static Option<T>Where<T>( this Option<T> @this, Func<T, bool> predicate ) => @this.IsSome && predicate(@this.Value) ? @this : None;
  • 40.
    var host =AppSettings["RavenDB.Host"] ?? "localhost"; var port = AppSettings["RavenDB.Port"].ParseInt() .Where(p => p > 0) .GetOrElse(8080);
  • 41.
    public interface IRepository<T,TId> { Option<T> GetById(TId id); }
  • 42.
    public void Run() { WriteLine("Starting..."); varf30 = 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); }
  • 43.
    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!"); }
  • 44.
    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!"); }
  • 45.
    public static classCombinators { 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; }; } }
  • 46.
    public void Run4() { varfibonacci = 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!"); }
  • 47.
    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; }; }
  • 48.
    public void Run5() { varfibonacci = 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!"); }
  • 49.
    public static doubleDivide(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
  • 50.
    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); }
  • 51.
    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; }
  • 52.
    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));
  • 53.
    WriteLine(Divide(a, b).Match( right: res=> $"Result {res}", left: error => $"Error {error}") );
  • 54.
  • 55.
    C# como vocênunca viu! Conceitos avançados de programação functional em .NET Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com