Circular Reasoning in Haskell by Tom Harding

October 27, 2022

In the Circular Reasoning in Haskell presentation by Tom Harding, he discusses the challenges and complexities of creating circular references in Haskell, a purely functional programming language known for its lazy evaluation. Tom shares his experience of using go-to statements in Haskell, which demonstrates the power of lazy evaluation but is difficult to read and write. He also mentions the availability of libraries for common use cases and the lack of built-in type facilities to help with circular reasoning. Tom advises that if no useful library or alternative is found, one might consider writing JavaScript instead. The talk concludes with a demonstration of creating cyclical data structures in Haskell using the proposed approach.

Circular Reasoning in Haskell: A comprehensive overview

Introduction and background

Tom Harding took the stage to discuss circular reasoning in Haskell, sharing his background and what motivated him to explore this topic. He set the stage by highlighting the unique challenges of creating circular references in a purely functional language like Haskell, where mutable state is not supported.

Challenges of circular references

Tom started by addressing the fundamental issue: in mutable languages like JavaScript, creating circular references (e.g., a person being their own friend in a social network) is straightforward. However, Haskell’s immutability means once a value is defined, it cannot be changed. To tackle this, Tom introduced the concept of defining a value in terms of itself, made possible through Haskell’s lazy evaluation. This allows values to be wrapped in promises, only evaluated when needed.


Lazy evaluation and circular definitions

One of the standout aspects of Tom’s talk was his explanation of how Haskell’s lazy evaluation handles circular definitions. Using social network friends as an example, he illustrated that Haskell doesn’t need all definitions upfront. Instead, the compiler figures out just enough to provide an answer when requested. This lazy evaluation enables the creation of infinite lists and sequences, such as the Fibonacci sequence, without running into infinite loops, a common issue in non-lazy languages.


The role of monad Fix

Tom introduced the concept of Monad Fix, a tool for referring to values not yet defined within a block, essential for handling I/O effects where execution order matters. By using Monad Fix, one can define circular references within an I/O context, such as a friendship graph that involves I/O operations. This tool essentially allows a function to take its output as an input, a powerful feature when dealing with circular dependencies.


Practical examples and warnings

To ground his theoretical explanations, Tom presented practical examples. He demonstrated the use of the mfix function in IO to introduce laziness and how to build functions that handle sums and counts in lists using circular references. He also warned about the dangers of misusing these features, which can lead to infinite loops if not handled carefully.


Stateful Operations and Arrows

Moving further, Tom discussed stateful operations in Haskell and how monads can chain these operations together, producing values and updated states. He hinted at advanced concepts like running code in reverse order and manipulating states that occur in the future or past, teasing a future talk on this intriguing subject.

He also touched upon Arrows as a potential alternative to Monads, aiming to simplify code and eliminate branching. This part of the talk highlighted Tom’s inventive approach, as he shared his creation of a new language with go-to labels and print statements to streamline execution.


Practical challenges and solutions

Tom didn’t shy away from discussing the practical challenges of implementing circular reasoning in Haskell. He shared his experiences with go-to statements and mutable variables, illustrating how these can complicate program logic. Despite these challenges, he emphasized the value of lazy evaluation in Haskell for avoiding impossible problems.

He also pointed out that while Haskell lacks built-in type facilities to handle circular reasoning cleanly, various libraries exist to manage common use cases like running state backwards or bidirectional state operations. These libraries are designed to help developers navigate the complexities of circular reasoning.


Conclusion and takeaways

Tom concluded his presentation by acknowledging the difficulties of circular reasoning in Haskell but also its potential when used correctly. He advised developers to explore existing libraries for handling circular dependencies and, if all else fails, to consider simpler solutions like JavaScript.

Tom’s talk provided a deep dive into the nuanced world of circular reasoning in Haskell, offering valuable insights for both seasoned Haskell developers and those new to functional programming.


Final thoughts

Tom Harding’s presentation on circular reasoning in Haskell was a masterclass in understanding the language’s lazy evaluation and handling complex data dependencies. His examples and explanations shed light on how to leverage Haskell’s strengths while navigating its challenges, making this talk a must-watch for anyone interested in functional programming and advanced Haskell concepts.


Additional resources

Check out more from the MeetUp Func Prog Sweden. Func Prog Sweden is the community for anyone interested in functional programming. At the MeetUps the community explore different functional languages like Erlang, Elixir, Haskell, Scala, Clojure, OCaml, F# and more.