Skip to content

Instantly share code, notes, and snippets.

Avatar

Matt Parsons parsonsmatt

View GitHub Profile
View provide.hs
{-# language TypeApplications, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}
{-# language DataKinds, RankNTypes, PolyKinds, ScopedTypeVariables, GADTs, UndecidableInstances, TypeOperators #-}
{-# language ConstraintKinds #-}
module CatchR where
import Control.Monad.Reader
import Control.Monad.Except
to :: Reader (r, rest) a -> (r -> Reader rest a)
@parsonsmatt
parsonsmatt / dbcomp.markdown
Created May 28, 2020
haskell database library comparison
View dbcomp.markdown

there's kind of a ladder of complexity, where you have safety vs complexity vs how much to learn vs what the lib does for you. hasql and postgresql-simple have a 1 on safety and "what the lib does for you" but also have a 1 on complexity and how much to learn. if you know SQL, you can write raw string queries. But you also don't get any safety or migrations or composability. persistent is a 2 on the "how much to learn", and around a 3 on "how much it does for you." You get migrations, datatype definitions, very safe easy/common-case functions. The functions it gives you are perfectly safe, but you need to use esqueleto or raw SQL for fancy stuff so it's like 3 on safety. There's not a huge amount to learn, maybe it's a 2 here. esqueleto is a lot more powerful, but requires a lot more learning - so it's like a 4 on what it does for you and a 3 on how much to learn. It's not perfectly safe, but it does more safely than persistent, so it gets a 4. beam is complicated and difficult to learn. It has a 5 on how m

@parsonsmatt
parsonsmatt / mbc.hs
Created Feb 21, 2020
Compatibility function to make MonadUnliftIO and MonadBaseControl IO work together
View mbc.hs
{-
Oh no! You're lost in a twisty maze of IO lifting and unlifting, and you've come to
an impossible fork: you're currently in some monad that is `MonadBaseControl IO m`,
but you need to call a function in `MonadUnliftIO`. AND you need to call functions
in your original monad transformer, too!
We can make this work, but it's a bit hairy.
MonadUnliftIO is a strictly less powerful type class than `MonadBaseControl IO`, so
@parsonsmatt
parsonsmatt / skolem.hs
Created Feb 7, 2020
What's goin on with my skolems
View skolem.hs
-- This reproduction can be played with using `ghcid --allow-eval`
{-# language RankNTypes #-}
import Control.Monad.ST
newtype IdT m a = IdT { unIdT :: m a }
-- $> :set -XRankNTypes
--
@parsonsmatt
parsonsmatt / timestamp.hs
Created Aug 6, 2019
How long is your Template Haskell taking to run?
View timestamp.hs
timestamp :: String -> Q a -> Q a
timestamp name action = do
start <- runIO getCurrentTime
runIO $ putStrLn $ "Starting " <> name <> ": " <> show start
a <- action
end <- runIO getCurrentTime
runIO $ do
putStrLn $ "Ending " <> name <> ": " <> show end
putStrLn $ "Elapased " <> name <> ": " <> show (diffUTCTime end start)
pure a
View drf.hs
{-# language DuplicateRecordFields, TypeApplications #-}
module DuplicateRecordFields where
data User = User { name :: String }
data Dog = Dog { name :: String }
-- Works
nameAlias :: User -> String
nameAlias = name
View log.hs
{-# LANGUAGE TypeApplications, GADTs, FlexibleInstances, OverloadedLists #-}
module History where
import Lib
import Control.Monad (join)
import qualified Data.Map as Map
import Data.Map (Map)
import qualified Data.List.NonEmpty as NEL
import Data.List.NonEmpty (NonEmpty(..))
View setisnotafunctor.hs
{-# LANGUAGE DeriveFunctor #-}
module SetIsNotAFunctor where
import Data.Set (Set)
import qualified Data.Set as Set
-- | A type for annotating a value where equality and ordering only care
-- about the value.
data Ann ann a = Ann { annotation :: ann, value :: a }
View animal2.sql
-- We're modeling the following Haskell datatype:
--
-- data Animal = Cat Name Age | Dog Name OwnerId
--
-- We're going to factor the common 'Name' field into the animal table.
--
-- The data that is specific for each field will go on a table with that field.
-- First we create the animal_type.
CREATE TYPE animal_type AS ('cat', 'dog');
View animal.sql
-- First we create the animal_type.
CREATE TYPE animal_type AS ('cat', 'dog');
-- Then we create the animal table with a primary key consisting of an
-- auto-incremented integer and the animal type.
CREATE TABLE animal (
id SERIAL NOT NULL,
type animal_type NOT NULL,
PRIMARY KEY (id, type),
You can’t perform that action at this time.