Concept → IO ()

Linux Emacs Coding Music Links About Search

Notes on MuniHac 2025 talks

MuniHac has happened again. I enjoyed it a lot. Below you can find my personal notes on the talks. Free free to contact me if you have any comments!

Rodrigo Mesquita: A modern step-through debugger for Haskell

[2025-09-12 Fri 11:30] Link to talk.

Rodrigo gives a pitch about haskell-debugger:

We also observe tail call optimization, a fundamental feature of functional languages, where no stack frame is created for intermediate function calls.

Gaël Deest: Hindsight - Type-safe, evolvable event sourcing

[2025-09-13 Sat 09:30] Event sourcing:

Drawbacks of event sourcing

Hindsight - The library

Other notes

Andrew Lelechenko: Linear Haskell for string builders

Link to talk.

String

Text

TextBuilder

Java-style string builder

data Buffer = Buffer {
    buffer :: ByteArray
  , used   :: Int
  }

(++) :: Buffer -> Text -> Buffer
(++) = ... -- Mutates buffer (`freeze . copy bytes . thaw`).

Unsafe! We can not just mutate buffers, we need to copy them somewhere else.

We can be honest about having a mutable buffer:

data MutBuffers s = MutBuffer {
    buffer :: MutableByteArray s
  , used   :: Int
  }

(++) :: MutBuffer s -> Text -> ST s (MutBuffer s)

Impractical. Can not be used with standard library functions.

Linear types

Instead of poisoning the context with ST, we would like to restrict our functions in that they can only use the buffer once.

First use hidden in attoparsec:

data Builder = Builder {
    gen    :: Int
  , buffer :: ByteArray -- Also stores the generation counter `gen` at start.
  , used   :: Int
  }

If somebody is tempering with the mutable buffer, one can detect it using the immutable generation counter gen. (Bryan o Sullivan).

Linear and unlifted types

data Buffer :: TYPE ('BoxedRep 'Unlifted) where
  Buffer :: {-# UNPACK #-} !Text -> Buffer

Combines idea of Java and attoparsec.

(Values of unlifted types are never bottom.)

appendBounded :: Int _> _ -> Buffer %1 -> Buffer
(>) :: Buffer %1 -> Text -> Buffer
runBuffer   :: (Buffer %1 -> Buffer) %1 -> Text
runBufferBS :: (Buffer %1 -> Buffer) %1 -> StrictByteString

%1 -> (also printed as lollipop arrow) means the old value becomes invalid, i.e., is mutated.

We wrap the Buffer type into an exposed Builder type we are used. Affects performance, again.

data Builder = Builder ) Buffer %1 -> Buffer )

fromText :: Text -> Builder
-- ...

Benchmarks show that the library linear-builder is extremely fast (especially the linear interface, not so much the builder interface).

Steve Shuck: The pcre2 regular expression library

In Haskell, it is currently too complicated to use regular expressions

Usage of pcre2

module Main (main) where

ipmort System.Exit      (die)
import Text.Regex.Pcre2

main :: IO ()
main = do
  let re = matchOpt (Caseless <> NotEmpty) "a*"

  case re "aa b Aaa" of
    []      -> die
    results -> print results

Compilation of expressions happens once and is stored in a lookup table. (But GHC is smart enough to reuse the compiled regular expressions anyways; i.e., the lookup is not even performed). That is, each regular expression is compiled only once, even when it is matched multiple times.

Also impressive, Steve provides Template Haskell splices:

Tommy Engström: domaindriven - Type-safe event sourcing in Haskell

This talk is a reply to the talk of Gaël Deest: Hindsight - Type-safe, evolvable event sourcing.

Tommy shows how he is handling events in Haskell. He uses servant, and domaindriven, a library he is developing.

If event types changes (e.g., a record is added), Tommy migrates all events in the store using a function with ShapeCoercible type class constraint. (You need to define how to shapeCoerce EventV1 to EventV2).

He also argues that the big downside of event sourcing is that the initial design is too important. Months into projects, we usually have collected knowledge about how the initial design can be improved, but major changes are difficult to implement when using event sourcing.

Joe Warren: How I use Haskell for 3D printing

How do 3D printers work:

We can construct objects using constructive solid geometry, a Boolean algebra for superimposing 3D shapes.

1991
OpenCascade release (Non-uniform rational B-spline, NURB).
2006
In anticipation of the expiration of the FDM patend, first projects start to design open 3D printers.
2009
FDM patent expires (most available 3D printers use this technology)
2010
OpenSCAD release.
2018
Joe writes CSG library.
2023
Waterfall CAD (bindings to OpenCascade).

Joe makes a point for using programmable CAD frameworks: Abstraction and code reuse.

Producing a number of Christmas logos from SVG images induced Jow to develop an SVG importer into Waterfall CAD, and and exporter from Waterfall CAD to SVG.

Mike Sperber: Six years of FUNAR - Teaching software architecture and functional programming to the uninitiated

Link to talk.

What is (specifically) functional software architecture?

Replies from MuniHac audience.

What is software architecture?

Functional design and architecture - Alexander Granin.

FUNAR module: Functional software architecture (iSAQB).

Structure and interpretation of computer programs (SICP) - Abelson, Sussman.

How to design programs - Felleisen, Findler, Flatt, Krishnamurthi.

Schreibe dein Programm - Sperber, Klaeren.

Software architecture in Haskell

Functional programming excels in data modeling:

For example, model the “Hearts” game.

The modulith - salvation for the monolith?

Structured design: Fundamentals of discipline of computer program and systems design - Yourdon, Constantine.

Managing, changing code is expensive. The more interdependencies/coupling you have in your code, the harder it is to change code. Optimize code to have low coupling.

Immutability, abstraction boundaries, expressive interface languages, expressive effects.

Functional software architecture

Conclusions

Questions/comments