Skip to content

Instantly share code, notes, and snippets.

@LSLeary
LSLeary / Help.hs
Created September 19, 2025 07:22
Rebind xmonad's help command
module Help (helpAt) where
-- containers
import Data.Map.Strict (Map, (!))
import Data.Map.Strict qualified as M
-- xmonad
import XMonad hiding ((|||))
@LSLeary
LSLeary / Enumeration.hs
Created September 12, 2025 03:42
Church-encoded lists for constant-space enumeration (experimental)
{-# LANGUAGE RankNTypes, LambdaCase, BlockArguments #-}
module Enumeration (
Enumeration(..),
fromFoldable,
) where
-- GHC/base
import GHC.Exts (build)
-- base
@LSLeary
LSLeary / PrevLayout.hs
Created September 11, 2025 16:38
xmonad: switch to the previous layout (experimental)
module PrevLayout (prevLayout) where
import XMonad
import qualified XMonad.StackSet as W
prevLayout :: X ()
prevLayout = do
[email protected]{ W.current = [email protected]{ W.workspace = ws }} <- gets windowset
mp <- findPrev (description (W.layout ws)) (W.layout ws)
case mp of
@LSLeary
LSLeary / Free.hs
Last active August 22, 2025 10:56
The Church-encoded Higher-Order Free Monad for f
{-# LANGUAGE RankNTypes, QuantifiedConstraints, BlockArguments, LambdaCase #-}
module Free where
-- base
import Data.Coerce (coerce)
type f ~> g = forall x. f x -> g x
@LSLeary
LSLeary / Heap.hs
Last active August 4, 2025 14:28
A heap on poset keys. Neither the performance nor stability are good, but I doubt we can do much better.
{-# LANGUAGE RoleAnnotations, DerivingStrategies, LambdaCase #-}
module Heap (
Poset(..), Prefix(..),
Heap, size,
empty, singleton,
insert, (<+>), fromList,
pop, assocs,
) where
@LSLeary
LSLeary / Phases.hs
Last active August 2, 2025 07:53 — forked from sjoerdvisscher/Phases.hs
The Phases Applicative (but written as a heap)
{-# LANGUAGE GHC2021, LambdaCase, RoleAnnotations #-}
module Phases (Phases, runPhases, phase) where
-- To maintain the heap invariant according to @Ord k@, the type role of @k@
-- must be nominal, and @Phases@ must be opaque.
type role Phases nominal representational representational
data Phases k f a where
Pure :: a -> Phases k f a
Phase :: k -> (w -> x -> y -> z) -> f w -> Phases k f x -> Phases k f y
@LSLeary
LSLeary / GADTs That Can Be Newtypes and How to Roll 'Em.md
Last active July 28, 2025 14:33
GADTs That Can Be Newtypes and How to Roll 'Em, 2nd Revision

GADTs That Can Be Newtypes and How to Roll 'Em

I think many people know about Data.Some.Newtype⁠—⁠it uses quite a cute (and cursed) trick to encode a simple existential wrapper as a newtype, hence avoiding an unwanted indirection in the runtime representation.

But there's more to data than existentials⁠—⁠so how far do these tricks go? The answer is: surprisingly far! Let's see what other GADTs we can slim down.

Preliminaries

@LSLeary
LSLeary / ID.hs
Last active June 1, 2025 13:52
Catch and throw exceptions without Typeable constraints
{-# LANGUAGE GHC2021, RoleAnnotations #-}
module ID (
ID, newID,
sameID,
) where
-- base
import Unsafe.Coerce (unsafeCoerce)
import Data.Coerce (coerce)
{-# LANGUAGE GHC2021, BlockArguments, LambdaCase #-}
module Search (search) where
search :: Foldable f => (a -> Bool) -> f a -> Maybe a
search p = try . foldMap \x -> if p x
then Succeed x
else Fail
@LSLeary
LSLeary / LambdaEncodings.md
Last active February 18, 2025 22:19
Scott & Church Encodings

Scott & Church Encodings

Algebraic Data Types

It suffices to describe sums, products and their identities to obtain the full wealth of ADTs:

newtype a + b = Sum{ matchSum :: forall r. (a -> r) -> (b -> r) -> r) }

left :: a -> a + b