Reed Copsey, Jr. Thoughts on F#, C#, WPF, .NET, and programming for Scientific Visualization Home About Series Talks Contact Me F# Basics – Result<'a>: or How I Learned to Stop Worrying and Love the Bind Posted by Reed on December 17, 2020 · 1 Comment This year, for FsAdvent, I’m taking a request and am going to write about embracing the happy path while writing F#. When coming to F# or other functional programming languages, one of the hurdles I see people face is often rethinking how they approach problems. While many posts talk about how to do this, I want to focus on one of the huge advantages – less worry and stress about the code working correctly. For this post, I’m going to use a small example task – parsing a file on disk and summarizing some information from it. In this case, we’ll do something simple – read a CSV log file of “events” that occurred, and get the range of ID numbers from the file. Here is our input file: 12/17/2020 1928 Child in snow 12/17/2020 1929 Child grabbing snow 12/17/2020 1930 Snowball being formed 12/17/2020 1931 Snowball flinging towards tree 12/17/2020 1932 Tree gets hit 12/17/2020 1933 Tree vibrates 12/17/2020 1934 Snow falls off branches 12/17/2020 1935 Snow lands on child and dog 12/17/2020 1936 The dog wimpers, then says "Woof" 12/17/2020 1937 The child hugs dog 12/17/2020 1938 Everybody runs around 12/17/2020 1939 A good time is had by all view raw events.csv hosted with by GitHub Our task will be to read this file, parse it, and get the range of IDs being used. In this case, we’ll end up with 2 numbers as our result – 1928 and 1939. When working in F#, I often start by describing the data I’ll be using, as well as the result I want to get or manipulate. Here, each row represents three things; a date, an ID, and a description of the event. We want to eventually get two numbers, a starting ID and an ending ID. In addition, we know there are a few things that could go wrong – the file might not exist, there might be no data in the file, or the data might be malformed. I’m going to start by defining a couple of types to help with this: // The data in our rows type Event = { Date : DateTime ; ID : int ; Description : string } // Our end result type Range = { Start : int ; End : int } // Our potential problems type Issue = | IO of message : string * exn : Exception | DataMissing | DataMalformed of message : string * exn : Exception view raw types.fs hosted with by GitHub My goal when writing this utility will be to always write in a “happy path”. Instead of focusing on handling bad data or errors, I’m going to try to break everything up into small steps, each a function, that does one thing. I’m always going to assume my inputs are good, and my output will always either be good result or an Issue from above. Basically, I never want to think about “bad data” – I just want to write code that does something as I go. In F#, there is a type that helps with this significantly – Result. The Result type is a discriminated union with two options; an Ok result, or an Error. We’ll start by opening our file. In this case, we want a function that takes a filename and returns a Stream we can use for reading. File IO is one place where exception handling is nearly required, so I’m using that to create my error case: let openFile filename = try File.OpenRead filename |> Result.Ok with | e -> IO(message = "Could not open file", exn = e) |> Result.Error view raw open_file.fs hosted with by GitHub This function will follow a common pattern – it takes an input (filename) and creates a Result: val openFile : filename:string -> Result To parse the file, I’m going to use the CsvHelper library. This will allow me to not think about parsing the “hard parts” of CSV, like strings with embedded commas or quotes. Now we need a small function to take a stream from our openFile and convert it to a CsvReader: let openCsv (strm : Stream) = new CsvReader(new StreamReader(strm), Globalization.CultureInfo.InvariantCulture) view raw open_csv.fs hosted with by GitHub Here, we know, if we have a valid stream, we’ll get a valid reader, so we can just write a simple Stream -> CsvReader helper. We can put these together with Result.map, which allows us to take an “Ok” result and use it’s value to make a new result. let file = openFile "C:\\users\\reedc\\desktop\\events.csv" let csv = file |> Result.map openCsv view raw make_csv.fsx hosted with by GitHub Running in FSI, with a good filename, gives us val csv : Result = Ok CsvHelper.CsvReader . With a bad filename, you get: val csv : Result = Error (IO ("Could not open file", System.IO.FileNotFoundException: Could not find file … Now that our file is opened, we can move onto parsing. Again, we’ll assume we have a good input (our reader), and just write routines to just parse. In this case, I’m going to write a function to parse a single row and create an option, and a separate function to parse until we receive None, which will return our Result. This does get a little uglier with the routine to read all of the rows. We want to make sure to close our file (we effectively pass ownership), so we need the try/finally to dispose of it anytime our routine to open succeeded. We’ll use a simple try/with to handle parsing errors. Using Seq.initInfinite and Seq.takeWhile allows us to “loop” through our data until we return None: let readRow (reader : CsvReader) = if reader.Read () then let evt = { Date = reader.GetField<DateTime>(0) ; ID = reader.GetField<int>(1) ; Description = reader.GetField<string>(2) } Some evt else None let readRowsAndClose reader = try try let rows = Seq.initInfinite (fun _ -> readRow reader) |> Seq.takeWhile (fun r -> r.IsSome) |> Seq.choose id |> Seq.toList if List.isEmpty rows then Result.Error DataMissing else Result.Ok rows with | e -> DataMalformed ("Unable to parse data", e) |> Result.Error finally reader.Dispose () view raw read_rows.fsx hosted with by GitHub Our final step is to reduce the Event list to our two numbers: let getIds (events : Event list) = let ids = events |> List.map (fun e -> e.ID) let min = ids |> List.min let max = ids |> List.max { Start = min ; End = max } view raw get_ids.fs hosted with by GitHub Now that we have all of the pieces, we can stream these together. We will use two functions from the Result module in the core libraries to string these together – Result.map and Result.bind. Whenever we have a function that doesn’t produce an error case, we will use map. When we have a function that takes our input and might need an error case, we will use bind. In our case, openFile and getIds both “always work” if their input are good, so we can map them. readRowsAndClose can map the data through to a list, but can also create an error case, so we will use bind. When stringing these together, we end up with: let result = openFile "C:\\users\\reedc\\desktop\\events.csv" |> Result.map openCsv |> Result.bind readRowsAndClose |> Result.map getIds view raw result.fs hosted with by GitHub When run via FSI, and given the input file above, this now produces: val result : Result = Ok { Start = 1928 End = 1939 } If we pass an invalid filename, we get a nice error: val result : Result = Error (IO ("Could not open file", System.IO.FileNotFoundException: Could not find file... If we pass a good filename, but the file has bad data, that is also handled: val result : Result = Error (DataMalformed ("Unable to parse data", CsvHelper.TypeConversion.TypeConverterException: The conversion cannot be performed. Text: '193d3' By breaking this into pieces, and using Result.map and Result.bind, we were able to parse this in stages, where every stage could assume everything was “good”, and our errors propagate through cleanly at the end. Each step in the chain only has to focus on the task at hand. FILED UNDER .NET, F#, UNCATEGORIZED · TAGGED WITH F# Basics – From loops to folds Posted by Reed on December 19, 2019 · Leave a Comment Instead of writing about Christmas trees this year, like I have for the last few years of FsAdvent, I thought I’d do a post about a topic that seems to frequently arise on the F# Software Foundation slack #beginners channel – looping and folds. People coming to F# from other languages frequently find themselves copying the idioms of their past, and struggling with how to have things make sense in F#. Loops are a very common example. A common thread in these discussions which seem to cause difficulty is “looping to generate a result”. This can be seen easily in the C# tutorial’s looping code. Here, a mutable value is created to hold some result (sum), a for loop iterates through a bunch of numbers, logic is placed in the loop body that mutates the value, and the result is used afterwards. While this can be ported to F# directly, it tends to be ugly in the end, as it relies on looping and on mutation. int sum = 0; for (int number = 1; number < 21; number++) { if (number % 3 == 0) { sum = sum + number; } } Console.WriteLine($"The sum is {sum}"); view raw csharp_coding_challenge.cs hosted with by GitHub I frequently suggest that people new to F# should strive to reduce mutation as well as code which relies on side effects (every loop body does), but confusion frequently occurs with cases like this. Recursion is frequently suggested as a solution, but its far from simple in many cases, especially when people are just starting out. So let’s rework this a bit – and lets start small by reducing mutation. First off, we can refactor the “logic” portion of this into a function and make it pure. In this case, we want a function which will not mutate a value, but instead, return a new value each time it’s run, passing the existing input into it. int AddNewConditionally(int last, int number) { if(number % 3 == 0) return last + number; else return last; } int sum = 0; for (int number = 1; number < 21; number++) { sum = AddNewConditionally(sum, number); } Console.WriteLine($"The sum is {sum}"); view raw csharp_coding_challenge_factored.cs hosted with by GitHub Doing this allows the “logic” to be much more easily tested, but is also an important first step. We can then remove another point of mutation – the for loop itself, by switching to a foreach loop over a sequence: foreach (var number in Enumerable.Range(1,20)) { sum = AddNewConditionally(sum, number); } view raw csharp_for_to_foreach.cs hosted with by GitHub It’s typically at this point where people get stuck. Its far less obvious to see how we remove the mutable value which holds the result. Before we move forward with removing the mutation, lets port this to F#: let addNewConditionally last number = if number % 3 = 0 then last + number else last let mutable sum = 0 for number in { 1..20 } do sum <- addNewConditionally sum number printfn "The sum is %d" sum view raw fsharp_ported_with_loop.fs hosted with by GitHub While this is obviously more succinct, it does exactly the same thing, using the same imperative techniques as before, at least in the core loop. In preparation to eliminate the mutation, I’m going to make this less succinct, so the intention behind what is occuring becomes more obvious. let addNewConditionally last number = if number % 3 = 0 then last + number else last // Start with "0" let startingValue = 0 let valuesToProcess = { 1 .. 20 } // Make a value we can increment as we loop let mutable runningValue = startingValue for number in valuesToProcess do // Adjust this each step runningValue <- addNewConditionally runningValue number // Get the result at the end let sum = runningValue printfn "The sum is %d" sum view raw fsharp_loop_with_steps.fs hosted with by GitHub While this does the same steps as the previous version, each temporary value is broken out into a binding, so the intent and process becomes more clear. However, we still are using a mutable to hold and mutate state each step. Enter fold. If we look at Seq.fold, we see that it has the following signature: Seq.fold : ('State -> 'T -> 'State) -> 'State -> seq<'T> -> 'State view raw Seq.fold hosted with by GitHub This function takes a function as input, which takes the previous state, the current value, and returns the new state. That is remarkably similar looking to our factoring of addNewConditionally – it takes the last value, the current value, and returns the new value. It also then takes a ‘State value – which is the initial state used for the first item being processed. Finally, it takes a sequence to operate over, and then returns a result at the end after processing each item. In our case, we have all three of these, so we can easily rewrite our loop as a fold: let addNewConditionally last number = if number % 3 = 0 then last + number else last // Start with "0" let startingValue = 0 let valuesToProcess = { 1 .. 20 } // Fold instead of looping let sum = Seq.fold addNewConditionally startingValue valuesToProcess printfn "The sum is %d" sum view raw fsharp_fold.fs hosted with by GitHub Note that this eliminates the need for a mutable value – each step works on the previous result, and returns a new value. We can now remove all of the temporaries, and rewrite this much more simply: let addNewConditionally last number = if number % 3 = 0 then last + number else last let sum = { 1 .. 20 } |> Seq.fold addNewConditionally 0 printfn "The sum is %d" sum view raw fsharp_fold_final.fs hosted with by GitHub This gives us a simple, clean way to handle this example. On a side note, in this particular case, the result type and input collection are all int values, and the initial value is the default value for int (0), so we have other, potentially simpler options. We could use Seq.reduce instead, or a Seq.filter piped into a Seq.sum. However, looking back at fold, one benefit is that the ‘State type is separate from the input type ‘T. This means we can use a fold to replace any loop that is used to generate results based off the items being looped over, even if the types don’t match. As a simple example, lets say our requirements change. Instead of just needing the sum of the values that meet our criteria, suppose we want to generate a list of the values as strings. All we need to do is change our function to work on and return a string list, and to change our initial ‘State value. let buildListConditionally l number = if number % 3 = 0 then (string number)::l else l let values = { 1 .. 20 } |> Seq.fold buildListConditionally [] printfn "The values are %A" values printfn "The first value is \"%s\"" (List.head values) view raw fsharp_fold_v2.fs hosted with by GitHub This works the same way, but now we go from int seq to string list instead of to an int as our result. While these are fairly simple and contrived examples, the approach taken here works for moving from any loop that generates “results” to a fold: Make core logic a pure function (which can be a lambda expression) – which takes the previous result, the current value, and return a new state Rework items being “processed” into a collection or sequence if using a “for” style loop Remove the mutable “running value” and the loop, and replace with a call to fold FILED UNDER UNCATEGORIZED · TAGGED WITH 2018 Christmas Trees – Cross Platform Edition using Avalonia Posted by Reed on December 18, 2018 · 2 Comments For the last couple of years, my FsAdvent posts have focused around a simple, fun little Christmas Trees application illustrating the usage of Gjallarhorn.Bindable – and for this year, I thought I’d keep the streak going – with a twist. I’m happy to announce the availability of Gjallarhorn.Bindable.Avalonia, which allows Gjallarhorn to be used with Avalonia, the cross platform XAML based UI Framework. Read more FILED UNDER UNCATEGORIZED · TAGGED WITH Christmas Trees in WPF, 2017 Update Posted by Reed on December 14, 2017 · 6 Comments Last year, I wrote about making Christmas Trees in WPF using Gjallarhorn. The Gjallarhorn project has improved dramatically since last year, and I thought I’d update the project, demonstrating the newer API and significant improvements in usability and ease of development. I recommend skimming through the previous post, as this post expands on the information there. This post will modernize the Christmas TreeÂ application from last year, improving it, and highlighting the changes in Gjallarhorn, showing the dramatic improvements inspired by great projects like Elmish. My hope is that more developers will see the benefits of unidirectional architecture for UI development, and try using Elmish for web, Gjallarhorn for XAML, or other unidirectional, functional approaches to user interfaces. Read more FILED UNDER UNCATEGORIZED · TAGGED WITH Christmas Trees in WPF, 2016 Edition Posted by Reed on December 15, 2016 · 8 Comments Last year, I wrote about making Christmas Trees in WPF using FSharp.ViewModule. Â At the time,Â I was excited being able to demonstrate howÂ FSharp.ViewModule could make typical MVVM much more functional feeling. Â This year, for my F# Advent Calendar contribution, I want to demonstrate how Gjallarhorn.BindingÂ can serve as a replacement, and help create a WPF application with a design that is clean, functional, and most importantly, simple. This post will modernize the Christmas TreeÂ application from last year, improving it, and highlighting the differences between a classic MVVM approach to WPF and a more functional approach. Â While reading through the post from last year would add context, it’s completely optional. Read more FILED UNDER .NET, ASYNC, F#, GJALLARHORN, MVVM, WPF · TAGGED WITH WPF GJALLARHORN F# Christmas Trees in WPF using FSharp.ViewModule Posted by Reed on December 9, 2015 · 9 Comments As my contribution to the F# Advent Calendar this year, I thought Iâ€™d write a bit about one approach I often use to create WPF user interfaces in a functional style – mixing MailboxProcessor with FSharp.ViewModule. This post will illustrate using a pair of MailboxProcessor instances mixed with FSharp.ViewModuleÂ toÂ construct a simple application. Â In the spirit of F# Advent, our application will be a small drawing application that allows us to place and decorate Christmas trees. Read more FILED UNDER ASYNC, F#, MVVM, UNCATEGORIZED, WPF · TAGGED WITH F# 2014 – A Retrospective and Call to Action Posted by Reed on December 31, 2014 · 6 Comments I have the privilege of being allowed to writeÂ the final post forÂ theÂ F# Advent Calendar in English. To celebrate, I thought I’d skip aÂ technical post and end the year, and the Advent Calendar, with a brief, personal look back on 2014 and the wonderful time I’ve had within the F# community over this past year. Read more FILED UNDER COMMUNITY, F#, F# SOFTWARE FOUNDATION · TAGGED WITH F#, F# SOFTWARE FOUNDATION, FSSF Slides and Code from “Using C#’s Async Effectively” Posted by Reed on October 2, 2013 · 3 Comments The slides and code from my talk on the new async language features in C# and VB.Net are now available on https://github.com/ReedCopsey/Effective-Async Read more FILED UNDER .NET, ALGORITHMS, ASYNC, C#, COMMUNITY · TAGGED WITH .NET, .NET 4.5, C#, C# 5, COMMUNITY Launching a WPF Window in a Separate Thread, Part 1 Posted by Reed on November 28, 2011 · 45 Comments Typically, I strongly recommend keeping the user interface within an applicationâ€™s main thread, and using multiple threads to move the actual â€œworkâ€ into background threads. However, there are rare times when creating a separate, dedicated thread for a Window can be beneficial. This is even acknowledged in the MSDN samples, such as the Multiple Windows, Multiple Threads* sample. However, doing this correctly is difficult. Even the referenced MSDN sample has major flaws, and will fail horribly in certain scenarios. To ease this, I wrote a small class that alleviates some of the difficulties involved. Read more FILED UNDER .NET, C#, WPF · TAGGED WITH .NET, C#, WPF Reflections on GiveCamp Posted by Reed on October 25, 2011 · 2 Comments I participated in the Seattle GiveCamp over the weekend, and am entirely impressed. GiveCamp is a great event â€“ I especially like how rewarding it is for everybody involved. I strongly encourage any and all developers to watch for future GiveCamp events, and consider participating, for many reasonsâ€¦ Read more FILED UNDER COMMUNITY, PROFESSIONAL · TAGGED WITH CHARITY, COMMUNITY, GIVECAMP, PROGRAMMING Next Page » Search for: Categories Categories Select Category .NET (73) C# (67) F# (4) MVVM (15) WPF (19) Algorithms (34) Async (7) Parallelism (22) C Tech (1) C++ (3) Community (3) F# Software Foundation (1) Gjallarhorn (1) Performance (2) Professional (4) Uncategorized (5) Meta Log in Entries feed Comments feed WordPress.org Tags .NET .NET 4 .NET 4.5 Algorithms Async C# C# 4 C# 5 Charity Community F# F# Software Foundation FSSF GiveCamp IDisposable Interop MEF MVP MVVM Optimization Parallelism Performance PLINQ Programming Windows Forms WPF WPF Gjallarhorn F# StackOverflow Reed Copsey 530,914 ●7272 gold badges●11031103 silver badges Archives December 2020 December 2019 December 2018 December 2017 December 2016 December 2015 December 2014 October 2013 November 2011 October 2011 September 2011 August 2011 April 2011 January 2011 December 2010 October 2010 July 2010 April 2010 March 2010 February 2010 January 2010 December 2009 November 2009 October 2009 September 2009 August 2009 July 2009 May 2009 April 2009 March 2009 Twitter Feed META Log in Entries feed Comments feed WordPress.org CAREER C Tech RECENT POSTS F# Basics – Result<'a>: or How I Learned to Stop Worrying and Love the Bind F# Basics – From loops to folds 2018 Christmas Trees – Cross Platform Edition using Avalonia CATEGORIES .NET Algorithms Async C Tech C# C++ Community F# F# Software Foundation Gjallarhorn MVVM Parallelism Performance Professional Uncategorized WPF © 2021 REED COPSEY, JR. · SHADES OF BLUE THEME BY STUDIOPRESS · WORDPRESS · LOG IN