Skip to content

Instantly share code, notes, and snippets.

View robrix's full-sized avatar
🌊
every dot and stroke I paint will be alive

Rob Rix robrix

🌊
every dot and stroke I paint will be alive
View GitHub Profile
@robrix
robrix / apomorphisms.hs
Created March 5, 2015 02:32
Apomorphisms in Haskell
newtype Term f = In { out :: f (Term f) }
-- The trivial one
type RCoalgebra1 f a = a -> f (Either (Term f) a)
apo1 :: Functor f => RCoalgebra1 f a -> a -> Term f
apo1 f = In . (fmap fanin) . f
where fanin = either id (apo1 f)
@robrix
robrix / init.js
Last active May 8, 2018 13:41
select-outside-brackets and select-scope commands, built using Bracket Matcher’s select-inside-brackets.
'use babel';
import {Range} from 'atom';
atom.commands.add('atom-text-editor', 'editor:select-outside-brackets', function () {
const editor = atom.workspace.getActiveTextEditor();
const initial = editor && editor.getSelectedBufferRange().freeze();
atom.commands.dispatch(editor.element, 'bracket-matcher:select-inside-brackets');
@robrix
robrix / Hammer.hs
Last active March 6, 2016 01:43
Parsing with Derivatives, via GADTs
data Parser a where
Cat :: Parser a -> Parser b -> Parser (a, b)
Alt :: Parser a -> Parser b -> Parser (Either a b)
Rep :: Parser a -> Parser [a]
Map :: Parser a -> (a -> b) -> Parser b
Bnd :: Parser a -> (a -> Parser b) -> Parser b
Lit :: Char -> Parser Char
Ret :: [a] -> Parser a
Nul :: Parser a
Eps :: Parser a
@robrix
robrix / 1. RFunctor.hs
Last active June 4, 2016 19:01
Recursive functors with some fiddling for type parameter order
-- Old friends.
newtype Fix f = Fix { unFix :: f (Fix f) }
data Free f a = Free (f (Free f a)) | Pure a
data Cofree f a = a :< f (Cofree f a)
-- A recursive functor. We can’t define a Functor instance for e.g. `Fix` because:
-- 1. Its type parameter is of kind (* -> *). Maybe PolyKinds could hack around this, I’ve not tried.
-- 2. Following from that, its type parameter is applied to `Fix f` itself, and thus `(f (Fix f) -> g (Fix g)) -> Fix f -> Fix g` would probably be a mistake too; we want to ensure that `Fix` recursively maps its parameter functor into the new type, and not leave that map the responsibility of the function argument.
class RFunctor f
where rmap :: Functor a => (a (f b) -> b (f b)) -> f a -> f b
@robrix
robrix / FieldSet.hs
Created June 2, 2016 23:06
Extensible field sets, inspired by @aaronlevin’s extensible effects in the Van Laarhoven free monad: http://aaronlevin.ca/post/136494428283/extensible-effects-in-the-van-laarhoven-free-monad
{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs, MultiParamTypeClasses, PolyKinds, TypeOperators #-}
module FieldSet where
infix 9 :=>
-- | We can probably replace this with a wrapper around `Tagged`.
newtype a :=> b = (:=>) b
deriving (Eq, Show)
-- | “Smart” (actually quite dumb) constructor for the tagged type above for convenience
field :: b -> a :=> b
@robrix
robrix / Main.hs
Created July 16, 2016 18:30
Recursive/Corecursive over F
{-# LANGUAGE DeriveFoldable, DeriveFunctor, FlexibleContexts, KindSignatures, RankNTypes, TypeFamilies #-}
module Main where
import Data.Bifunctor
newtype F f a = F { runF :: forall r. (a -> r) -> (f r -> r) -> r }
wrap :: Functor f => f (F f a) -> F f a
wrap f = F (\ p i -> i (fmap (\ (F r) -> r p i) f))
@robrix
robrix / Parametricity.txt
Last active June 12, 2018 20:13
Higgledy Piggledy — Parametricity
Higgledy piggledy
parametricity’s
quite a nice property
functions can use;
Enforcing the absence of
state or identity
up to the type level
promotes reuse.
@robrix
robrix / JoinMonoid.hs
Created September 2, 2016 15:50
Joining a foldable collection of Monoids by some separator element.
import Data.Maybe
import Data.Monoid
-- | Join a Foldable collection of Monoids by a separator element.
join :: (Monoid a, Foldable t) => a -> t a -> a
join sep = fromMaybe mempty . fst . foldr combine (Nothing, True)
where combine each (into, isFirst) = if isFirst
then (Just each, False)
else (Just each <> Just sep <> into, False)
@robrix
robrix / Bidi.hs
Last active January 30, 2025 02:53
Bidirectional type elaboration for the simply-typed lambda calculus with unit values & types.
{-# LANGUAGE DeriveFunctor #-}
module Bidi where
-- For 'guard'.
import Control.Monad
-- We use Cofree to represent type-annotated terms.
import Control.Comonad.Cofree
import Data.Functor.Classes
-- We use Fix to represent unannotated terms.
import Data.Functor.Foldable
@robrix
robrix / Constructor.hs
Last active January 21, 2017 21:29
Generically-derivable mechanism for producing predicates from datatype constructors
{-# LANGUAGE DefaultSignatures, DeriveAnyClass, StandaloneDeriving, TypeFamilies, TypeOperators #-}
module Constructor where
import Data.Function (on)
import GHC.Generics
import Prologue
-- | The class of types for which we can determine whether an inhabitant was constructed with some specific constructor.
--
-- Note that the provided instance for functions returning 'HasConstructor' types, @HasConstructor b => HasConstructor (a -> b)@, applies its first argument to 'undefined'. Thus, data types with strict fields cannot safely implement 'HasConstructor' instances, since they would diverge. If you really want to play with fire, then you’ll have to apply the constructors to any strict fields yourself on the left-hand side.