41554 blogs · [ { "id": "01a07df2-42f6-70ca-aaf9-89c3c6914d1b", "title": "Ditch your (mut)ex, you deserve better", "url": "https://chrispenner.ca/posts/mutexes", "published_at": "2025-11-11T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c72844cd", "title": "Exploring Arrows for sequencing effects", "url": "https://chrispenner.ca/posts/arrow-effects", "published_at": "2025-10-16T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c749204f", "title": "Monads are too powerful: The Expressiveness Spectrum", "url": "https://chrispenner.ca/posts/expressiveness-spectrum", "published_at": "2025-09-24T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c79f0e1e", "title": "You should add debug views to your DB", "url": "https://chrispenner.ca/posts/views-for-debugging", "published_at": "2025-08-13T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c7ffb258", "title": "Save memory and CPU with an interning cache", "url": "https://chrispenner.ca/posts/intern-cache", "published_at": "2025-08-12T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c8ec1488", "title": "Using traversals to batch database queries", "url": "https://chrispenner.ca/posts/traversals-for-batching", "published_at": "2025-08-11T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c9315e3e", "title": "Building Industrial Strength Software without Unit Tests", "url": "https://chrispenner.ca/posts/transcript-tests", "published_at": "2025-06-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c98ef82a", "title": "3 things other languages should steal from Unison", "url": "https://chrispenner.ca/posts/things-to-steal-from-unison", "published_at": "2025-04-24T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3c9ff8bf3", "title": "Building Type Search for Unison", "url": "https://chrispenner.ca/posts/unison-type-search", "published_at": "2024-08-14T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3ca9008ca", "title": "Simpler and safer API design using GADTs", "url": "https://chrispenner.ca/posts/gadt-design", "published_at": "2020-12-10T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cb0faec1", "title": "Virtual Record Fields Using Lenses", "url": "https://chrispenner.ca/posts/virtual-fields", "published_at": "2020-11-26T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cbea2257", "title": "Composable filters using Witherable optics", "url": "https://chrispenner.ca/posts/witherable-optics", "published_at": "2020-10-31T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cc642db4", "title": "Silly job interview questions in Haskell", "url": "https://chrispenner.ca/posts/interview", "published_at": "2020-10-14T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cd55e6a6", "title": "Generalizing 'jq' and Traversal Systems using optics and standard monads", "url": "https://chrispenner.ca/posts/traversal-systems", "published_at": "2020-09-27T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cd951927", "title": "Intro to Kaleidoscopes: Optics for aggregating data through Applicatives", "url": "https://chrispenner.ca/posts/kaleidoscopes", "published_at": "2020-02-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3ce8a5933", "title": "Algebraic lenses", "url": "https://chrispenner.ca/posts/algebraic", "published_at": "2019-12-18T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3ceef29c2", "title": "Advent of Optics: Day 4", "url": "https://chrispenner.ca/posts/advent-of-optics-04", "published_at": "2019-12-04T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cf7dce9d", "title": "Advent of Optics: Day 3", "url": "https://chrispenner.ca/posts/advent-of-optics-03", "published_at": "2019-12-03T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cfca5fe6", "title": "Advent of Optics: Day 2", "url": "https://chrispenner.ca/posts/advent-of-optics-02", "published_at": "2019-12-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3cfeec1a4", "title": "Advent of Optics: Day 1", "url": "https://chrispenner.ca/posts/advent-of-optics-01", "published_at": "2019-12-01T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d022a973", "title": "Beating C with 80 lines of Haskell: wc", "url": "https://chrispenner.ca/posts/wc", "published_at": "2019-10-15T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d0e5a132", "title": "Optics + Regex: Greater than the sum of their parts", "url": "https://chrispenner.ca/posts/lens-regex-pcre", "published_at": "2019-09-20T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d1750ac8", "title": "Slick 1.0 Release - Now with a quick and easy template!", "url": "https://chrispenner.ca/posts/slick-template", "published_at": "2019-09-18T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d26f2e21", "title": "Haskell IDE Support (hie-core lsp Sept. 2019)", "url": "https://chrispenner.ca/posts/hie-core", "published_at": "2019-09-07T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d367b8d0", "title": "Higher Kinded Option Parsing", "url": "https://chrispenner.ca/posts/hkd-options", "published_at": "2019-05-04T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d37d62f9", "title": "Mocking Effects using Constraints and Phantom Data Kinds", "url": "https://chrispenner.ca/posts/mock-effects-with-data-kinds", "published_at": "2018-09-29T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d431393d", "title": "Update Monads: Variation on State Monads", "url": "https://chrispenner.ca/posts/update-monad", "published_at": "2018-09-03T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d52b4358", "title": "Typesafe Versioned APIs", "url": "https://chrispenner.ca/posts/typesafe-api-versioning", "published_at": "2018-08-04T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d5b6963d", "title": "Monoidal Sorting", "url": "https://chrispenner.ca/posts/monoid-sort", "published_at": "2018-07-22T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d6574e92", "title": "A Practical Introduction to Finger Trees", "url": "https://chrispenner.ca/posts/intro-to-finger-trees", "published_at": "2018-07-21T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d6d58187", "title": "Postman API Explorer: You've got mail!", "url": "https://chrispenner.ca/posts/postman", "published_at": "2018-06-03T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d7ca35d5", "title": "Query a Google Sheets Spreadsheet from BigQuery", "url": "https://chrispenner.ca/posts/bigquery-sheets", "published_at": "2018-06-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d8847930", "title": "ASTs with Fix and Free", "url": "https://chrispenner.ca/posts/asts-with-fix-and-free", "published_at": "2018-02-24T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d8b60d4e", "title": "MonadIO Considered Harmful", "url": "https://chrispenner.ca/posts/monadio-considered-harmful", "published_at": "2017-09-11T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d9a6232b", "title": "Type Tac Toe: Advanced Type Safety", "url": "https://chrispenner.ca/posts/type-tac-toe", "published_at": "2017-08-25T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3d9f2c420", "title": "Conway's Game of Life using Representable and Comonads", "url": "https://chrispenner.ca/posts/conways-game-of-life", "published_at": "2017-08-08T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3da103bd4", "title": "Radix Sort, Trie Trees, and Maps from Representable Functors", "url": "https://chrispenner.ca/posts/representable-discrimination", "published_at": "2017-07-23T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3da832f89", "title": "Free and Forgetful Functors", "url": "https://chrispenner.ca/posts/free-forgetful-functors", "published_at": "2017-07-20T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3db113571", "title": "Adjunctions and Battleship", "url": "https://chrispenner.ca/posts/adjunction-battleship", "published_at": "2017-07-19T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3db5b4a3c", "title": "Zippers using Representable and Cofree", "url": "https://chrispenner.ca/posts/representable-cofree-zippers", "published_at": "2017-07-05T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3dc5a3350", "title": "Shipping Haskell via Homebrew", "url": "https://chrispenner.ca/posts/homebrew-haskell", "published_at": "2017-04-24T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3dc7ab308", "title": "Kleisli Endomorphisms", "url": "https://chrispenner.ca/posts/kleisli-endo", "published_at": "2017-04-08T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3dd611fec", "title": "Tail Recursion In Python", "url": "https://chrispenner.ca/posts/python-tail-recursion", "published_at": "2016-07-26T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3de006b64", "title": "The Interface We Need", "url": "https://chrispenner.ca/posts/dont-argue", "published_at": "2016-02-15T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3de2c10da", "title": "Let there be Truth", "url": "https://chrispenner.ca/posts/let-there-be-truth", "published_at": "2016-01-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3def416de", "title": "Autoenv Trick", "url": "https://chrispenner.ca/posts/auto-env-trick", "published_at": "2015-09-04T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3def9b2c6", "title": "Semantic Versioning", "url": "https://chrispenner.ca/posts/use-semantic-versioning", "published_at": "2015-04-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3df6c3e14", "title": "BoxKite: Open-Sourced", "url": "https://chrispenner.ca/posts/boxkite", "published_at": "2015-03-25T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3df8d2f82", "title": "Getting Schooled", "url": "https://chrispenner.ca/posts/getting-schooled", "published_at": "2015-03-19T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3dfa14175", "title": "Gem: Duckling", "url": "https://chrispenner.ca/posts/gem-duckling", "published_at": "2015-02-21T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e04a267c", "title": "Worth a Read #4 - Unix Tools", "url": "https://chrispenner.ca/posts/worth-a-read-4", "published_at": "2015-02-13T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e0d173c1", "title": "Vim vs. Emacs?", "url": "https://chrispenner.ca/posts/vim-vs-emacs", "published_at": "2015-02-06T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e11f1ac9", "title": "Gem: Font-Awesome", "url": "https://chrispenner.ca/posts/gem-font-awesome", "published_at": "2015-01-21T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e1ea0091", "title": "Worth a Read #3 - Typography", "url": "https://chrispenner.ca/posts/worth-a-read-3", "published_at": "2015-01-13T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e1ed74cc", "title": "Gem: Git", "url": "https://chrispenner.ca/posts/gem-git", "published_at": "2015-01-05T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e2867f7a", "title": "Procedural Generation is the Future", "url": "https://chrispenner.ca/posts/procedural-content", "published_at": "2015-01-03T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e2e7129f", "title": "Worth a Read #2 - CSS", "url": "https://chrispenner.ca/posts/worth-a-read-2", "published_at": "2014-11-10T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e398cfad", "title": "Gem: Jekyll", "url": "https://chrispenner.ca/posts/gem-jekyll", "published_at": "2014-11-03T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e42d5e72", "title": "Worth a Read #1", "url": "https://chrispenner.ca/posts/worth-a-read-1", "published_at": "2014-10-31T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e4f782ba", "title": "Gem: Neovim", "url": "https://chrispenner.ca/posts/gem-neovim", "published_at": "2014-10-15T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e533bf8e", "title": "You Own Your Data", "url": "https://chrispenner.ca/posts/you-own-your-data", "published_at": "2014-09-26T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e538b9e5", "title": "The Future of Software", "url": "https://chrispenner.ca/posts/modular-software", "published_at": "2014-09-24T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e5f05a22", "title": "Set the Data Free", "url": "https://chrispenner.ca/posts/set-the-data-free", "published_at": "2014-08-02T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e6efc8d5", "title": "Legacy in Design", "url": "https://chrispenner.ca/posts/legacy-in-design", "published_at": "2014-07-26T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e6ff0829", "title": "Caps-lock", "url": "https://chrispenner.ca/posts/capslock", "published_at": "2014-05-25T00:00:00+00:00" }, { "id": "01a07df2-42f6-70ca-aaf9-89c3e7e85e57", "title": "The Switch To Mac", "url": "https://chrispenner.ca/posts/switch-to-mac", "published_at": "2014-05-19T00:00:00+00:00" } ] posts Claim your blog
Back to Chris Penner
Blog · corpus.blog/blogs/chrispenner.ca/posts

Chris Penner

chrispenner.ca

2025

2024

2020

2019

2018

2017

2016

2015

2014