Skip to content

Instantly share code, notes, and snippets.

@LSLeary
LSLeary / Poheap.hs
Created August 3, 2025 02:28
A heap on poset keys. Neither the performance nor stability are good, but I doubt we can do much better.
{-#
LANGUAGE
LambdaCase, RoleAnnotations, OverloadedStrings, DerivingStrategies
#-}
module Poheap (
Poset(..), Prefix(..),
Poheap, empty, singleton, (<+>),
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
@LSLeary
LSLeary / fragment.cabal
Created February 12, 2025 00:47
Structuring a cabal file so as to provide a unified `dev` component.
-- A demonstration, using a fragment of an unpublished library as-is.
-- Split out fields shared by all components into a common stanza:
common shared
build-depends: base
default-language: Haskell2010
default-extensions: ImportQualifiedPost
GeneralisedNewtypeDeriving
DerivingVia
DeriveTraversable
@LSLeary
LSLeary / EventManager.hs
Created January 21, 2025 16:07
A simple, functional event manager.
{-# LANGUAGE RankNTypes, PolyKinds, GeneralisedNewtypeDeriving #-}
module EventManager (
EventManager,
EventTag, eventTag,
attach, trigger,
) where
-- base
import Prelude hiding (lookup)
@LSLeary
LSLeary / Coercible.hs
Last active January 5, 2025 10:15
Generalised Coercible
-- These coercions could probably be generated automatically with a
-- type class and this plugin:
-- https://github.com/noughtmare/transitive-constraint-plugin
{-# LANGUAGE UnboxedTuples, UnliftedNewtypes, ExplicitNamespaces #-}
{-# LANGUAGE RoleAnnotations, DataKinds, QuantifiedConstraints #-}
module Coercible (
Coercible(..),
@LSLeary
LSLeary / Yoneda.hs
Last active February 4, 2025 04:00
A more general treatment of the Yoneda lemma than is given in Data.Functor.Yoneda.
{-# LANGUAGE GHC2021, BlockArguments #-}
module Yoneda where
import Prelude hiding (id, (.), map)
import Control.Category
-- Preliminaries
class (Category c, Category d) => ExoFunctor c d f where