It has been awhile since I posted something on F#, but I have been busy reading part 2 of Real-World Functional Programming. This so far has been one of the harder chapters. Not because I couldn’t understand what is going on in the examples it was more of a mind shift I didn’t quite yet grasp fully. Most of the examples were very easy to follow however the sheer functional aspect of the examples made me realize I am not thinking functionally quite yet, hopefully I will be soon. As usual here are some random notes and blurbs that stood out for me while reading this section.
Chapter 5, Using functional values locally
- In F#, if you need to recognize that a type either contains a value or does not, you can use the ‘option’ type. When working with the option type you never have the danger of dealing with a NullReferenceException since by definition an option type always is something either a value or missing a value.
- Values are typically used to solve problems in functional programming
- Data is usually something large and used by multiple portions of your program
- A type specifies an entire domain of values and a value is always an element within a domain specified by its type.
- Returning multiple values from a function is the primary motivation behind using tuples
- You can use out parameters in F# as you do in C#, however tuples is generally preferred, because of that .net method that utilize out parameters expose a method that returns tuples
let (success, parsed) = Int32.TryParse("42")
- When using tuples always consider the complexity of the tuple you are creating
- A tuple can contain more than two elements however if you begin to use 3+ elements in your tuple consider creating a record type for greater readability and maintainability
- Discriminated unions provides support for values that can be a number of named cases
- When doing pattern matching on Discriminated unions you are required to write all possible matches since the value passed into the function is unknown.
- You can declare a variable with let bindings twice, this practice is known as hiding a value
- The pattern matching construct in F# is similar to the switch statement in C#
- In F# null is rarely used, most times when you encounter null it means you are working with other aspects of the .net framework, in F# the use of the option type is preferred
- When using the option type in F# you are forced to write the match when a value is undefined
- The option type is similar to Nullable<T> as in C#
- F# type inference allows for the creation of function that use generics automatically
- F# filter is to C# where linq extension method, they both take a predicate function
- In C# you create lambda expression and in F# it is a lambda function
- A function is called a pure function if it behaves in a mathematical way, a function that returns true for even numbers for example
- The F# lambda expression starts with the fun keyword, you specify multiple arguments with spaces, you do not have to specify the type explicitly.
- In C# you can not use the var keyword when creating lambda expressions since the compiler needs to know if it is a Func or an Expression
Chapter 6, Processing values using higher-order functions
- Higher order functions are very important to functional programming
- You can create custom operators in F# using the normal let binding as you do with functions. You can use any F# mathematical character or logical operators and other special characters ($%.?&^~!), you can also use * however care needs to be taken since that is also used for a multi-line comment
- When creating custom operators you can use infix (takes two parameters) notation when using the operator, “A” +> “B” +> “C”
- You can also create prefix operators (takes one parameter) you need to start the operator with either ~ or !
- Use of the |> operator allows you to write the argument on the left hand side of the call, this is very similar to the idea of calling C# extension methods where the variable is on the left as well
- If you wrap an operator inside of () this allows you to call the operator as you would a function. 2 + 2 using () would look like (+) 2 2
- One of the most important types in F# is the option type
- Option.map transforms a given option type into another option type specified by the mapping function supplied
- Understanding a behavior of a function using only the type is a very important skill of a functional programmer
- option.bind invokes a function that takes an option type that also returns an option type
- You can compose functions together by using the » operator
let function1 x = x + 1 let function2 x = x * 2 let h = function1 >> function2 let result5 = h 100
- In F# if you want to do SelectMany the corresponding function is List.collect
Chapter 7, Designing data-centric programs
- When desiging a functional program, first think about the data that the program works with.
- When a record type in F# is simly a labeled tuple
- When declaring a record type you have to specify the types of the fields and their names
- When creating a record type you do not need to specify the type of the record since the F# compiler will infer the type based upon the fields
- A record is a functional data structure which also means it is immutable as well
- F# allows you to create new record types easily by using the with keyword, this allows you to create the new record type and only specify the fields the are changing, F# will copy the rest automatically
- The hole in the middle pattern allows you create a generic function that takes a function which gets executed in the middle. The hole is the function you supply to the other function that has pre and post logic.
- The .net IEnumerable<T> is abbreviated as seq<’a> in F#.
- Seq.head is the same Linq extension method .First()
- Code example from chapter 7
Chapter 8, Designing behavior-centric programs
- One frequent requirement for behavior-centric programs is the ability to load new behaviors dynamically from a library
- Since functions are treated as values you can easily create a list of functions to run on some type
- Storing functions in a list easily allow you to add and remove these behaviors
- Point free programming style allows you to define functions that do not directly specify the argument names, I do not exactly understand this yet but the wikipedia article sort of explains it
- Point-free style should be used only when the intent is very clear since removing the arguments from the definition could make the code harder to read and maintain
- The strategy pattern is useful whent he application needs to choose several algorithms at run time
- The command pattern describes a way to represent actions in an application, when using the command patter you most likely will need to work with mutable state. Since functional programming relies on immutable state when using the command pattern you should document clearly where the mutable portions are located.
- Closures allow you to limit the scope of mutable state when developing functional programs
- A function isn’t just code it also is a closure
- You can create mutable values by using the ref keyword
- C# variables are mutable by default so when using closures be very careful, an example would be a for loop creating a closure over a variable which ends up being the last value in the last iteration for all closures
- If you use a let binding followed by an and this allows both bindings to see each other
Next up in the book is advanced F# topics, I have a feeling tackling functional programming in one month might end up being a pipe dream. Learning the syntax is easy altering your mindset is hard.