What patterns are available for adhering to the Open/Close principle when programming in F#?
For example, I'm sure Pattern Matching within F# is great in some scenarios.
But what guidance exists when you don't want to modify the Pattern Matching construct each time a new business case is made to operate on?
Example:
let getFullName nickName =
match nickName with
| "Bizmonger" | "Rico" -> "Scott Nimrod"
| _ -> "not found"
getFullName "Bizmonger";;
What happens when new cases are introduced?
Hence, I don't want to keep modifying this function.
I think the crux of the problem you are encountering is called the expression problem.
Functional code using algebraic data types sits on one side, where it is very to define an initial problem domain and to create and add new functions that operate on that domain. On the other hand, it is rather difficult, especially once you have developed a portfolio of functions to add types to the initial domain.
Object oriented code sits on the other side of the problem. Once you have defined your initial problem domain, it becomes extremely difficult to add new functionality because all of the types must be extended to implement it but it is relatively easy to extend the domain to new problems.
Consider
type Shape =
|Circle of float
|Square of float * float
module Shapes =
let area = function
|Circle r -> Math.PI * r ** 2.0
|Square (a, b) -> a*b
let perimeter = function
|Circle r -> 2.0 * Math.PI * r
|Square (a, b) -> 2.0 * (a + b)
Here, it's easy to add functions because I can just define behaviour for each type of shape but it's hard to add new shapes because I have to edit every function.
[<AbstractClass>]
type Shape() =
abstract member Area : double
abstract member Perimeter : double
type Circle(r) =
inherit Shape()
override this.Area = Math.PI * r **2.0
override this.Perimeter = 2.0 * Math.PI * r
type Square(a, b) =
inherit Shape()
override this.Area = a*b
override this.Perimeter = 2.0 * (a+b)
Using OO, it's easy to add new shapes but it's hard to new properties or methods to Shape because I have to edit every type.
I don't know if you've ever used the visitor pattern in object oriented programming but the need for that pattern arises from the difficulty of expressing structures that can be readily expressed by algebraic data types in functional programming.
One of the great things about F# as a general purpose programming language is that you can decide which method of expressing a particular problem you want to use on a problem by problem basis. That gives you a huge amount of flexibility to pick the optimal approach to your software design.
well as you just found out in this case it's easy to add new functions (you could say it's open in this regard) but hard to add new cases
But of course you can just use classes/objects/interfaces in F# just as you do in C# and so you got your well-known OOP patterns as well
btw: in any case String is not a good choice to implement business cases ... you won't get OOP O/C and you won't get FP union-type goodies this way
Related
I'm new to F# and in an attempt to design some types, I noticed how much OOP has affected my design decisions. I had a hard time searching for this particular problem and came up empty-handed.
I will describe what I am trying to do in C# since I am more familiar with the terminology. Let us say that I have an interface specifying some minimal required methods on a container-like class. Let's call it IContainer. Then I have two classes that implement this interface, ContainerA and ContainerB with different underlying implementations that are hidden from users. This is a very common OOP pattern.
I am trying to achieve the same thing in F# only with immutable types to stay in the functional world, i.e. how can I implement a type where its functionality is interchangeable, but the public functions that users will use remain the same:
type 'a MyType = ...
let func1 mytype = ...
let func2 mytype -> int = ...
The definition of MyType is not known and can later be changed, e.g. if a more efficient version of the functions are found (like a better implementation of a container type), but without much effort or requiring a redesign of the entire module. One way is to use pattern matching in the functions and a discriminated union, but that does not seem very scalable.
It is more typical in functional languages to use far simpler types than you would in an OO language.
Modelling shapes is the classic example.
Here is a typical OO approach:
type IShape =
abstract member Area : double
type Circle(r : float) =
member this.Area = System.Math.PI * r ** 2.0
interface IShape with
member this.Area = this.Area
type Rectangle(w : float, h : float) =
member this.Area = w * h
interface IShape with
member this.Area = this.Area
Notice that it's very easy to add new types using this approach, we could introduce a Triangle or a Hexagon class with relatively little effort. We simply create the type and implement the interface.
By contrast, if we wanted to add a new Perimeter member to our IShape, we would have to change every implementation which could be a lot of work.
Now let's look at how we might model shapes in a functional language:
type Shape =
|Circle of float
|Rectangle of float * float
[<CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module Shape =
let area = function
|Circle r -> System.Math.PI * r ** 2.0
|Rectangle (w, h) -> w*h
Now, hopefully you can see that it's much easier to add a perimeter function, we simply pattern match against each Shape case and the compiler can check whether we've implemented it exhaustively for every case.
By contrast, it's now far more difficult to add new Shapes because we have to go back and change every function which acts upon Shapes.
The upshot is, whatever form of modelling we choose to use, there are trade-offs. This problem is called The Expression Problem.
You can easily apply the second pattern to your Container problem:
type Container =
|ContainerA
|ContainerB
let containerFunction1 = function
|ContainerA -> ....
|ContainerB -> ....
Here you have a single type with two or more cases and the unique implementation of functionality for each case is contained in module functions, rather than the type itself.
I am currently doing the exercism.io F# track. For everyone who doesn't know it, it's solving small problems TDD style to learn or improve a programming language.
The last two tasks were about the usage of classes in F# (or types as they are called in F#). One of the tasks uses a BankAccount that has a balance and a status (open/closed) and can be altered by using functions. The usage was like this (Taken from the test code):
let test () =
let account = mkBankAccount () |> openAccount
Assert.That(getBalance account, Is.EqualTo(Some 0.0)
I wrote the code that makes the test pass using an immutable BankAccount class that can be interacted with using free functions:
type AccountStatus = Open | Closed
type BankAccount (balance, status) =
member acc.balance = balance
member acc.status = status
let mkBankAccount () =
BankAccount (0.0, Closed)
let getBalance (acc: BankAccount) =
match acc.status with
| Open -> Some(acc.balance)
| Closed -> None
let updateBalance balance (acc: BankAccount) =
match acc.status with
| Open -> BankAccount (acc.balance + balance, Open)
| Closed -> failwith "Account is closed!"
let openAccount (acc: BankAccount) =
BankAccount (acc.balance, Open)
let closeAccount (acc: BankAccount) =
BankAccount (acc.balance, Closed)
Having done a lot of OO before starting to learn F# this one got me wondering. How do more experienced F# developers use classes? To make answering this question more simple, here are my main concerns about classes/types in F#:
Is the use of classes in a typical OO fashion discouraged in F#?
Are immutable classes preferred? ( I found them to be confusing in the above example)
What is the preferred way to access/alter class data in F#? (Class member functions and get/set or free functions which allow piping? What about static members to allow piping and providing the functions with a fitting namespace?)
I'm sorry if the question is vague. I don't want to develop bad coding habits in my functional code and i need a starting point on what good practices are.
Is the use of classes in a typical OO fashion discouraged in F#?
It's not discouraged, but it's not the first place most experienced F# developers would go. Most F# developers will avoid subclassing and OO paradigms, and instead go with records or discriminated unions, and functions to operate on them.
Are immutable classes preferred?
Immutability should be preferred when possible. That being said, immutable classes can often be represented other ways (see below).
What is the preferred way to access/alter class data in F#? (Class member functions and get/set or free functions which allow piping? What about static members to allow piping and providing the functions with a fitting namespace?)
This is typically done via functions that allow piping, though access can be done directly, as well.
For your above code, it would be more common to use a record instead of a class, and then put the functions which work on the record into a module. An "immutable class" like yours can be written as a record more succinctly:
type BankAccount = { balance : float ; status : AccountStatus }
Once you've done this, working with it becomes easier, as you can use with to return modified versions:
let openAccount (acc: BankAccount) =
{ acc with status = Open }
Note that it'd be common to put these functions into a module:
module Account =
let open acc =
{ acc with status = Open }
let close acc =
{ acc with status = Closed }
Question: Is the use of classes in a typical OO fashion discouraged in F#?
It is not against F#'s nature. I think that there are cases when this is justified.
However, usage of classes should be limited if developers want to take full advantage of F# strengths (e.g. type interference, ability to use functional patterns such as partial application, brevity) and are not constrained by legacy systems and libraries.
F# for fun and profit gives a quick summary of pros and cons of using classes.
Ouestion: Are immutable classes preferred? ( I found them to be confusing in the above example)
Sometimes yes, sometimes not. I think that immutability of classes gives you lots of advantages (it's easier to reason about type's invariants etc.) but sometimes immutable class can be a bit cumbersome to use.
I think that this question is a bit too broad - it's somewhat similar to a question if fluent interfaces are preferred in object-oriented design - the short answer is: it depends.
What is the preferred way to access/alter class data in F#? (Class member functions and get/set or free functions which allow piping? What about static members to allow piping and providing the functions with a fitting namespace?)
Piping is a canonical construct in F#, so I would go for static member. If your library is consumed in some other languages, you should include getter and setter inside class as well.
EDIT:
FSharp.org has a list of quite specific design guidelines which include:
✔ Do use classes to encapsulate mutable state, according to standard
OO methodology.
✔ Do use discriminated unions as an alternative to class hierarchies
for creating tree-structured data.
There are a few ways of looking at this question.
This could mean several things. For POCO's, immutable F# records are preferred. Then the operations on them return new records with the requisite fields changed.
type BankAccount { status: AccountStatus; balance: int }
let close acct = { acct with status = Closed } // returns a *new* acct record
So that means you've got to get past the idea of an account "object" that represents a single "thing". It's just data that you operate on to create different data, and eventually (likely) store into a database somewhere.
So rather than the OO paradigm acct.Close(); acct.PersistChanges(), you'd have let acct' = close acct; db.UpdateRecord(acct').
For "services" in a "service-oriented architecture (SOA)" however, interfaces and classes are perfectly natural in F#. For instance, if you want a Twitter API, you'd probably create a class that wraps all the HTTP calls just like you would in C#. I've seen some references to the "SOLID" ideology in F# that eschews SOA completely but I've never figured out how to make that work in practice.
Personally, I like an FP-OO-FP sandwich with Suave's FP combinators on top, a SOA using Autofac in the middle, and FP records on the bottom. I find that works well and is scalable.
FWIW also you may want do make your BankAccount a discriminated union, if Closed can't have a balance. Try this out in your code samples. One of the nice things in F# is it makes illogical states unrepresentable.
type BankAccount = Open of balance: int | Closed
What's the advantage of having a type represent a function?
For example, I have observed the following snippet:
type Soldier = Soldier of PieceProperties
type King = King of PieceProperties
type Crown = Soldier -> King
Is it just to support Partial Application when additional args have yet to be satisfied?
As Fyodor Soikin says in the comments
Same reason you give names to everything else - values, functions,
modules, etc.
In other words, think about programming in assembly which typically does not use types, (yes I am aware of typed assembly) and all of the problems that one can have and then how many of those problems are solved or reduced by adding types.
So before you programmed with a language that supported functions but that used static typing, you typed everything. Now that you are using F# which has static typing and functions, just extend what you have been using typing for but now add the ability to type the functions.
To quote Benjamin C. Pierce from "Types and Programming Languages"
A type system is a tractable syntactic method for proving the absence
of certain program behaviors by classifying phrases according to the
kinds of values they compute.
As noted in "Types and Programming Languages" Section 1.2
What Type Systems Are Good For
Detecting Errors
Abstraction
Documentation
Language Safety
Efficiency
TL;DR
One of the places that I find named type function definitions invaluable is when I am building parser combinators. During the construction of the functions I fully type the functions so that I know what the types are as opposed to what type inferencing will infer they are which might be different than what I want. Since the function types typically have several parameters it is easier to just give the function type a name, and then use that name everywhere it is needed. This also saves time because the function definition is consistent and avoid having to debug an improperly declared function definition; yes I have made mistakes by doing each function type by hand and learned my lesson. Once all of the functions work, I then remove the type definitions from the functions, but leave the type definition as comments so that it makes the code easier to understand.
A side benefit of using the named type definitions is that when creating test cases, the typing rules in the named function will ensure that the data used for the test is of the correct type. This also makes understanding the data for the test much easier to understand when you come back to it after many months.
Another advantage is that using function names makes the code easier to understand because when a person new to the code looks at if for the first time they can spot the consistency of the names. Also if the names are meaningful then it makes understanding the code much easier.
You have to remember that functions are also values in F#. And you can do pretty much the same stuff with them as other types. For example you can have a function that returns other functions. Or you can have a list that stores functions. In these cases it will help if you are explicit about the function signature. The function type definition will help you to constrain on the parameters and return types. Also, you might have a complicated type signature, a type definition will make it more readable. This maybe a bit contrived but you can do fun(ky) stuff like this:
type FuncX = int -> int
type FuncZ = float -> float -> float
let addxy (x:int) :FuncX = (+) x
let subxy :FuncX = (-) x
let addz (x:float) :FuncZ =
fun (x:float) -> (fun y -> x + y)
let listofFunc = [addxy 10;addxy 20; subxy 10]
If you check the type of listofFunc you will see it's FuncX list. Also the :FuncX refers to the return type of the function. But we could you use it as an input type as well:
let compFunc (x:FuncX) (z:FuncX) =
[(x 10);(z 10)]
compFunc (addxy 10) (addxy 20)
I'm started to learn F#, and I noticed that one of the major differences in syntax from C# is that type inference is used much more than in C#. This is usually presented as one of the benefits of F#. Why is type inference presented as benefit?
Imagine, you have a class hierarchy and code that uses different classes from it. Strong typing allows you quickly detect which classes are used in any method.
With type inference it will not be so obvious and you have to use hints to understand, which class is used. Are there any techniques that exist to make F# code more readable with type inference?
This question assumes that you are using object-oriented programming (e.g. complex class hierarchies) in F#. While you can certainly do that, using OO concepts is mainly useful for interoperability or for wrapping some F# functionality in a .NET library.
Understanding code. Type inference becomes much more useful when you write code in the functional style. It makes code shorter, but also helps you understand what is going on. For example, if you write map function over list (the Select method in LINQ):
let map f list =
seq { for el in list -> f el }
The type inference tells you that the function type is:
val map : f:('a -> 'b) -> list:seq<'a> -> seq<'b>
This matches our expectations about what we wanted to write - the argument f is a function turning values of type 'a into values of type 'b and the map function takes a list of 'a values and produces a list of 'b values. So you can use the type inference to easily check that your code does what you would expect.
Generalization. Automatic generalization (mentioned in the comments) means that the above code is automatically as reusable as possible. In C#, you might write:
IEnumerable<int> Select(IEnumerable<int> list, Func<int, int> f) {
foreach(int el in list)
yield return f(el);
}
This method is not generic - it is Select that works only on collections of int values. But there is no reason why it should be restricted to int - the same code would work for any types. The type inference mechanism helps you discover such generalizations.
More checking. Finally, thanks to the inference, the F# language can more easily check more things than you could if you had to write all types explicitly. This applies to many aspects of the language, but it is best demonstrated using units of measure:
let l = 1000.0<meter>
let s = 60.0<second>
let speed = l/s
The F# compiler infers that speed has a type float<meter/second> - it understands how units of measure work and infers the type including unit information. This feature is really useful, but it would be hard to use if you had to write all units by hand (because the types get long). In general, you can use more precise types, because you do not have to (always) type them.
Earlier I requested some feedback on my first F# project. Before closing the question because the scope was too large, someone was kind enough to look it over and leave some feedback.
One of the things they mentioned was pointing out that I had a number of regular functions that could be converted to be methods on my datatypes. Dutifully I went through changing things like
let getDecisions hand =
let (/=/) card1 card2 = matchValue card1 = matchValue card2
let canSplit() =
let isPair() =
match hand.Cards with
| card1 :: card2 :: [] when card1 /=/ card2 -> true
| _ -> false
not (hasState Splitting hand) && isPair()
let decisions = [Hit; Stand]
let split = if canSplit() then [Split] else []
let doubleDown = if hasState Initial hand then [DoubleDown] else []
decisions # split # doubleDown
to this:
type Hand
// ...stuff...
member hand.GetDecisions =
let (/=/) (c1 : Card) (c2 : Card) = c1.MatchValue = c2.MatchValue
let canSplit() =
let isPair() =
match hand.Cards with
| card1 :: card2 :: [] when card1 /=/ card2 -> true
| _ -> false
not (hand.HasState Splitting) && isPair()
let decisions = [Hit; Stand]
let split = if canSplit() then [Split] else []
let doubleDown = if hand.HasState Initial then [DoubleDown] else []
decisions # split # doubleDown
Now, I don't doubt I'm an idiot, but other than (I'm guessing) making C# interop easier, what did that gain me? Specifically, I found a couple disadvantages, not counting the extra work of conversion (which I won't count, since I could have done it this way in the first place, I suppose, although that would have made using F# Interactive more of a pain). For one thing, I'm now no longer able to work with function "pipelining" easily. I had to go and change some |> chained |> calls to (some |> chained).Calls etc. Also, it seemed to make my type system dumber--whereas with my original version, my program needed no type annotations, after converting largely to member methods, I got a bunch of errors about lookups being indeterminate at that point, and I had to go and add type annotations (an example of this is in the (/=/) above).
I hope I haven't come off too dubious, as I appreciate the advice I received, and writing idiomatic code is important to me. I'm just curious why the idiom is the way it is :)
Thanks!
One practice I used in my F# programming is use the code in both places.
The actual implementation is natural to be put in a module:
module Hand =
let getDecisions hand =
let (/=/) card1 card2 = matchValue card1 = matchValue card2
...
and give a 'link' in the member function/property:
type Hand
member this.GetDecisions = Hand.getDecisions this
This practice is also generally used in other F# libraries, e.g. the matrix and vector implementation matrix.fs in powerpack.
In practice, not every function should be put in both places. The final decision should be based on the domain knowledge.
Regarding the top-level, the practice is to put functions in to modules, and make some of them in the top-level if necessary. E.g. in F# PowerPack, Matrix<'T> is in the namespace Microsoft.FSharp.Math. It is convenient to make a shortcut for the matrix constructor in the toplevel so that the user can construct a matrix directly without opening the namespace:
[<AutoOpen>]
module MatrixTopLevelOperators =
let matrix ll = Microsoft.FSharp.Math.Matrix.ofSeq ll
An advantage of members is Intellisense and other tooling that makes members discoverable. When a user wants to explore an object foo, they can type foo. and get a list of the methods on the type. Members also 'scale' easier, in the sense that you don't end up with dozens of names floating around at the top level; as program size grows, you need more names to only be available when qualified (someObj.Method or SomeNamespace.Type or SomeModule.func, rather than just Method/Type/func 'floating free').
As you've seen, there are disadvantages as well; type inference is especially notable (you need to know the type of x a priori to call x.Something); in the case of types and functionality that is used very commonly, it may be useful to provide both members and a module of functions, to have the benefits of both (this is e.g. what happens for common data types in FSharp.Core).
These are typical trade-offs of "scripting convenience" versus "software engineering scale". Personally I always lean towards the latter.
This is a tricky question and both of the approaches have advantages and disadvantages. In general, I tend to use members when writing more object-oriented/C# style code and global functions when writing more functional code. However, I'm not sure I can clearly state what the difference is.
I would prefer using global functions when writing:
Functional data types such as trees/lists and other generally useable data structures that keep some larger amount of data in your program. If your type provides some operations that are expressed as higher order functions (e.g. List.map) then it is probably this kind of data type.
Not type-related functionality - there are situations when some operations don't strictly belong to one particular type. For example, when you have two representations of some data structure and you're implementing transformation between the two (e.g. typed AST and untyped AST in a compiler). In that case, functions are better choice.
On the other hand, I would use members when writing:
Simple types such as Card that can have properties (like value and color) and relatively simple (or no) methods performing some computations.
Object-oriented - when you need to use object-oriented concepts, such as interfaces, then you'll need to write the functionality as members, so it may be useful to consider (in advance) whether this will be the case for your types.
I would also mention that it is perfectly fine to use members for some simple types in your application (e.g. Card) and implement the rest of the application using top-level functions. In fact, I think that this would probably be the best approach in your situation.
Notably, it is also possible to create a type that has members together with a module that provides the same functionality as functions. This allows the user of the library to choose the style he/she prefers and this is completely valid approach (however, it probably makes sense for stand-alone libraries).
As a side-note, chaining of calls can be achieved using both members and functions:
// Using LINQ-like extension methods
list.Where(fun a -> a%3 = 0).Select(fun a -> a * a)
// Using F# list-processing functions
list |> List.filter (fun a -> a%3 = 0) |> List.map (fun a -> a * a)
I generally avoid classes primarily because of the way members cripple type inferencing. If you do this, it is sometimes handy to make the module name the same as the type name - the compiler directive below comes in handy.
type Hand
// ...stuff...
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Hand =
let GetDecisions hand = //...