Engineer built Fame Boy, a working Game Boy emulator in F# with sound, running on both desktop and web after hundreds of hours.
Key Takeaways
Architecture separates emulator core from frontends via two arrays (framebuffer, audiobuffer) and two functions, enabling desktop and web targets.
F# discriminated unions reduced 512 raw opcodes to 58 typed instructions; separate From/To types enforce hardware-legal states at compile time.
Mutability was adopted pragmatically: copying 16+ kB of memory per CPU cycle was too costly, unlike the pure CHIP-8 predecessor Fip-8.
A 16-line Flags module using inline pure functions replaced a DU-based setFlags array approach and improved emulator FPS by ~10%.
AI was used only for generating CPU test cases from specs, keeping implementation learning intact while catching bugs in existing instructions.
Hacker News Comment Review
Commenters broadly praised the F# type modeling, with specific technical feedback that struct discriminated unions ([<Struct>]) could further reduce allocations in Instructions.fs.
F#’s performance ceiling for interpreter-style workloads came up as a known tradeoff; the author’s pragmatic shift to mutability is consistent with community experience.
A thread of sentiment emerged around F# being permanently overshadowed by C# in the .NET ecosystem, limiting library ergonomics for idiomatic F# use.
Notable Comments
@debugnik: Flags registers typed as byte make the &&& 0xFFuy mask in setters redundant; suggests [<Struct>] DUs to cut allocations.
@redrobein: F# library ecosystem is largely C# handmedowns with no F#-specific docs, limiting idiomatic development.