Language-ext: Samples

Created on 21 Apr 2017  路  9Comments  路  Source: louthy/language-ext

Can i find some Samples/Tutorials somewhere?
I'm a typical c# programmer who would like to use some more functional principles to clean up my code.
I already checked out the Pluralsight course on functional programming in c# and trough some googling came to this lib.

Now a sort of "Getting started with language-ext" would be nice. As now i find it pretty hard to just take a small program/piece of code and just refactor it. Maybe some before and after examples would be very helpful for people tying to get into using language-ext.

examples / documentation

Most helpful comment

@Skoucail You may want to start with a book, I can recommend Functional Programming in C#; I've been a technical proofer on that book and would recommend it highly. There's a lot of cross-over to what I have built here.

The key thing with functional programming in C# is being strict with yourself, as it's easy to fall into the OO habits. Primarily it's about:

  • Expression oriented programming - making everything you do an expression, rather than a sequence of statements (you can always tell if you've got an expression because the first thing in a method is return, or you're using the expression-bodied methods that don't have braces and start with =>)
  • Get the OO notion of functionality and data being attached out of your mind. Create immutable types (see my StackOverflow answer here for info); they act like 'record types' or 'data types' in other functional languages. And then create static classes that work with the data-types.
  • Write _pure_ methods. Pure methods are _referentially transparent_. They don't refer to any global state, and work solely with the values provided to the method. Combined with immutable types it allows you to consider the result of a pure method to be exactly like a value, because every time you provide the same inputs you get the same output.
  • Try to avoid throwing exceptions. Exceptions are like a goto, and do not fit the expression oriented mentality. Instead return Option<A> to indicate success or failure, or Either<L, R> where L is the error value and R is the success value.
  • For the occasions where you're using code that might throw an exception, use Try<A>. It will catch the exception and allow you to match or map on the result.
  • Learn what functors, applicatives, and monads are. They're scary terms, but so is 'polymorphism' when you first start OO. Functors are types with a Map function (also known as Select in LINQ). They allow you to 'stay in context' with some of the core functional types like Option<A>, Either<L, R>, Try<A>, etc.

For example, let's say you have a function that can return an optional result (so instead of throwing an error, you return None):
```c#
Option GetValue(bool hasValue) =>
hasValue
? Some("Skoucail")
: None;

`Option<A>` doesn't allow you to get at the inner value of the type without matching:
```c#
    string value = GetValue(true).Match(
        Some: name => $"Hello, {name}",
        None: () => "Goodbye"
    );

Now doing that all the time you want to work with optional values is pretty annoying. And this is where functors and monads come in. So with functors you can stay in the optional context by mapping:
```c#
Option value = GetValue(true).Map(name => $"Hello, {name}");

So instead of jumping back out to the `string`, you stay in the `Option<string>` context.  You can maintain this for as long as necessary by doing subsequent calls to `Map`.  The key thing is that the lambda inside the `Map` won't be invoked if the `Option` is in a `None` state.  So `Option` is a replacement for `if` statements, and reduces the cyclomatic complexity of your code.

Monads are classically a difficult subject for people coming at OO.  But don't worry too much about their name, just know that most of the types in language-ext are monads.  Monads have two requirements: 

1. To have a constructor function
2. To have a bind function

The constructor function just makes a new monad of whatever type.  The `Some(x)` and `None` functions above construct the `Option` monad.  Usually in functional programming it's called `Return` which adds to the confusion, but don't worry about that for now.

The `Bind` function is almost exactly the same as the `Map` function.  Except where `Map` takes a `Func<A, B>` to map an `A` to a `B`;  `Bind` takes a `Func<A, M<B>>`, where `M` is the monad type.  So for `Option` its `Func<A, Option<B>>`.  So in other words you're mapping an `A` to a monad of `B`.  This allows you to chain multiple functions together that all return `Option` for example:
```c#
    Option<string> GetFirstName() => 
        Some("Joe");

    Option<string> MakeFullName(string firstName) => 
        Some($"{firstName} Bloggs");

    Option<string> name = GetFirstName().Bind(MakeFullName);

So of course if either GetFirstName() or MakeFullName() returned None then name would be None.

Again that starts to get a bit unwieldy, but C# has syntax for monadic types: LINQ:
```c#
Option GetFirstName() =>
Some("Joe");

Option<string> GetLastName() => 
    Some("Bloggs");

var name = from first in GetFirstName()
           from last in GetLastName()
           select $"{first} {last}";
Whenever you see a `from x in y`, you should always think that `y` is a monad, and that `x` is the value _inside_ the monad.  `IEnumerable` is a monad as well.

Why is this better?  Well, it avoids you writing the same shit over and over:
```c#
    var name = "";
    var firstName = GetFirstName();
    if(firstName != null)
    {
        var lastName = GetLastName();
        if(lastName != null)
        {
            name = $"{first} {last}";
        }
    }

So Option removes the need to write if statements, so does Either but gives you an _alternative_ value for when it fails (else). Try avoids the need to write try/catch statements. TryOption is a combination of returning an optional result and catches exceptions, etc.

The collection types in lang-ext are all immutable types, which are much more robust than mutable ones, and are easier to use when writing pure functions. Lst<A> is a List<A> replacement, Set<A> and HashSet<A> replace the BCL HashSet<A>, Map<A, B> andHashMap<A, B> replace SortedDictionary<A, B> and Dictionary<A, B>; Seq<A> is a better IEnumerable which doesn't suffer from multiple evaluation traps, etc.

__Summing up__

The best thing to do is start working with expressions more, start using Option more, get friendly with the ternary operator for conditional expressions (a ? "true" : "false" instead of if(a) ...); it will take time to all sink in, and may seem bat shit crazy at times, but take it from me as a reformed OO guy, that it will be worth it, and you'll wonder why you ever wrote OO in the first place. You'll have several 'aha' moments, but it can take a few years to really master it, although there's tons more resource around now compared to when I started it. Most of the functionality in this library are here to help you to compose expressions, that is the absolute key to all of this: to make your code act like a mathematical formula - which gives you super powers as a programmer when it comes to reasoning about it (and from stopping it code-rotting over time).

You may want to have a look at the unit tests for examples, although they're not particularly presented in a style that's useful for tutorials.

All 9 comments

@Skoucail You may want to start with a book, I can recommend Functional Programming in C#; I've been a technical proofer on that book and would recommend it highly. There's a lot of cross-over to what I have built here.

The key thing with functional programming in C# is being strict with yourself, as it's easy to fall into the OO habits. Primarily it's about:

  • Expression oriented programming - making everything you do an expression, rather than a sequence of statements (you can always tell if you've got an expression because the first thing in a method is return, or you're using the expression-bodied methods that don't have braces and start with =>)
  • Get the OO notion of functionality and data being attached out of your mind. Create immutable types (see my StackOverflow answer here for info); they act like 'record types' or 'data types' in other functional languages. And then create static classes that work with the data-types.
  • Write _pure_ methods. Pure methods are _referentially transparent_. They don't refer to any global state, and work solely with the values provided to the method. Combined with immutable types it allows you to consider the result of a pure method to be exactly like a value, because every time you provide the same inputs you get the same output.
  • Try to avoid throwing exceptions. Exceptions are like a goto, and do not fit the expression oriented mentality. Instead return Option<A> to indicate success or failure, or Either<L, R> where L is the error value and R is the success value.
  • For the occasions where you're using code that might throw an exception, use Try<A>. It will catch the exception and allow you to match or map on the result.
  • Learn what functors, applicatives, and monads are. They're scary terms, but so is 'polymorphism' when you first start OO. Functors are types with a Map function (also known as Select in LINQ). They allow you to 'stay in context' with some of the core functional types like Option<A>, Either<L, R>, Try<A>, etc.

For example, let's say you have a function that can return an optional result (so instead of throwing an error, you return None):
```c#
Option GetValue(bool hasValue) =>
hasValue
? Some("Skoucail")
: None;

`Option<A>` doesn't allow you to get at the inner value of the type without matching:
```c#
    string value = GetValue(true).Match(
        Some: name => $"Hello, {name}",
        None: () => "Goodbye"
    );

Now doing that all the time you want to work with optional values is pretty annoying. And this is where functors and monads come in. So with functors you can stay in the optional context by mapping:
```c#
Option value = GetValue(true).Map(name => $"Hello, {name}");

So instead of jumping back out to the `string`, you stay in the `Option<string>` context.  You can maintain this for as long as necessary by doing subsequent calls to `Map`.  The key thing is that the lambda inside the `Map` won't be invoked if the `Option` is in a `None` state.  So `Option` is a replacement for `if` statements, and reduces the cyclomatic complexity of your code.

Monads are classically a difficult subject for people coming at OO.  But don't worry too much about their name, just know that most of the types in language-ext are monads.  Monads have two requirements: 

1. To have a constructor function
2. To have a bind function

The constructor function just makes a new monad of whatever type.  The `Some(x)` and `None` functions above construct the `Option` monad.  Usually in functional programming it's called `Return` which adds to the confusion, but don't worry about that for now.

The `Bind` function is almost exactly the same as the `Map` function.  Except where `Map` takes a `Func<A, B>` to map an `A` to a `B`;  `Bind` takes a `Func<A, M<B>>`, where `M` is the monad type.  So for `Option` its `Func<A, Option<B>>`.  So in other words you're mapping an `A` to a monad of `B`.  This allows you to chain multiple functions together that all return `Option` for example:
```c#
    Option<string> GetFirstName() => 
        Some("Joe");

    Option<string> MakeFullName(string firstName) => 
        Some($"{firstName} Bloggs");

    Option<string> name = GetFirstName().Bind(MakeFullName);

So of course if either GetFirstName() or MakeFullName() returned None then name would be None.

Again that starts to get a bit unwieldy, but C# has syntax for monadic types: LINQ:
```c#
Option GetFirstName() =>
Some("Joe");

Option<string> GetLastName() => 
    Some("Bloggs");

var name = from first in GetFirstName()
           from last in GetLastName()
           select $"{first} {last}";
Whenever you see a `from x in y`, you should always think that `y` is a monad, and that `x` is the value _inside_ the monad.  `IEnumerable` is a monad as well.

Why is this better?  Well, it avoids you writing the same shit over and over:
```c#
    var name = "";
    var firstName = GetFirstName();
    if(firstName != null)
    {
        var lastName = GetLastName();
        if(lastName != null)
        {
            name = $"{first} {last}";
        }
    }

So Option removes the need to write if statements, so does Either but gives you an _alternative_ value for when it fails (else). Try avoids the need to write try/catch statements. TryOption is a combination of returning an optional result and catches exceptions, etc.

The collection types in lang-ext are all immutable types, which are much more robust than mutable ones, and are easier to use when writing pure functions. Lst<A> is a List<A> replacement, Set<A> and HashSet<A> replace the BCL HashSet<A>, Map<A, B> andHashMap<A, B> replace SortedDictionary<A, B> and Dictionary<A, B>; Seq<A> is a better IEnumerable which doesn't suffer from multiple evaluation traps, etc.

__Summing up__

The best thing to do is start working with expressions more, start using Option more, get friendly with the ternary operator for conditional expressions (a ? "true" : "false" instead of if(a) ...); it will take time to all sink in, and may seem bat shit crazy at times, but take it from me as a reformed OO guy, that it will be worth it, and you'll wonder why you ever wrote OO in the first place. You'll have several 'aha' moments, but it can take a few years to really master it, although there's tons more resource around now compared to when I started it. Most of the functionality in this library are here to help you to compose expressions, that is the absolute key to all of this: to make your code act like a mathematical formula - which gives you super powers as a programmer when it comes to reasoning about it (and from stopping it code-rotting over time).

You may want to have a look at the unit tests for examples, although they're not particularly presented in a style that's useful for tutorials.

I would like to second the functional c# programming book suggestion. I started reading it without any functional experience and felt very comfortable afterwards. The extensions the book uses is almost identical to this project.

Will take a look at the book for sure.
And thx for the short summary.
Maybe in a few years i will be able to call myself a reformed OO guy too!

@Skoucail Good luck! I guess one final point, and I know it's kinda obvious, but it's all about functions. Functions are the unit of currency, whether they're pure static functions or first class functions (Func<...>) that you pass around. Dependency Injection for example is terrible in OO land, yet in functional land it's just done with Func and is the core idea behind the paradigm. Even the high-abstraction stuff like monads, applicatives, and functors are all just about function composition.

@jeremysmith1 That's great to hear :)

Again, praise to the book by Enrico Buonanno, which really is an eye-opener and by far the best book for ambitious C# developers trying to adopt functional principles. @louthy Kudos to you and all people working as proofers and editors on Enricos book - the released book shows substantial improvements in quality over the MEAP versions (which already were worth the money).

Regarding monads, there's this great article by Eric Lippert here, which really helped me to wrap my brains around the concept. On top of that Enrico does a great job in explaining the intricacies of functors and such.

Hello!

I too, like @Skoucail, would like to do more functional programming in C#. I'm reading the book by Enrico Buonanno.

In general, when seeing functional programming code I usually find it just beautiful. The book by Enrico is most educational.

Now, I do struggle with something. I am not a believer of the OOP paradigm as a way to make software more manageable and easier to design. In fact, I find that in this regard, OOP has really failed us. I often hear from the functional programmer community, as well as books, similar arguments that OOP in general (really generalizing here) increases complexity, makes code harder to maintain and design. This is a viewpoint I can relate to.

The point I'm trying to get to, is that, looking at the book of Enrico, where he explains the implementation of Option (and Some/None), I find myself... slightly lost. Like, after quite some thought I could follow and see how the implementation works. But this feels like code in a whole different level. What I struggle with is this: how does one go about in the thinking process of implementing something like that? It feels complicated. It feels clever. Maybe to clever? Like using implicit conversion operator to do get the effect of "inheritance by implicit conversion" (page 70). Is there any good books about the design process in functional programming? Or is it something that comes with time and experience of using FP ideas?

Also, thanks to @louthy , excellent write up.

Regards

I'm reading the book by Enrico Buonanno. [...] The book by Enrico is most educational.

Indeed. Keep reading it. It is very good.

how does one go about in the thinking process of implementing something like [Enrico's Option type]?

Ok. I think I know where you are going with this.

It feels complicated. It feels clever. Maybe to clever? Like using implicit conversion operator to do get the effect of "inheritance by implicit conversion" (page 70). Is there any good books about the design process in functional programming? Or is it something that comes with time and experience of using FP ideas?

Oh, that is not where I thought you were going.

The implicit conversions are not that important. It is easy to do without them. They are just syntactic sugar.

Implicit conversions are somewhat specific to C# or .NET. On the other hand, functional programming transcends any particular programming language. You probably know another programming language. Can you implement the essence of Enrico's Option type in another language? A crucial feature a language needs in order to express concepts from functional programming is first-class and higher-order functions.

Here is the first line of the README for this project.

This library uses and abuses the features of C# to provide a functional-programming 'base class library' that, if you squint, can look like extensions to the language itself.

language-ext also has those implicit conversion operators. I think it is reasonable to put that feature into the "abuse" column. You don't need to be too hard on yourself for not thinking of such an idea.

This is true in general by the way. In is not necessary to be able to have "new" ideas. Instead, you are very valuable as a programmer specifically and a person in today's society generally if you can hear someone else's idea and quickly understand it.

how does one go about in the thinking process of implementing something like [Enrico's Option type]?

Let's get back to this great question. Even if you meant by this question certain details like implicit conversion operators, I want to show you at what level of detail you should be thinking.

A boolean is a simplest data type. True or false. Often represented by a single bit: 0 or 1.

Most of the time, a boolean is used in an if-else statement to do one thing or another. However, that code is very constrained. It needs to know _both_ what to do when the boolean is true and what do when the boolean is false. The code that handles the true and false cases are currently coupled.

We can weaken that coupling by abstracting over a boolean. We want to represent what we would compute if the boolean were true separately from what we would compute if the boolean were false. In general, this leads to the Either<L, R> type. With such a type, now is it possible to for some code to only "(perhaps partially) handle" the the "true" case. Some other code can "(perhaps partially) handle" the false case.

In practice, you discover it often suffices to only keep track of one piece of data (usually corresponding to the true case). That is the use case for Option<A>. For example, if you have a connection string, then you could make a DbConnection from it. If the connection string is missing, then you cannot. What should we do when asked for a DbConnection but we don't have a connection string? Return null? I think not. We would be lying to they caller. They will think that they have a DbConnection when they do not. Instead, immediately put the "optional" connection string into Option<string>. Then call .Map(CreateDbConnection) to obtain Option<DbConnection> and return that.

Hopefully you found this helpful. Good luck on your journey into functional programming! :)

@TysonMN Thank your for further explaining. I will keep reading/studying, It's quite mind-blowing :)

Like using implicit conversion operator to do get the effect of "inheritance by implicit conversion" (page 70). Is there any good books about the design process in functional programming? Or is it something that comes with time and experience of using FP ideas?

To be fair, Enrico got that idea from language-ext, so it's not a common property of functional-programming technique. I used that technique as a pragmatic way to avoid typing Option<int>.None, which is quite ugly. The reason it works in this instance is because the None type has no contents. There is exactly one value of Option.None and that's None.

This ability to pull a value out of thin air actually has some theory behind it (although that's beyond the scope of the FP in C# book). Option.None is isomorphic to Unit and () (empty-tuple). Interestingly in the category-of-sets (in category-theory) there's always a single unique morphism from any object to the terminal-object. The terminal-object in the category of sets is a singleton.

In programmer speak:

  • Category-of-sets = Type-system (each type representing a set of possible values)
  • Object = Type (bit confusing if you're used to OO land)
  • Morphism = function from one type to another (so a single argument function that returns a value)
  • Unique morphism = means there's exactly one function that fits the definition
  • Terminal-object = The type that all other types can be mapped to, it must, by definition be a singleton type (Unit, None, ())

So, if you went through all types and built a function which represents the unique-morphism it would look like this:

```c#
Unit ToUnit(int _) => unit;
Unit ToUnit(bool _) => unit;
Unit ToUnit(string _) => unit;
...

Clearly that can be made generic:
```c#
    Unit ToUnit<A>(A _) => unit;

Which proves that there's a unique morphism from any type (Object in the Category of Sets) to the terminal-object (Singleton in the Category of Sets).

Because Option.None is a singleton and a terminal object, I know I can write an implicit conversion from anything to Option.None. So providing an implicit conversion from OptionNone (which is also a singleton type) to Option.None is completely legitimate in theory. Incidentally, as-is the implicit conversion from null (another singleton type) to Option.None. In truth they are all isomorphic to each-other, and are therefore effectively the same.

And so, I wouldn't put it in the 'abuse' column, I'd put it in the leveraging type-theory and category-theory column 馃榿

Was this page helpful?
0 / 5 - 0 ratings