Skip to content

Instantly share code, notes, and snippets.

View gelisam's full-sized avatar

Samuel Gélineau gelisam

View GitHub Profile
@gelisam
gelisam / ActionSetOptics.hs
Last active December 9, 2022 22:30
Representing optics by the set of actions they support.
-- An alternative representation of optics.
--
-- I represent an optic as the set of actions it supports. Composition
-- intersects the sets, which is how e.g. composing a Lens with a Prism gives a
-- Traversal.
{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs, KindSignatures, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeOperators, UndecidableInstances #-}
{-# OPTIONS -Wno-name-shadowing #-}
module Main where
import Test.DocTest
@gelisam
gelisam / FreeBubbleSort.hs
Created October 15, 2020 02:59
optimizing bubble sort using free monads
-- In response to https://twitter.com/chrislpenner/status/1315494889191161857
-- and https://twitter.com/drezil1985/status/1315495791243472896
--
-- The challenge is to implement bubble sort on lists... which makes no sense
-- at first glance, because bubble sort is defined in terms of swap operations,
-- which make little sense for lists!
{-# LANGUAGE DataKinds, FlexibleContexts, GADTs, MultiWayIf, QuantifiedConstraints, ScopedTypeVariables, TypeApplications, TypeOperators #-}
module Main where
import Test.DocTest
@gelisam
gelisam / ConfigurableMonadStack.hs
Created May 21, 2020 14:30
Using a runtime value to choose a monad transformer stack
-- in response to https://twitter.com/1akrmn/status/1263124698449272832
--
-- We have a polymorphic action which can be instantiated to multiple
-- transformer stacks, and the goal is to use a runtime value to
-- determine which monad transformer stack to use.
{-# LANGUAGE AllowAmbiguousTypes, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, QuantifiedConstraints, RankNTypes, StandaloneDeriving, TypeApplications, UndecidableInstances #-}
{-# OPTIONS -Wno-orphans #-}
module Main where
import Test.DocTest
@gelisam
gelisam / AssociativeParser.hs
Last active May 19, 2020 17:44
prototype parser with an associative <|>
-- A prototype demonstrating a possible fix for https://github.com/mrkkrp/megaparsec/issues/412
{-# LANGUAGE LambdaCase, TemplateHaskell #-}
{-# OPTIONS -Wno-name-shadowing #-}
module Main where
import Test.DocTest
import Control.Lens
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Reader
@gelisam
gelisam / ContextTransformers.hs
Last active April 24, 2020 03:40
deep pattern-matching in the finally-tagless style
-- How to convert an algorithm with deep pattern-matches into the
-- finally-tagless style in an extensible way; that is, in a way which makes it
-- possible to add a new constructor to the AST and corresponding cases to the
-- algorithm without modifying the code which has been written for the existing
-- constructors.
{-# LANGUAGE FlexibleInstances, LambdaCase, MultiParamTypeClasses #-}
module ContextTransformers where
import Test.DocTest
@gelisam
gelisam / DerivingViaSameShape.hs
Created April 23, 2020 15:59
using DerivingVia with types which are not representationally-equal
-- DerivingVia is great when you want to delegate to a type which is
-- representationally-equal, in the sense that we can use coerce to convert
-- between the two types. But what if you want to delegate to a type which has
-- the same representation in the other sense of having the same shape? Here's a
-- trick!
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
@gelisam
gelisam / FlameGraphDiff.hs
Created February 16, 2020 22:08
a simple algorithm to diff two flame graphs
-- in response to https://twitter.com/jfischoff/status/1228861734271647745
--
-- The challenge is to visualize the diff of two flame graphs. My idea is: we
-- need to draw both Trees in the same image, so we draw each node as the _sum_
-- of the two durations. The color of the node indicates whether the nodes above
-- it are slower or faster. Grey is "same speed", orange is "slower" (burns more
-- resources), and blue is "faster" (dousing the flames).
--
-- Note that I'm using a simple 'Tree' from the containers library, not whatever
-- is the real output from 'perf', so more work would be needed to make this
@gelisam
gelisam / StringPattern.hs
Created January 30, 2020 14:39
A Haskell reimplementation of Scala's "direct pattern-matching on strings"
-- in response to https://twitter.com/chrislpenner/status/1221784005156036608
--
-- The goal is to mimic this Scala code, but in Haskell:
--
-- > "spotify:user:123:playlist:456" match {
-- > case s"spotify:user:$userId:playlist:$playlistId"
-- > => ($userId, $playlistId) // ("123", "456")
-- > }
{-# LANGUAGE DeriveFunctor, LambdaCase, PatternSynonyms, QuasiQuotes, RankNTypes, TemplateHaskell, TypeOperators, ViewPatterns #-}
{-# OPTIONS -Wno-name-shadowing #-}
@gelisam
gelisam / LazyTypeLevelRepeat.hs
Created January 20, 2020 18:51
infinite lists at the type level
-- in response to https://twitter.com/xgrommx/status/1219310199342817283
--
-- The challenge is to write a type-level Repeat. Sounds easy, until you realize
-- that type-level computations are evaluated strictly, not lazily!
{-# LANGUAGE DataKinds, PolyKinds, TypeFamilies, TypeOperators, UndecidableInstances #-}
import GHC.TypeLits
-- We will use "defunctionalization" to work around the limitation that type
-- families cannot be partially-applied. A value of type (a ~> b) is not a fuction,
-- but it represents one particular function. Each time you define such a value, you
@gelisam
gelisam / FmapAt.hs
Created January 20, 2020 15:07
fmapping over the nth type parameter using n-ary-functor-1.0
-- in response to https://twitter.com/xgrommx/status/1218552046867156993
--
-- The goal is to implement a function (fmapAt @n) which fmaps over the nth
-- argument of an n-ary functor, like this:
--
-- >>> fmapAt @1 (+1) (0,0)
-- (1,0)
-- >>> fmapAt @2 (+1) (0,0)
-- (0,1)
-- >>> fmapAt @1 (+1) (0,0,0)