19
Functional-style control flow in F# Lincoln Atkinson 7/17/2013

Functional-style control flow in F#

Embed Size (px)

Citation preview

Page 1: Functional-style control flow in F#

Functional-style control flow in F#

Lincoln Atkinson7/17/2013

Page 2: Functional-style control flow in F#

Agenda

• Motivation/goals

• Idiomatic control-flow mechanisms in F#• Pattern matching/Active patterns• Loops via recursion• Higher-order functions for collection processing

• Examples

Page 3: Functional-style control flow in F#

Motivation

• Most of us learn imperative-style control flow first

• F# allows for a fair bit of imperative style, but this is not always the best approach

• “Translate your C# projects to F#” is advice often given to those looking to learn F#

• Not bad advice, but naïve translations might leave a bad impression• These patterns usually require mutable state, extra local variables,

nested scopes…

Page 4: Functional-style control flow in F#

FSM

Page 5: Functional-style control flow in F#

FSM

(F# Spaghetti Monster)

Page 6: Functional-style control flow in F#

Goals

• Help you have a better understanding of how to use common functional-style tools via F#, and how they compare to imperative-style tools

• Show you at least 1 thing about F# you hadn’t seen before, didn’t know before, or hadn’t thought about before

Non-Goals

• Teach you intro F#

• Convince you that functional-style is the only cool thing to do, or that imperative code is “bad”

Page 7: Functional-style control flow in F#

Pattern Matching

• Powerful mechanism to partition data into distinct cases

• Encompasses capabilities of “switch” + “if/else” + more, all in one language construct

• Can pattern match against:• Constant literal values• Data structure (for common F# types)• Types• Arbitrary tests• Combinations of above

• Matching and capturing are done in a single step

Page 8: Functional-style control flow in F#

(examples)

Page 9: Functional-style control flow in F#

Active Patterns

• Allow for custom partitioning of data, beyond native pattern matching capabilities

• Enhance readability by keeping partitioning implementation details separate from usage

• Perfect for when the logic to determine cases is complex enough that ideas become obscured by the code. “This looks complex, but it’s really just a few fundamental cases.”

Page 10: Functional-style control flow in F#

(examples)

Page 11: Functional-style control flow in F#

Recursive loops

• F# supports basic imperative loops• ‘for’ with constant iterators• ‘foreach’ over collections• ‘while’

• Limitations• Loop bodies must return ‘unit’, so mutation required in order to obtain

computed data• No ‘break’ statement (yet)

Page 12: Functional-style control flow in F#

Recursive loops - cont

• Advantages of recursive loops• More general approach – all loop types implemented essentially the

same via recursion• No mutation required• Arbitrary short-circuiting (i.e. ‘break) is simple to implement• Can return any data you want

• Disadvantages of recursive loops• Harder to grok at first• Slower

Page 13: Functional-style control flow in F#

Recursive loops - cont

• General approach• Identify the stopping condition(s) of the loop, and what data affect

it(them).• Identify the data that are processed or mutated in each iteration• Define a recursive function which accepts arguments capturing each of

the above• In recursive function body

• Check stopping conditions and return if needed• Otherwise compute data for next iteration and pass recursively

Page 14: Functional-style control flow in F#

(examples)

Page 15: Functional-style control flow in F#

Higher-order functions

• Any function that either• Accepts another function as an argument, or• Returns a function as output

• Particularly useful for transforming and processing collections• Chaining (pipelining) such functions together is a common strategy

Page 16: Functional-style control flow in F#

Higher-order functions - cont

• Key higher-order functions to know for collection processing• map – transform a collection to a new one by applying a function to each

element of the original

• fold – transform a collection into a single result by successively applying a function to each element, threading an accumulator through the calculation

• filter – transform a collection into a new one by applying a Boolean function to each element of the original and keeping only those which cause the function to return true

• iter – apply a given function to each element of a collection, returning unit.

Page 17: Functional-style control flow in F#

(examples)

Page 18: Functional-style control flow in F#

Takeaways

• Pattern matching can greatly streamline code, reduce spaghetti nested if-blocks, and simplify branching

• Active patterns can be used to enhance expressivity, readability, and modularity of complex partitioning logic

• Recursion is a powerful, general approach to looping

• Higher-order functions provide clean, pre-packaged engines for common actions

Page 19: Functional-style control flow in F#

Questions?