Leveraging the benefits of
the functional paradigm
Afif Mohammed
@askafif
linkedin.com/in/afifmohammed/
Working effectively with code
• Cannot remain on top of every behavior and every iteration over that
behavior
• Effectiveness is qualified by the ability to reason well
• Effectiveness is qualified by the ability to extend existing function via
composition
What constitutes effective
reasoning?
Its not the same as readability, which is very subjective and is largely a function of
familiarity.
How effectively can you reason through this?
How effectively can you reason through this?
What constitutes effective
reasoning?
• The less you have to reason with the better
• Effectively apply logical thinking
• A common language needs to be learned
What constitutes effective
composition?
Not the same as coordination where order and execution needs to be followed in
lockstep
How effectively can you compose?
How effectively can you compose?
What constitutes effective
composition?
• Action is deferred to the last responsible moment
• Usage is driven by the context of the Consumer
• Allows for multiple approaches to the same result
So what are the principles that
underpin FP?
• How do they promote effective reasoning?
• How do they promote effective composition?
• How does that look in practice in a typed language?
Total functions return an output
for every input
• How is this represented in a typed language?
• How does this help with reasoning?
• How does this help with composition?
{fname:string, sname:string, dob:DateTime, email:string}
Customer
{"@..", null, "2025/1/1", "a@_"}
{fname:string, sname:string, dob:DateTime, email:string}
Tuple<string[], Customer>
string
string
Either<string[], FirstName>
Either<string[], LastName>
DateTime
Either<string[], DateOfBirth>
FirstName
LastName
DateOfBirth
Email
Url
Postcode
CustomerId
• By removing input validation that is not core to the domain of the function, we
have made the function more cohesive
• A consumer better understands what are the pre-conditions to calling the
function
public Customer FindBy(string fname, string lname, string email);
public Customer FindBy(Firstname firstName, Lastname lastName, Email email);
Total functions return an output
for every input
Total functions return an output for
every input
• The types inform the consumer that finding a value is optional by design
• The types inform the consumer that an exception is possible by design
public Optional<Customer> FindBy(Firstname firstName, Lastname lastName, Email email);
public Either<Exception, Optional<Customer>> FindBy(
Firstname firstName,
Lastname lastName,
Email email);
public Customer FindBy(Firstname firstName, Lastname lastName, Email email);
Customer FindBy(FirstName firstName, LastName lastname, Email email);
bool IsPreferred(Customer customer);
var preferred = IsPreferred(FindCustomerBy(fname, lname, email));
Either<Exception, Optional<Customer>> FindBy(FirstName firstName, LastName lastName, Email email);
Either<Exception, Optional<bool>> IsPreferred(Either<Exception, Optional<Customer>> either)
{
if (!either.HasResult) return either.Error;
var optional = either.Result;
if (!optional.HasValue) return Optional.Empty;
return IsPreferred(optional.Value);
}
static Either<TError, Optional<TB>> Pipe<TError, TA, TB>(
this Either<TError, Optional<TA>> either,
Func<TA, TB> map)
{
if (!either.HasResult) return either.Error;
var optional = either.Result;
if (!optional.HasValue) return Optional.Empty;
return Map(optional.Value);
}
var preferred = Pipe(FindCustomerBy(fname, lname, email), IsPreferred);
Total functions return an output for
every input
• By capturing all known behaviors within our type signature, its made possible for
consumers to elect into what behavior they wish to build on
• Simply follow the types and all known concerns are addressed
public Optional<Customer> FindBy(Firstname firstName, Lastname lastName, Email email);
public Either<Exception, Optional<Customer>> FindBy(
Firstname firstName,
Lastname lastName,
Email email);
public Customer FindBy(Firstname firstName, Lastname lastName, Email email);
Deterministic functions return the
same output for the same input
• How is this represented in a typed language?
• How does this help with reasoning?
• How does this help with composition?
WeatherReading GetCurrentWeatherReadingAt(Location location);
WeatherReading GetWeatherReadingAt(Location location, DateTime time);
WeatherReading GetWeatherReadingAt(Location location, DateTime time, DateTime readingAsOf);
string[] Top(IEnumerable<string> values, int count);
static Func<WeatherReader, WeatherReading> GetWeatherReadingAt(
Location location,
DateTime time,
DateTime readingAsOf);
delegate IEnumerable<WeatherReadingRecord> WeatherReader(WeatherQuery query);
Percentage CalculateRainProbability(WeatherReading reading);
Func<TEnv, TB> Pipe<TEnv, TA, TB>(Func<TEnv, TA> fa, Func<TA, TB> fb)
{
return env => fb(fa(env));
}
var percentage = Pipe(
GetWeatherReadingAt(melbourne, time: now, readingAsOf: oneHourAgo),
CalculateRainProbability);
Deterministic functions return the
same output for the same input
• Instead of limiting the context to how its meant to be used, it exposes the complete
context required to understand all the variables that participate in the outcome.
• By exposing full context, it enables the consumer/composer to drive usage, and by
deferring execution, it enables that action to be interpreted at the last responsible
moment as suited to the consumer.
WeatherReading GetCurrentWeatherReadingAt(Location location);
static Func<WeatherReader, WeatherReading> GetWeatherReadingAt(
Location location,
DateTime time,
DateTime readingAsOf);
Func<TEnv, TB> Pipe<TEnv, TA, TB>(
Func<TEnv, TA> fa,
Func<TA, TB> fb) => env => fb(fa(env));
Pure functions have no side
effects, only an output
• How is this represented in a typed language?
• How does this help with reasoning?
• How does this help with composition?
Pure functions have no side
effects, only an output
public RefundService(
ICustomerRepository customerRepository,
ILogger logger,
IRefundRepository refundRepository)
public Error[] ApproveRefund(Request r)
static Error[] ApproveRefund(
Request r,
Func<CustomerId, Customer> getCustomer,
Action<LogMessage[]> log,
Action<Refund> save);
static Either<Error[], Tuple<LogMessage[], Refund>> ApproveRefund(
Request r,
Customer c)
Working effectively with code
• Cannot remain on top of every behavior and every iteration over that
behavior
• Effectiveness is qualified by the ability to reason well
• Effectiveness is qualified by the ability to extend existing function via
composition
• The less you have to reason with the better
• Effectively apply logical thinking
• A common language needs to be learned
What constitutes effective
composition?
• Action is deferred to the last responsible moment
• Usage is driven by the context of the Consumer
• Allows for multiple approaches to the same result
What constitutes effective
reasoning?
Afif Mohammed
@askafif
linkedin.com/in/afifmohammed/

Leveraging benefits of the functional paradigm

  • 1.
    Leveraging the benefitsof the functional paradigm Afif Mohammed @askafif linkedin.com/in/afifmohammed/
  • 2.
    Working effectively withcode • Cannot remain on top of every behavior and every iteration over that behavior • Effectiveness is qualified by the ability to reason well • Effectiveness is qualified by the ability to extend existing function via composition
  • 3.
    What constitutes effective reasoning? Itsnot the same as readability, which is very subjective and is largely a function of familiarity.
  • 4.
    How effectively canyou reason through this?
  • 5.
    How effectively canyou reason through this?
  • 6.
    What constitutes effective reasoning? •The less you have to reason with the better • Effectively apply logical thinking • A common language needs to be learned
  • 7.
    What constitutes effective composition? Notthe same as coordination where order and execution needs to be followed in lockstep
  • 8.
    How effectively canyou compose?
  • 9.
    How effectively canyou compose?
  • 10.
    What constitutes effective composition? •Action is deferred to the last responsible moment • Usage is driven by the context of the Consumer • Allows for multiple approaches to the same result
  • 11.
    So what arethe principles that underpin FP? • How do they promote effective reasoning? • How do they promote effective composition? • How does that look in practice in a typed language?
  • 13.
    Total functions returnan output for every input • How is this represented in a typed language? • How does this help with reasoning? • How does this help with composition?
  • 14.
    {fname:string, sname:string, dob:DateTime,email:string} Customer {"@..", null, "2025/1/1", "a@_"} {fname:string, sname:string, dob:DateTime, email:string} Tuple<string[], Customer>
  • 16.
    string string Either<string[], FirstName> Either<string[], LastName> DateTime Either<string[],DateOfBirth> FirstName LastName DateOfBirth Email Url Postcode CustomerId
  • 17.
    • By removinginput validation that is not core to the domain of the function, we have made the function more cohesive • A consumer better understands what are the pre-conditions to calling the function public Customer FindBy(string fname, string lname, string email); public Customer FindBy(Firstname firstName, Lastname lastName, Email email); Total functions return an output for every input
  • 18.
    Total functions returnan output for every input • The types inform the consumer that finding a value is optional by design • The types inform the consumer that an exception is possible by design public Optional<Customer> FindBy(Firstname firstName, Lastname lastName, Email email); public Either<Exception, Optional<Customer>> FindBy( Firstname firstName, Lastname lastName, Email email); public Customer FindBy(Firstname firstName, Lastname lastName, Email email);
  • 19.
    Customer FindBy(FirstName firstName,LastName lastname, Email email); bool IsPreferred(Customer customer); var preferred = IsPreferred(FindCustomerBy(fname, lname, email)); Either<Exception, Optional<Customer>> FindBy(FirstName firstName, LastName lastName, Email email); Either<Exception, Optional<bool>> IsPreferred(Either<Exception, Optional<Customer>> either) { if (!either.HasResult) return either.Error; var optional = either.Result; if (!optional.HasValue) return Optional.Empty; return IsPreferred(optional.Value); } static Either<TError, Optional<TB>> Pipe<TError, TA, TB>( this Either<TError, Optional<TA>> either, Func<TA, TB> map) { if (!either.HasResult) return either.Error; var optional = either.Result; if (!optional.HasValue) return Optional.Empty; return Map(optional.Value); } var preferred = Pipe(FindCustomerBy(fname, lname, email), IsPreferred);
  • 20.
    Total functions returnan output for every input • By capturing all known behaviors within our type signature, its made possible for consumers to elect into what behavior they wish to build on • Simply follow the types and all known concerns are addressed public Optional<Customer> FindBy(Firstname firstName, Lastname lastName, Email email); public Either<Exception, Optional<Customer>> FindBy( Firstname firstName, Lastname lastName, Email email); public Customer FindBy(Firstname firstName, Lastname lastName, Email email);
  • 21.
    Deterministic functions returnthe same output for the same input • How is this represented in a typed language? • How does this help with reasoning? • How does this help with composition?
  • 22.
    WeatherReading GetCurrentWeatherReadingAt(Location location); WeatherReadingGetWeatherReadingAt(Location location, DateTime time); WeatherReading GetWeatherReadingAt(Location location, DateTime time, DateTime readingAsOf); string[] Top(IEnumerable<string> values, int count); static Func<WeatherReader, WeatherReading> GetWeatherReadingAt( Location location, DateTime time, DateTime readingAsOf); delegate IEnumerable<WeatherReadingRecord> WeatherReader(WeatherQuery query); Percentage CalculateRainProbability(WeatherReading reading); Func<TEnv, TB> Pipe<TEnv, TA, TB>(Func<TEnv, TA> fa, Func<TA, TB> fb) { return env => fb(fa(env)); } var percentage = Pipe( GetWeatherReadingAt(melbourne, time: now, readingAsOf: oneHourAgo), CalculateRainProbability);
  • 23.
    Deterministic functions returnthe same output for the same input • Instead of limiting the context to how its meant to be used, it exposes the complete context required to understand all the variables that participate in the outcome. • By exposing full context, it enables the consumer/composer to drive usage, and by deferring execution, it enables that action to be interpreted at the last responsible moment as suited to the consumer. WeatherReading GetCurrentWeatherReadingAt(Location location); static Func<WeatherReader, WeatherReading> GetWeatherReadingAt( Location location, DateTime time, DateTime readingAsOf); Func<TEnv, TB> Pipe<TEnv, TA, TB>( Func<TEnv, TA> fa, Func<TA, TB> fb) => env => fb(fa(env));
  • 24.
    Pure functions haveno side effects, only an output • How is this represented in a typed language? • How does this help with reasoning? • How does this help with composition?
  • 26.
    Pure functions haveno side effects, only an output public RefundService( ICustomerRepository customerRepository, ILogger logger, IRefundRepository refundRepository) public Error[] ApproveRefund(Request r) static Error[] ApproveRefund( Request r, Func<CustomerId, Customer> getCustomer, Action<LogMessage[]> log, Action<Refund> save); static Either<Error[], Tuple<LogMessage[], Refund>> ApproveRefund( Request r, Customer c)
  • 27.
    Working effectively withcode • Cannot remain on top of every behavior and every iteration over that behavior • Effectiveness is qualified by the ability to reason well • Effectiveness is qualified by the ability to extend existing function via composition
  • 28.
    • The lessyou have to reason with the better • Effectively apply logical thinking • A common language needs to be learned What constitutes effective composition? • Action is deferred to the last responsible moment • Usage is driven by the context of the Consumer • Allows for multiple approaches to the same result What constitutes effective reasoning?
  • 29.

Editor's Notes

  • #5 Structure, but not everyone follows it Too many things that can go wrong Hard to apply logical thinking.
  • #6 Strong enforced structure High barrier to entry Once you get it, you only need to be on top of what you do
  • #9 Different approaches can be used to build towards the same end result.
  • #10 Only one right approach. Get it wrong, and it can be a costly mistake
  • #13 We will explore how they help with composition and improving our ability to reason.
  • #15 How do we get away with not making errors/exceptions explicit in the behavior contracts? Economies of scale Lack of vocabulary Adopted the practice that was already there
  • #26 FP gives us the vocabulary to understand how to defer side effects. The vocabulary that opens us up to the possibilities of composition with full context in hand. The more opportunities we are setup to explore, the more benefits we realize over time.