Post on 08-Nov-2018
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Elemar Jr
São as cicatrizes que contam a história do
guerreiro.
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Elemar Jr
10 INPUT A, B
20 FOR I = A TO B STEP 1
30 IF I MOD 2 = 0 THEN GOTO 50
40 PRINT I
50 NEXT I
60 END
Programação funcional é um paradigma cada vez mais importante.
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Conceitos > Técnicas
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Guidelines para ser “mais funcional”
• Seja declarativo
•Projete para imutabilidade
• Evite “side effects”
•Prefira expressões em lugar de “statements”
•Utilize “high-order functions”
Todas as principais linguagens estão evoluindo para suportar o paradigma
funcional.
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public interface IShape{
double SideA { get; set; }double SideB { get; set; }bool CanRotate { get; set; }double Area { get; set; }
}
C#
Imutabilidade
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public sealed class CuttingPlan{
public IEnumerable<Shape> ShapesToCut { get; }public IPlacementStrategy PlacementStrategy { get; }public double Margin { get; }
public CuttingPlan(IEnumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, double margin) : this(shapesToCut, placementStrategy, margin, new CuttingLayout[0])
{ }
public CuttingPlan(Enumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, ouble margin,IEnumerable<CuttingLayout> layouts)
{ShapesToCut = shapesToCut;PlacementStrategy = placementStrategy;Margin = margin;Layouts = layouts;
}
public IEnumerable<CuttingLayout> Layouts { get; }public bool IsCompleted => !ShapesToCut.Any();
public CuttingPlan AddLayout(CuttingLayout layout){
var newShapesToCut =ShapesToCut.Where(shape => layout.Placements.All(p => p.Shape.Concrete() != shape)).ToList();
return new CuttingPlan(newShapesToCut, PlacementStrategy, Margin, Layouts.Concat(new[] { layout }));}
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public sealed class CuttingPlan{
public IEnumerable<Shape> ShapesToCut { get; }public IPlacementStrategy PlacementStrategy { get; }public double Margin { get; }
public CuttingPlan(IEnumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, double margin) : this(shapesToCut, placementStrategy, margin, new CuttingLayout[0])
{ }
public CuttingPlan(Enumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, ouble margin,IEnumerable<CuttingLayout> layouts)
{ShapesToCut = shapesToCut;PlacementStrategy = placementStrategy;Margin = margin;Layouts = layouts;
}
public IEnumerable<CuttingLayout> Layouts { get; }public bool IsCompleted => !ShapesToCut.Any();
public CuttingPlan AddLayout(CuttingLayout layout){
var newShapesToCut =ShapesToCut.Where(shape => layout.Placements.All(p => p.Shape.Concrete() != shape)).ToList();
return new CuttingPlan(newShapesToCut, PlacementStrategy, Margin, Layouts.Concat(new[] { layout }));}
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Pure Functionsem side effects e, para os mesmos
parâmetros, retorna sempre o mesmo resultado.
(Implicity Thread Safe)
public sealed class CuttingPlan{
public IEnumerable<Shape> ShapesToCut { get; }public IPlacementStrategy PlacementStrategy { get; }public double Margin { get; }
public CuttingPlan(IEnumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, double margin) : this(shapesToCut, placementStrategy, margin, new CuttingLayout[0])
{ }
public CuttingPlan(Enumerable<Shape> shapesToCut, IPlacementStrategy placementStrategy, ouble margin,IEnumerable<CuttingLayout> layouts)
{ShapesToCut = shapesToCut;PlacementStrategy = placementStrategy;Margin = margin;Layouts = layouts;
}
public IEnumerable<CuttingLayout> Layouts { get; }public bool IsCompleted => !ShapesToCut.Any();
public CuttingPlan AddLayout(CuttingLayout layout){
var newShapesToCut =ShapesToCut.Where(shape => layout.Placements.All(p => p.Shape.Concrete() != shape)).ToList();
return new CuttingPlan(newShapesToCut, PlacementStrategy, Margin, Layouts.Concat(new[] { layout }));}
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Mudanças de objetos retornam
sempre novas instâncias
C#
public interface IPlanner{
CuttingPlan Execute(CuttingPlan plan,IStockProvider stockProvider);
}
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
protected override void ApplyMutations(IList<Hint> arrayToMutate, double mutationRate, int ignore)
{for (var i = ignore; i < arrayToMutate.Count; i++){
arrayToMutate[i] = arrayToMutate[i].Mutate(mutationRate);}
}
protected override void FillWithCrossovers(IList<Hint> arrayToFill){
for (var i = 0; i < arrayToFill.Count; i++){
if (arrayToFill[i] != null) continue;
var parent1 = PickUsingTournament();var parent2 = PickUsingTournament();arrayToFill[i] = parent1.CrossOver(parent2);
}}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
C#protected override void ApplyMutations(IList<Hint> arrayToMutate, double mutationRate, int ignore)
{Parallel.For(ignore, arrayToMutate.Count, (i) =>{
arrayToMutate[i] = arrayToMutate[i].Mutate(mutationRate);});
}
protected override void FillWithCrossovers(IList<Hint> arrayToFill){
Parallel.For(0, arrayToFill.Count, (i) =>{
if (arrayToFill[i] != null) return;
var parent1 = PickUsingTournament();var parent2 = PickUsingTournament();arrayToFill[i] = parent1.CrossOver(parent2);
});}
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
C#protected override void ApplyMutations(IList<Hint> arrayToMutate, double mutationRate, int ignore)
{Parallel.For(ignore, arrayToMutate.Count, (i) =>{
arrayToMutate[i] = arrayToMutate[i].Mutate(mutationRate);});
}
protected override void FillWithCrossovers(IList<Hint> arrayToFill){
Parallel.For(0, arrayToFill.Count, (i) =>{
if (arrayToFill[i] != null) return;
var parent1 = PickUsingTournament();var parent2 = PickUsingTournament();arrayToFill[i] = parent1.CrossOver(parent2);
});}
60%+performance
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
BigDecimal totalOfDiscountedPrices = BigDecimal.ZERO;
for (BigDecimal price : prices) {
if (price.compareTo(BigDecimal.valueOf(20)) > 0) {
totalOfDiscountedPrices = totalOfDiscountedPrices.add(
price.multiply(BigDecimal.valueOf(0.9))
);
}
}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Filter
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Filter Map
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Filter Map Reduce
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final BigDecimal totalOfDiscountedPrices = prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalOfDiscountedPrices = BigDecimal.ZERO;
for (BigDecimal price : prices) {
if (price.compareTo(BigDecimal.valueOf(20)) > 0) {
totalOfDiscountedPrices = totalOfDiscountedPrices.add(
price.multiply(BigDecimal.valueOf(0.9))
);
}
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
var totalDiscountedPrices = prices.Where(price => price.CompareTo(20M) > 0).Select(price => price*0.9M).Sum();
Where Select Sum
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Where Select Sum
var discountedPrices =from price in priceswhere price.CompareTo(20M) > 0select price*0.9M;
var totalDiscountedPrices = discountedPrices.Sum();
Javascript
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
var totalOfDiscountedPrices = prices.filter(function (p) { return p > 20; }).map(function (p) { return p * 0.9; }).reduce(function (a, b) { return a + b; });
Filter Map Reduce
Javascript
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
var totalOfDiscountedPrices = prices.values().filter(function (p) { return p > 20; }).map(function (p) { return p * 0.9; }).reduce(function (a, b) { return a + b; });
Filter Map Reduce
Iterators/Generatorsresolvem esse
problema
Typescript
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Filter Map Reduce
var totalOfDiscountedPrices = prices.filter(p => p > 20).map(p => p * 0.9).reduce((a, b) => a + b);
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
template <template <typename, typename> class OutputCont = std::vector,template <typename> class Alloc = std::allocator,typename Fn, class Cont
>OutputCont<typename Cont::value_type, Alloc<typename Cont::value_type >>map(Fn mapfn, const Cont& inputs){
OutputCont<typename Cont::value_type, Alloc<typename Cont::value_type >> result;for (auto& item : inputs)
result.push_back(mapfn(item));return result;
}
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
std::vector<double> values;
std::cout << "Enter values separated by one or more spaces. Enter Ctrl+Z to End: \n";
values.insert(begin(values),std::istream_iterator<double>(std::cin),std::istream_iterator<double>());
std::cout << "The average is"<< accumulate(begin(values), end(values), 0.0) / values.size()<< std::endl;
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
template <template <typename, typename> class OutputCont = std::vector,template <typename> class Alloc = std::allocator,typename Fn, class Cont
>OutputCont<typename Cont::value_type, Alloc<typename Cont::value_type >>filter(Fn filterfn, const Cont& inputs){
OutputCont<typename Cont::value_type, Alloc<typename Cont::value_type >> result;for (auto& item : inputs)
if (filterfn(item))result.push_back(item);
return result;}
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
template <class Cont>typename Cont::value_type sum(const Cont& inputs){
typename Cont::value_type seed{};return std::accumulate(begin(inputs), end(inputs), seed);
}
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
auto totalOfDiscountedPrices = sum(map([](double p) { return p * 0.9; },filter([](double p) { return p > 20; },
prices)));
Filter Map Sum
C++ (N4286)
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
template< typename Fn, typename T >static generator<T> map(Fn mapfn, generator<T> gen){
for (auto val : gen) {__yield_value mapfn(val);
}}
C++ (N4286)
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
template< typename Fn, typename T >static generator<T> map(Fn filterfn, generator<T> gen){
for (auto val : gen) {if (pred(val)) {
__yield_value val;}
}}
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
auto totalOfDiscountedPrices = sum(map([](double p) { return p * 0.9; },filter([](double p) { return p > 20; },
prices)));
Filter Map Sum
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
for (int i = 0; i < customers.size(); i ++) {
System.out.println(customers.get(i).getName());
}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
for (Customer customer : customers) {
System.out.println(customer.getName());
}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.forEach(new Consumer<Customer>() {
public void accept(final Customer customer) {
System.out.println(customer.getName());
}
});
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.forEach(new Consumer<Customer>() {
public void accept(final Customer customer) {
System.out.println(customer.getName());
}
});
@FunctionalInterface
public interface Consumer<T>
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.forEach((customer) -> System.out.println(customer.getName()));
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.forEach(System.out::println);
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.ForEach(c => Console.WriteLine(c.Name));
public static class Extensions{
public static void ForEach<T>(this IEnumerable<T> inputs,Action<T> action)
{foreach (var input in inputs)
action(input);}
}
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
std::for_each(begin(customers),end(customers),[](const Customer& customer) {
std::cout << customer.getName();});
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
customers.stream()
.map(c -> c.getName())
.map(s -> s.toUpperCase())
.forEach(System.out::println);
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
final Predicate<Customer> nameStartingWithN =
(customer) -> customer.getName().startsWith("N");
final Function<Customer, String> UpperCaseName =
(customer) -> customer.getName().toUpperCase();
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
private Predicate<Customer> nameStartingWithN =(customer) => customer.Name.StartsWith("N");
private Func<Customer, string> UpperCaseName =(customer) => customer.Name.ToUpper();
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void Run(){
Console.WriteLine("Starting...");var f30 = Fibonacci(30);var f35 = Fibonacci(35);var f40 = Fibonacci(40);var f45 = Fibonacci(45);Console.WriteLine("Results: {0}, {1}, {2}, {3}", f30, f35, f40, f45);Console.WriteLine("Done!");
}
public int Fibonacci(int n){
if (n == 0) return 0;if (n == 1) return 1;return Fibonacci(n - 1) + Fibonacci(n - 2);
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void Run(){
Func<int, int> fibonacci = Fibonacci;
Console.WriteLine("Starting...");var f30 = fibonacci(30);var f35 = fibonacci(35);var f40 = fibonacci(40);var f45 = fibonacci(45);Console.WriteLine("Results: {0}, {1}, {2}, {3}", f30, f35, f40, f45);Console.WriteLine("Done!");
}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void run() {
System.out.println("Starting..");
final Function<Integer, Integer> fibo = Program::fibonacci;
int f30 = fibo.apply(30);;
int f35 = fibo.apply(35);
int f40 = fibo.apply(40);
int f45 = fibo.apply(45);
System.out.println("Results: " + f30 + ", " + f35 + ", " + f40 + ", " + f45);
System.out.println("Done!");
}
public static int fibonacci(final int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void Run(){
Func<int, int> fibonacci = Fibonacci;
Console.WriteLine("Starting...");var f30 = fibonacci(30);Console.WriteLine("Input: {0} Result: {1}", 30, f30);
var f35 = fibonacci(35);Console.WriteLine("Input: {0} Result: {1}", 35, f35);
var f40 = fibonacci(40);Console.WriteLine("Input: {0} Result: {1}", 40, f40);
var f45 = fibonacci(45);Console.WriteLine("Input: {0} Result: {1}", 45, f45);
Console.WriteLine("Results: {0}, {1}, {2}, {3}", f30, f35, f40, f45);Console.WriteLine("Done!");
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public static Func<T, TResult> PrintingResult<T, TResult>(this Func<T, TResult> func){
return (input) =>{
var result = func(input);Console.WriteLine("Input: {0} Result: {1}", input, result);return result;
};}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public static <T, TResult> Function<T, TResult>
PrintingResult(Function<T, TResult> func) {
return (input) -> {
TResult result = func.apply(input);
System.out.println("Input " + input + " Result: " + result);
return result;
};
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public static Func<T, TResult> MeasuringTime<T, TResult>(Func<T, TResult> func){
return (input) =>{
var before = DateTime.Now;var result = func(input);Console.WriteLine("Time to this input: {0}", DateTime.Now - before);return result;
};}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public static <T, TResult> Function<T, TResult>
MeasuringTime(Function<T, TResult> func) {
return (input) -> {
long before = System.currentTimeMillis();
TResult result = func.apply(input);
long ellapsed = (System.currentTimeMillis() - before);
System.out.println("Time to this input: " + ellapsed);
return result;
};
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void Run(){
Console.WriteLine("Starting...");var fibonacci = ((Func<int, int>) Fibonacci)
.PrintingResult()
.MeasuringTime();
var f30 = fibonacci(30);var f35 = fibonacci(35);var f40 = fibonacci(40);var f45 = fibonacci(45);Console.WriteLine("Results: {0}, {1}, {2}, {3}", f30, f35, f40, f45);Console.WriteLine("Done!");
}
Java
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public void run() {
System.out.println("Starting..");
final Function<Integer, Integer> fibo =
MeasuringTime(PrintingResult(Program::fibonacci));
int f30 = fibo.apply(30);
int f35 = fibo.apply(35);
int f40 = fibo.apply(40);
int f45 = fibo.apply(45);
System.out.println("Results: " + f30 + ", " + f35 + ", " + f40 + ", " + f45);
System.out.println("Done!");
}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Func<int, int, int> add = (a, b) => a + b;Console.WriteLine(add(2, 5));
Func<int, Func<int, int>> addC = a => b => a + b;Console.WriteLine(addC(2)(5));
var succ = addC(1);Console.WriteLine(succ(5));
C++
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
auto add = [](int a, int b) { return a + b; };auto succ = std::bind(add, 1, _1);
std::cout << succ(5); // output = 2
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
public static class Currying{
public static Func<T1, Action<T2>>Curry<T1, T2>(this Action<T1, T2> action)
{return a => b => action(a, b);
}
public static Func<T1, Func<T2, Action<T3>>>Curry<T1, T2, T3>(this Action<T1, T2, T3> action)
{return a => b => c => action(a, b, c);
}}
C#
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
var wl = ((Action<string, string>) Console.WriteLine).Curry();var alert = wl("ALERT: {0}");
alert("Hello World");alert("This is the second alert");alert("This is the third alert");
O que vem por aí?
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
@elemarjr | linkedin.com/in/elemarjr | elemarjr.com
Elemar Jr