A Haskell developer has built a simple to-do app using GTK 4 and the Adwaita library, and the tutorial explains how to manage a model, handle messages, and build a view in the Elm architecture style, all while keeping the code easy for intermediate Haskellers to follow.
The Empty Window
The tutorial starts with a minimal window. The developer creates an Adwaita “Application” object that handles resources, including Adwaita stylesheets. The code snippet below sets up the window with a title, size, and a toolbar:
haskell
app <- new Adw.Application [#applicationId := "tech.floreal.TodoApp"]
on app #activate (activate app)
Gio.applicationRun app Nothing
Inside the activate function, the window is created and shown:
haskell
window <-
new Adw.ApplicationWindow
[ #application := app
, #title := "Todos"
, #defaultWidth := 480
, #defaultHeight := 640
, #content := toolbar
]
Gtk.windowPresent window
That is the whole window, title, and dimensions.
Elm Architecture in Haskell
The tutorial explains the Elm Architecture through three concepts: Model, View, and Update. The Model holds the app’s state, the View turns the Model into a user interface, and the Update function changes the Model based on Messages. The code uses data types to represent the state and actions.
Here is how the state is defined:
“`haskell
newtype TodoId = TodoId Word
deriving stock (Show)
deriving newtype (Eq, Ord)
data Todo = Todo
{ id :: TodoId
, title :: Text
, done :: Bool
}
deriving stock (Eq, Show)
data Model = Model
{ todos :: Map TodoId Todo
, nextId :: TodoId
}
deriving stock (Eq, Show)
“`
Messages are represented as a known set of user interactions:
haskell
data Message
= Add Text
| SetDoneStatus TodoId Bool
deriving stock (Eq, Ord)
The update function takes a Message and a Model, then returns a new Model and a list of Effects. The Effects represent actions like saving the to-do list to disk.
Testing in GHCi
The tutorial encourages readers to test the code in GHCi, the Haskell interpreter. Here is how a session might look:
ghci
ghci> let (m1, e1) = update (Add "Buy leeks") init
ghci> e1
[Save [Todo {id = TodoId 0, title = "Buy leeks", done = False}]]
Then the status is changed:
ghci
ghci> let (m2, e2) = update (SetDoneStatus (TodoId 0) True) m1
ghci> e2
[Save [Todo {id = TodoId 0, title = "Buy leeks", done = True}]]
Setting the status back to True produces no Effects, so the list stays empty.
What This Tutorial Gets Right
The tutorial’s strength is its clarity. It explains each piece of the Elm Architecture before showing the code, so the data types and functions land as explanations rather than mysteries. The use of data structures for messages and effects makes the app’s behavior visible at a glance.
The code is also clean. The update function is short and easy to follow, and the use of the withTodos helper keeps the code focused on what it is doing.
The tutorial is not trying to be a deep introduction to GTK or Haskell. It assumes readers know the basics and focuses on the architecture. That focus makes it a good entry point for developers who want to apply functional ideas to UI work.
The Bottom Line
This is a solid piece of technical writing. It explains a complex architecture in plain terms, backs it up with working code, and gives readers a clear path forward. The full code is available on GitHub at Floreal-Technologies/adwaita-todo.
For anyone curious about building apps in Haskell, this is a good place to start.
Key facts:
– Project: Making a GTK application in Haskell, part 1
– Author: Feriel Choutri de Tarlé
– Code: Available on GitHub at Floreal-Technologies/adwaita-todo
– Architecture: Elm-style Model-View-Update
– Libraries: GTK 4, Adwaita, haskell-gi
– Difficulty: Intermediate Haskell
Steps to follow:
1. Test the update function in GHCi.
2. Build your own small app using the same pattern.
Source material: “Making a GTK application in Haskell, part 1,” floreal.tech.
Get the Notebook.
The day's best stories and every fresh verdict, in plain English, in your inbox by seven. One email a day, no more.

