Skip to content

Instantly share code, notes, and snippets.

data CheckpointedException
= CheckpointedException
{ additionalContext :: BugsnagCtx
, locations :: NonEmpty Loc
, originalException :: SomeException
} deriving (Show, Typeable)
instance Exception CheckpointedException
copyCtxToEvent :: BugsnagCtx -> BugsnagEvent -> BugsnagEvent
@parsonsmatt
parsonsmatt / haskell-app-layers.md
Created December 11, 2017 15:48
A basic draft of a future blog post

The question of "How do I design my application in Haskell?" comes up a lot. There's a bunch of perspectives and choices, so it makes sense that it's difficult to choose just one. Do I use plain monad transformers, mtl, just pass the parameters manually and use IO for everything, the ReaderT design pattern, free monads, freer monads, some other kind of algebraic effect system?!

The answer is: why not both/all?

Lately, I've been centering on a n application design architecture with roughly three layers:

Layer 1:

newtype AppT m a = AppT { unAppT :: ReaderT YourStuff m a } deriving ............ The ReaderT Design Pattern, essentially. This is what everything gets boiled down to, and what everything eventually gets interpreted in. This type is the backbone of your app. For some components, you carry around some info/state (consider [MonadMetrics](https://hackage

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
import GHC.TypeLits
import Data.Proxy
newtype ModList (mod :: Nat) a = ModList { unModList :: [a] }
$ stack ghci --package case-insensitive
> import Data.CaseInsensitive as CS
> :set -XOverloadedStrings
> CI.mk "ß" == "SS"
True
λ> CI.mk "ß" == "ss"
True
λ> CI.mk "ß" == "s"
False
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module TyCon where
import GHC.Exts (Constraint)
@parsonsmatt
parsonsmatt / waterfall.hs
Created August 8, 2017 04:12
Waterfall in ST
module Waterfall.Base where
import Control.Monad.ST
import Data.Foldable (for_)
import Data.STRef
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as MU
rainfallBase :: [Int] -> Int
rainfallBase xs = sum (zipWith (-) mins xs)
@parsonsmatt
parsonsmatt / stack-8.2.1.yaml
Created July 23, 2017 20:10
ghc-8.2.1 stack yaml
compiler-check: match-exact
compiler: ghc-8.2.1
resolver: nightly-2017-07-21
setup-info:
ghc:
windows64:
8.2.1:
url: https://downloads.haskell.org/~ghc/8.2.1/ghc-8.2.1-x86_64-unknown-mingw32.tar.xz
sha1: bdede26c1a2cfcf4ebb08329853d285e32213b3d
content-length: 175053796
@parsonsmatt
parsonsmatt / repeats.hs
Last active June 25, 2017 17:20
repeats
-- me
skips :: [a] -> [[a]]
skips xs = zipWith takeEvery [1..length xs] (repeat xs)
takeEvery :: Int -> [a] -> [a]
takeEvery n xs
| n > length xs = []
| otherwise = xs !! (n-1) : takeEvery n (drop n xs)
-- the guy she tells me not to worry about
@parsonsmatt
parsonsmatt / Implicits.hs
Last active June 14, 2017 15:30
Implicit params instead of ReaderT
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE RankNTypes #-}
module Lib where
data Env = Env { envFoo :: Int, envBar :: String }
type App a = (?env :: Env) => IO a
someFunc :: IO ()
@parsonsmatt
parsonsmatt / garbage.sql
Created May 22, 2017 23:09
I hate MySQL
mysql> create table garbage (`why` enum('are', 'you') not null);
Query OK, 0 rows affected (0.16 sec)
mysql> insert into garbage values ('mysql'), ('hates'), ('you');
Query OK, 3 rows affected, 2 warnings (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 2
mysql> select * from garbage;
+-----+
| why |