| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

Thinking Functionally

Page history last edited by Matthew Podwysocki 15 years, 5 months ago

The intent of this session was to discuss the tenets of functional programming and how to take advantage of this paradigm.  The discussion led to moving from an imperative mindset to a more declarative style using functional programming techniques

 

The tenets of functional programming are:

  • Functions as first class values
  • Immutable by default
  • Functional purity

 

How do we move towards a functional style of programming?

  • Avoid mutable state
  • Functional composition over inheritance
  • Recursion over mutable state
  • Lazy evaluation over eager

 

Talked about the evolution of C# and how over time, has gathered functional programming aspects as it is not a true functional language.  With the advent of C# 3.0, we now have LINQ, Lambda Expressions, Extension methods, Better type inference, among others.  How it falls down is the lack of treating void as a type, limited lazy evaluation, no recursion optimization and no simple data types such as Tuples and Records.

 

Introduced F#, which is based on OCaml and a first class language in the .NET framework.  This language is first and foremost, a functional language, with imperative and object oriented constructs as well.  This language is well suited for data mining, scientific analysis, internal DSLs, as well as others.  This language has many features that we need as functional programmers to get our jobs done.

 

How does it affect our code?  Should be separated into three areas, in the large, in the medium and in the small.  In the large revolves around overall architecture of the system.  A lazy evaluated by default decision has the most impact here.  In the medium (at the class and interface level), it is affected by replacing OOP design patterns with functional composition and reuse.  In the small, we talk about small, reusable functions that can be passed around frequently as well as immutable by default data.

 

How do we get there?  Move from mutable to immutable.  Move from eager evaluation to lazy.  Move from interface driven to function driven.

 

Next was covered basic data structures in functional programming, such as tuples, records, lists, and discriminated unions. 

 

High order functions are functions that either take a function as an argument or return a function.  Such examples shown were Map (Select), FIlter (Where), Fold (Sum/Aggregate) and iterator.

 

Lazy evaluation is helpful when designing APIs.  We want to delay our work until the last possible second so that we get the best scalability and performance, instead of large blocking calls.  Such examples are reading from the disk, large calculations, and reading from a large data set.

 

Recursion is a technique that is used in functional programming in order to avoid mutable state.  Instead, we return a value which accumulates the value to be computed again.  Linear recursion is the most simple recursion where the function is called until the terminate condition.  Tail call recursion is where the last call is the call to the function.  This is important due to avoiding stack overflow issues for those languages optimized for the tail call.  Other techniques that can be used is by using Continuation Passing Style.

 

Pattern Matching is one of the most important aspects of functional programming in that it allows us to tease apart data in interesting ways.  We can pattern match against guarded conditions, records, tuples, .NET types, literal values and so on.  Active patterns is a way to do advanced pattern matching to create new patterns.  Examples of this were regular expressions and filtering via file information.

 

Side topics such as memoization and list generation were discussed as well.  Memoziation is the ability to stored a computed result for later retrieval instead of recalculating each and every time.  List generation is the ability to generate sequences based upon any number of sources, whether it be literal integer values, files, web requests and so on.

 

Monads were a nice mind bending part of the discussion.  Monads are a way to supercharge values, where each type has a corresponding monadic type.  This allows the value to be interpreted by the underlying monadic structure.  Examples of monads discussed were the identity, maybe, list, error, async and software transactional memory.

 

One of the reasons that functional programming is becoming important is the message around concurrency.  By having an immutable by default and side effect free architecture, we can better look for ways to optimize for parallelization.  We took simple examples from serial code to parallel, using the Parallel Extensions for .NET and F# Async Computation Expressions.

 

But with any of this, there comes a price.  When mixing side effects with lazy evaluation, there are penalties.  One must be conscious of possible exceptions when dealing with closures, scope of exception handling and scope of resources.  Several examples showed where code can easily break in simple yet interesting ways.  So, how do we fix it?  Get rid of the side effects.  Maybe we should start thinking about a language that makes its side effects more explicit?  Maybe taking some cues from Haskell?  And what about Spec#?

Comments (0)

You don't have permission to comment on this page.