Writing Haskell with Chat GPT
In our last couple of articles, we've asked Chat GPT a bunch of questions about Haskell and functional programming. Today we're going to do one more exploration to see what kinds of Haskell code this chatbot can write.
Hello World
We'll start with a simple "Hello World" program.
How do I write a "Hello World" program in Haskell?
Chat GPT:
To write a "Hello World" program in Haskell, you can use the putStrLn
function from the Prelude, which is Haskell's default library. This function takes a string as an argument and prints it to the console. Here's an example of a simple "Hello World" program in Haskell:
main :: IO ()
main = putStrLn "Hello, World!"
This program defines a function main that has the type IO ()
. The IO
type is used for actions that perform input/output, and the ()
type represents the empty tuple, which has no contents. The main
function is special in Haskell because it is the entry point of every executable Haskell program. When the program is run, the main
function will be called and the string "Hello, World!" will be printed to the console.
You can compile and run this program using the ghc
compiler, which is included with the Haskell Platform. First, save the program to a file named HelloWorld.hs
. Then, open a terminal and navigate to the directory where you saved the file. To compile the program, type the following command:
ghc HelloWorld.hs
This will produce an executable file named HelloWorld
. To run the program, type the following command:
./HelloWorld
This will print "Hello, World!" to the console.
Commentary
This not only gives the code to run the program, it also gives detailed instructions for running it using GHC. Recommending Stack and GHCup would be better advice for beginners though. I'm sure it would know how to describe using these tools if asked about them. But it would be best if it knew to recommend these tools to someone who didn't know about them. Still, I'm nit-picking a bit here.
Sorting Algorithms
So a "Hello World" program is one of the simplest things you can do though. How does ChatGPT do with writing some algorithmic code? Let's start with a couple simple sorting algorithms, quicksort and mergesort.
How can I write quicksort in Haskell?
Chat GPT:
Here is an implementation of quicksort in Haskell:
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort [y | y <- xs, y <= x] ++ [x] ++ quicksort [y | y <- xs, y > x]
This function defines a quicksort
that sorts a list of elements that are part of the Ord
type class (which includes types like Int
, Char
, and Double
). The function uses a recursive approach to sort the list.
The base case of the recursion is the empty list, which is already sorted. For the recursive case, the function divides the list into three parts:
- A sublist of elements that are less than or equal to the pivot element (x)
- The pivot element itself
- A sublist of elements that are greater than the pivot element
The function then recursively sorts the first and third sublists, and concatenates the sorted sublists with the pivot element to produce the final sorted list.
You can test this implementation by calling quicksort
with a list of elements:
quicksort [4, 6, 9, 8, 3, 5, 1, 7, 2]
This should return the sorted list [1, 2, 3, 4, 5, 6, 7, 8, 9]
.
How can I write mergesort in Haskell?
Chat GPT:
Here is an implementation of mergesort in Haskell:
merge :: Ord a => [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys)
| x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
mergesort :: Ord a => [a] -> [a]
mergesort [] = []
mergesort [x] = [x]
mergesort xs = merge (mergesort left) (mergesort right)
where
mid = length xs `div` 2
left = take mid xs
right = drop mid xs
This implementation defines a merge
function that merges two sorted lists into a single sorted list, and a mergesort
function that sorts a list using the merge sort algorithm.
The merge
function works by comparing the head elements of the two input lists, and adding the smaller of the two to the result list. It repeats this process until one of the input lists is empty, at which point it appends the remaining elements of the other list to the result.
The mergesort
function works by dividing the input list into two halves, sorting each half using a recursive call to mergesort
, and then merging the two sorted halves using the merge
function.
You can test this implementation by calling mergesort
with a list of elements:
mergesort [4, 6, 9, 8, 3, 5, 1, 7, 2]
This should return the sorted list [1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Commentary
For quicksort, it comes up with a simple 3-line solution, and the mergesort solution is also quite succinct. However, one change I would make to the solution is to tail recursion. As with the "Hello, World" example though, the descriptions are very helpful for someone just learning the language.
Heap Sort
Quicksort and mergesort are one thing. These algorithms have fairly straightforward recursive implementations that work well in Haskell. What about heapsort?
How can I write heapsort in Haskell?
Chat GPT:
Here is an implementation of heapsort in Haskell:
heapify :: Ord a => [a] -> [a]
heapify xs = heapify' (length xs `div` 2 - 1) xs
where
heapify' (-1) xs = xs
heapify' i xs = heapify' (i - 1) (heapifyOne i xs)
heapifyOne :: Ord a => Int -> [a] -> [a]
heapifyOne i xs = case cmp of
GT -> xs
_ -> heapifyOne' i cmp xs
where
cmp = compare (xs !! i) (xs !! child)
child = if r < length xs && xs !! r > xs !! l then r else l
l = 2 * i + 1
r = 2 * i + 2
heapifyOne' i GT xs = xs
heapifyOne' i _ xs = heapifyOne (if r < length xs && xs !! r > xs !! l then r else l) $ swap i (if r < length xs && xs !! r > xs !! l then r else l) xs
where
l = 2 * i + 1
r = 2 * i + 2
swap i j xs = [if k == i then xs !! j else if k == j then xs !! i else xs !! k | k <- [0..length xs - 1]]
sort :: Ord a => [a] -> [a]
sort [] = []
sort xs = y : sort ys
where
(y:ys) = heapify xs
This implementation defines a heapify
function that turns a list into a heap, and a sort
function that sorts a list using the heap sort algorithm.
The heapify
function works by recursively transforming the list into a heap, starting from the middle of the list and working towards the beginning. It does this by repeatedly calling the heapifyOne
function, which restores the heap property to a single element and its children in the heap.
The sort
function works by repeatedly extracting the maximum element (the root of the heap) and placing it at the end of the result list, until the heap is empty.
You can test this implementation by calling sort with a list of elements:
sort [4, 6, 9, 8, 3, 5, 1, 7, 2]
This should return the sorted list [1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Commentary
Very impressive, especially with the detailed description! This time, we do see tail recursion applied in the heapify
function.
List Functions
How does it do with a more abstract prompt? I came up with this question based on Day 1 of the recently concluded 2022 Advent of Code.
Write a Haskell function to solve the following problem. The input is a list of lists of integers. We want to find the three lists with the largest sums, and add their sums together. So the output is just an integer.
Chat GPT:
Here is a function that solves the problem you described:
largestThreeSums :: [[Int]] -> Int
largestThreeSums xs = sum $ take 3 $ sortBy (flip compare) $ map sum xs
This function first applies the sum
function to each sublist in xs
, producing a list of sums. It then sorts this list in descending order using the sortBy
function, and takes the first three elements using the take
function. Finally, it sums these three elements using the sum
function and returns the result.
To use this function, you can call it with a list of lists of integers as an argument:
largestThreeSums [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
This should return the result 33, which is the sum of the three largest sublists [7, 8, 9], [10, 11, 12], and [4, 5, 6]
.
Commentary
This is quite similar to my solution! So Chat GPT did an effective job parsing my description, and determining the right list functions to use to make an efficient, one-line solution.
Making a Server
For one more example, let's try doing something more practical, like a web server. This will require using libraries beyond Haskell's base packages. Once again, this works quite well!
How can I write a basic HTTP server in Haskell?
Chat GPT:
Here is an example of a basic HTTP server in Haskell using the wai
and wai-extra
libraries:
{-# LANGUAGE OverloadedStrings #-}
import Network.Wai
import Network.Wai.Handler.Warp
import Network.HTTP.Types (status200)
import Blaze.ByteString.Builder (copyByteString)
import qualified Data.ByteString.UTF8 as BU
app :: Application
app request respond = respond $
case rawPathInfo request of
"/hello" -> hello
_ -> notFound
where
hello = responseBuilder
status200
[("Content-Type", "text/plain")]
(copyByteString "Hello, World!")
notFound = responseBuilder
status404
[("Content-Type", "text/plain")]
(copyByteString "Not Found")
main :: IO ()
main = do
putStrLn "Listening on port 3000"
run 3000 app
This server listens for incoming HTTP requests on port 3000, and responds with a "Hello, World!" message for requests to the /hello
path, and a "Not Found" message for all other paths.
To run this server, save the code to a file and compile it using the ghc
compiler:
ghc Server.hs
This will produce an executable file named Server
. To start the server, run the executable:
./Server
You should see the message "Listening on port 3000" printed to the console. You can then send HTTP requests to the server using a tool like curl
or by opening a web browser and going to http://localhost:3000/hello
. You should receive a "Hello, World!" response for the /hello
path, and a "Not Found" response for all other paths.
Conclusion
So overall, Chat GPT does quite well with these basic challenges! It would be interesting to take this further still and see if we could make our server program more and more complex, like adding custom functionality for different routes. But Chat GPT definitely seems useful enough to help with basic tasks, even in a less well-known language like Haskell!
As a final note, I did check (out of curiosity) to see if Chat GPT seemed to know much about this blog. The answer appeared to be a resounding "no", leading to a good laugh for me! I asked, "do you know about Monday Morning Haskell?" This was the response I got from Chat GPT (emphasis is mine):
Yes, I am familiar with the term "Monday Morning Haskell." It refers to a programming style or approach that involves using the Haskell programming language to solve problems or write software on a Monday morning, with the implication being that Haskell is a particularly well-suited language for starting the work week off with a clear and focused mind. Haskell is a functional programming language known for its strong static type system, expressive type inference, and purity (lack of side effects). Many developers find that programming in Haskell can help them write clearer, more concise, and more maintainable code, and that it is especially well-suited for tasks that require reasoning about abstract concepts or dealing with complex data.
I might just have to add that description to the home page!
Chat GPT and Functional Programming
Last week I explored what Chat GPT has to say about monads. But it's interesting to go beyond this single area and see what its thoughts are about functional programming (FP) in general, and how different languages fit within this paradigm.
So I asked the bot a few questions in these areas to see its response. In each section, the question is either the header, or if it is a longer question, it is given as a quote below the header. This will then be followed by Chat GPT's answer. I'll then follow most sections with some commentary.
We'll see that despite providing a lot of useful knowledge, the bot still sometimes struggles with consistency and the handling of ambiguous and contentious issues.
What is Functional Programming?
Chat GPT:
Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions. It is based on the idea of immutability and the avoidance of changing state and mutable data. In functional programming, functions are first-class citizens, meaning that they can be passed as arguments to other functions and returned as values from functions. This allows for the creation of higher-order functions that take other functions as input or return them as output.
Functional programming languages typically provide features such as higher-order functions, anonymous functions, and lazy evaluation to support the functional programming paradigm. Some examples of functional programming languages include Lisp, ML, Haskell, and Erlang.
Functional programming has a number of advantages, including the ability to write code that is easier to reason about, easier to test, and less prone to errors. It can also be more efficient in some cases, since it avoids the overhead of mutable state and allows for the use of techniques such as memoization and parallelization. However, it can also be more difficult to understand and learn for programmers who are used to imperative programming styles.
Commentary
So we start with an abstract definition: FP is a paradigm that views programming as the evaluation of mathematical functions. Then we get a slew of features (immutable state, functions as first class citizens, etc.). The features it lists include lazy evaluation, which is noteworthy.
It's interesting though to compare the advantages and disadvantages the bot mentions. It says that functional code is "easier" to reason about and test. It also lists efficiency as an important feature.
It then claims a disadvantage is that it is more difficult to understand...but mainly for people coming from imperative styles. So overall it should be easier to understand, but programmers who have been trained in other systems have a difficult time migrating to FP.
We'll come back to a number of these points later. But first, let's ask about a couple other languages and how they relate to functional programming.
Is C++ a Functional Language?
Chat GPT:
C++ is a multi-paradigm programming language, meaning that it supports several programming paradigms, including functional programming. However, C++ is not a purely functional language, as it also supports other paradigms such as imperative programming and object-oriented programming.
While C++ does not have some of the features that are commonly found in functional programming languages, such as first-class functions and lazy evaluation, it does support the creation of functions and the use of function pointers, which allows for the use of functional programming techniques to some extent.
For example, it is possible to write code in C++ that uses higher-order functions, anonymous functions, and recursive functions, which are all common features of functional programming languages. However, C++ does not have some of the other features that are commonly found in functional programming languages, such as pattern matching and algebraic data types.
Is Rust a Functional Language?
Chat GPT:
Like C++, Rust is a multi-paradigm programming language that supports functional programming, among other paradigms. Rust provides a number of features that make it suitable for functional programming, such as first-class functions, pattern matching, and algebraic data types.
However, Rust is not a purely functional language, as it also supports imperative programming and object-oriented programming. Rust's support for functional programming is more limited than that of languages that were specifically designed for functional programming, such as Haskell or ML.
Despite this, Rust's support for functional programming is sufficient to allow developers to write code in a functional style, and many Rust developers use functional programming techniques in their Rust code.
Commentary
What we see here is the difference between "what is functional programming" and "what is a functional language". C++ and Rust both allow you to use functional programming techniques even if FP isn't their primary paradigm. They're both intended to be flexible, multi-paradigm languages.
However, Rust facilitates FP much more through specific features, specifically abstract data types and pattern matching. Features like these are definitely an important part of why, culturally speaking, Rust programmers are more likely to employ functional programming ideas in their code.
What about the reverse? Does Chat GPT think we can use Haskell for Object Oriented Programming (OOP)?
Can Haskell be used in an object-oriented way?
Chat GPT:
Haskell is a purely functional programming language, which means that it does not support object-oriented programming as a primary paradigm. However, that does not necessarily mean that it is impossible to write object-oriented code in Haskell.
One way to write object-oriented code in Haskell is to use a typeclass-based approach, where types are defined as data types and behaviors are defined as functions on those data types. This can provide a way to define classes and objects, and to define methods on those objects.
Another way to write object-oriented code in Haskell is to use the "Object I/O" library, which provides a set of libraries and tools for building graphical user interface (GUI) applications in Haskell using an object-oriented style. This library allows developers to define classes, objects, and methods in a way that is similar to object-oriented languages such as Java or C++.
Overall, while Haskell is not a language that was designed for object-oriented programming, it is possible to use it in an object-oriented way with some effort. However, the functional programming paradigm is more idiomatic in Haskell, and most Haskell code is written in a functional style.
Commentary
This answer arrives at a conclusion I've had for a while. Typeclasses provide most of the abstraction you really need to get a lot of the benefits of OOP. Of course, they don't inherently provide stateful mutations, which are implicit in OOP, but this is possible to include in Haskell with the State monad.
It is interesting to see the trend that FP is a "more restrictive" paradigm. FP languages don't naturally address OOP as easily or as often as OOP languages allow functional ideas. But I would spin this as a positive for FP. Java and C++ have added more functional features (especially with lambda syntax) in the last few years because functional ideas are inherently useful. Haskell doesn't feel the need to incorporate OOP ideas as much because it doesn't need them.
Lazy Evaluation
In response to the first question, the bot included "lazy evaluation" as one of the features of functional programming, even though this is more specific to a few languages than to the whole paradigm. So I asked the following question:
Is lazy evaluation a defining characteristic of functional programming? Are there functional languages that use eager evaluation?
Chat GPT:
Lazy evaluation is a common feature of functional programming languages, but it is not a defining characteristic of functional programming. Lazy evaluation is a evaluation strategy that delays the evaluation of an expression until it is needed, rather than evaluating it as soon as it is bound to a variable.
Lazy evaluation can be useful in functional programming because it allows for the creation of infinite data structures, and it can also lead to more efficient code in some cases by avoiding the computation of unnecessary expressions. However, lazy evaluation is not a requirement for a language to be considered functional.
There are indeed functional programming languages that use eager evaluation, which is the opposite of lazy evaluation. Eager evaluation evaluates expressions as soon as they are bound to a variable, rather than delaying their evaluation until they are needed.
Some examples of functional programming languages that use eager evaluation include Miranda and Mercury. These languages provide many of the same features as lazy functional languages, such as higher-order functions and immutable data structures, but they use eager evaluation instead of lazy evaluation.
Commentary
So it seems like I've caught the bot in a bit of inconsistency. Lazy evaluation is not actually a necessary part of FP (like it implied in its first answer). But it's certainly more common in FP-oriented languages.
Disadvantages of FP
You said functional programming is more difficult to understand for programmers used to an imperative style. Are there any other disadvantages to functional programming?
Chat GPT:
Functional programming can be more difficult to understand for programmers who are used to imperative programming styles because it involves a different way of thinking about computation. In functional programming, the emphasis is on expressing the desired result of a computation rather than specifying how the computation should be performed, which can be a shift for programmers who are used to an imperative approach.
There are a few other potential disadvantages to functional programming to consider:
- Performance: In some cases, functional code can be less efficient than imperative code, particularly if it makes heavy use of higher-order functions or lazy evaluation.
- Debugging: Debugging functional code can be more difficult in some cases because it can be harder to understand the flow of control in a functional program, especially if the program makes heavy use of higher-order functions or anonymous functions.
- Lack of familiar libraries: Depending on the language, the functional programming ecosystem may not have as many libraries and frameworks available as other paradigms. This can make it more difficult to build certain types of applications, and may require more work to integrate functional code with existing systems.
- Limited adoption: Functional programming is not as widely used as imperative programming, which means that there may be a smaller pool of developers with functional programming experience to draw from. This can make it more difficult to find developers with functional programming skills, and can also make it more difficult to find resources and documentation when learning functional programming.
It's worth noting that these disadvantages are not unique to functional programming, and many of them can be mitigated with the right tools and techniques. Ultimately, the choice of programming paradigm should be based on the needs of the project and the preferences of the development team.
Commentary
So two of the 4 disadvantages still mainly come down to "Haskell/FP are hard because fewer people use them". If there was wider adoption (point #4), then there would be more familiar libraries (point #3).
It's curious though that performance is now listed as a disadvantage when "efficiency" was given as an advantage before! But both points are salient. Immutability does make parallelization easier, but a variety of issues can make FP less efficient, especially in Haskell, where a simple action like changing a value in a contiguous array might require re-copying the whole array.
Debugging is definitely an important issue to list as a disadvantage. Besides GHCI, I haven't used a specific debugging tool for Haskell with much success, so this is a good topic to explore.
In this discussion of the advantages and disadvantages of FP, I thought it would be a good idea to check on formal research in the area. Here's what Chat GPT had to say:
Research
You said functional programming can be easier to reason about and easier to test. Are there experiments or research comparing functional programming and other paradigms in these areas?
Chat GPT:
There have been a number of studies and surveys conducted over the years that have compared functional programming with other paradigms in terms of readability, maintainability, and other factors. These studies have generally found that functional programming can be easier to reason about and easier to test in some cases, although the results are not always clear-cut and can depend on a variety of factors.
For example, a study published in the Journal of Systems and Software in 2002 compared the maintainability of functional, imperative, and object-oriented programs and found that functional programs had fewer maintenance-related defects and were easier to understand than imperative programs.
Another study published in the Journal of Functional Programming in 2005 surveyed developers who had used both functional and imperative programming languages and found that the functional programmers reported fewer debugging and testing problems, and felt that their programs were easier to understand and modify.
Overall, it seems that functional programming can offer some benefits in terms of readability and testability, but more research is needed to determine the extent to which these benefits hold up in practice. It's also important to note that the choice of programming paradigm is just one factor that can impact the readability and maintainability of code, and other factors such as code style, architecture, and the use of good design practices can also be important.
Are There More Recent Studies?
Chat GPT:
There have been a number of more recent studies and surveys that have compared functional programming with other paradigms in terms of readability, maintainability, and other factors.
For example, a study published in the Journal of Systems and Software in 2015 examined the effect of functional programming on the reliability of software systems and found that functional programs had fewer defects and were easier to understand than imperative programs.
Another survey published in the ACM SIGPLAN Haskell Symposium in 2018 surveyed developers who had used both functional and imperative programming languages and found that the functional programmers reported fewer debugging problems and felt that their programs were easier to understand and modify.
Overall, it seems that the results of these more recent studies are consistent with the findings of earlier studies, which is that functional programming can offer some benefits in terms of readability, maintainability, and reliability, but more research is needed to determine the extent to which these benefits hold up in practice.
Linking to Studies
Can you link me to these studies?
Chat GPT:
Sure! Here are the links to the studies I mentioned:
- "A comparison of the maintainability of object-oriented, imperative and functional programs" (2002): https://www.sciencedirect.com/science/article/pii/S0164121201001866
- "Functional programming experience: A survey of functional and imperative programmers" (2005): https://www.researchgate.net/publication/220654465_Functional_programming_experience_A_survey_of_functional_and_imperative_programmers
- "Functional programming and the reliability of software systems" (2015): https://www.sciencedirect.com/science/article/pii/S0164121214001442
- "The State of Haskell in Industry" (2018): https://dl.acm.org/doi/10.1145/3236779.3236782
Commentary
Similar to my experience with asking Chat GPT for monad tutorials, none of these links work unfortunately. So Google is still definitely a better option for finding research and tutorials. But the summary we get from the bot is consistent with what I had thought before. A few groups have tried to study FP vs. OOP, and cautiously concluded some small advantages with FP, but it's difficult to resolve this issue conclusively.
Conclusion
Chat GPT provides a very good summary of the broad points about programming issues. However, when you really dig into the details, things aren't always completely consistent, and it is definitely not the best tool for finding research results just yet.
Next week, we'll take one final run with Chat GPT and see if it can write some Haskell code for us!
Monads According to a Robot
To start the new year, I thought it would be fun to spend some time messing around with the item that's all the rage right now - Chat GPT, the newest chatbot published by Open AI.
This chatbot can provide decent answers to most questions you throw at it, similar in concept to Google. However, instead of simply linking to other pages, it can provide fairly detailed and lengthy responses to the question, which Google cannot do. It also does a good job of maintaining conversational context, which is well beyond Google's abilities right now.
So I thought it would be interesting to ask it about a few Haskell-related topics. This week, we'll start with Monads, one of the trickier subjects involved with learning Haskell. I wanted to see how its suggestions line up with my Monads Series.
So the next three sections consist of me asking a question to Chat GPT, and its (often lengthy) response.
What is a Monad?
A monad is a concept from functional programming, which involves structuring programs as a series of computations that are strung together and can be combined in various ways. It's a way of abstracting out certain patterns of computation and making it easier to reuse and compose code. Monads are a bit of an advanced topic, and can be difficult to understand at first, but they can be very powerful once you get the hang of them.
What are Monads used for?
Monads are a powerful concept from functional programming that can be used to structure programs in a way that makes them easier to write, understand, and maintain.
At their core, monads are a way of abstracting out common patterns of computation and making them more modular and reusable. This allows you to write code that is more flexible and easier to work with, and can help you avoid common pitfalls and mistakes.
One of the key benefits of using monads is that they allow you to write code that is more declarative and abstract, rather than focusing on the details of how the computation is actually performed. This can make your code more concise and easier to read, and can help you avoid getting bogged down in the specifics of how the code works.
Another advantage of monads is that they make it easier to combine and compose different pieces of code, allowing you to build larger, more complex programs from smaller, more modular components. This can help you write more flexible and reusable code, and can make it easier to write programs that are modular, maintainable, and easy to understand.
Overall, monads are a powerful tool that can help you write better, more elegant code. They may take some time to understand and get used to, but once you get the hang of them, they can be a valuable asset in your programming toolkit.
How do I use Monads in Haskell?
To use monads in Haskell, you first need to have a basic understanding of the Haskell programming language and how it works. Once you have a handle on the basics, you can start learning about monads and how to use them in your programs.
One way to get started with monads in Haskell is to read through some tutorials or blog posts that introduce the concept and provide examples of how to use monads in your code. There are many resources available online that can help you learn about monads and how to use them in Haskell, including tutorials, blog posts, and videos.
Another way to learn about monads is to experiment with using them in your own programs. This can be a great way to get a feel for how monads work and how they can help you write better code. You can try writing simple programs that use monads, and see how they help you structure your code in a more modular and reusable way.
Overall, the best way to learn how to use monads in Haskell is to dive in and start experimenting with them in your own code. The more you use monads and see how they work, the better you will understand them and be able to apply them in your programs.
My Thoughts
I often describe a monad as a "computational context", and this idea is clearly seen in the bot's response. It talks about "abstracting patterns of computation", which is more or less the same thing. Its response also emphasizes some elements that get lost when we get too far into the weeds of a tutorial, like the modularity and reusability of code. Perhaps I'll go back and re-emphasize those pieces in my own tutorials.
The general response for "how do I use monads" is also good. Reading tutorials helps, and writing your own programs is ultimately essential. I'll link once again to my tutorial series, which contains some code examples you can try for yourself. For more detailed examples that allow you to work on your own project code, you can also try out my two monad-related courses, Making Sense of Monads, and Effectful Haskell.
Limitations
Unfortunately, the bot does a surprisingly poor job providing links to such tutorials. It provided me with several examples of blog posts that sounded very convincing, like "All About Monads by Brent Yorgey", and then it would link me to Brent Yorgey's blog page with a URL that contained the title "All About Monads" from 2009 or so. But the link was broken, suggesting the specific post of that title never existed. (Incidentally, the Haskell Wiki contains a page for All About Monads, but it doesn't seem as though Brent Yorgey was a contributor).
This process repeated with 3-4 different suggestions. It would have a monad related title, the name of a notable Haskell practitioner, and a link that seemed link it should work. And yet the link would be broken. In one case, it gave the title of Monads for the Working Haskell Programmer but attributed this work to Bartosz Milewski (instead of Theodore Newell, plainly listed as the author at the top of the page) along with an incorrect link (I found the correct link after googling the title).
I would have expected the bot to check links before supplying them, so this was definitely surprising behavior.
I also tried to push the boundaries and see if it could write a code-based tutorial for me. It would start writing some promising looking code, but eventually the whole thing would get deleted! Perhaps the code was getting too long and I was getting rate limited, I'm not sure. I'll experiment more with having it write code in the coming weeks.