Skip to content

Instantly share code, notes, and snippets.

@parsonsmatt
parsonsmatt / dont-use-hkd.md
Last active August 3, 2023 01:14
Another Failed HKD Attempt

Why not use HKD for the Esqueleto Records?

The most recent patch to esqueleto creates another datatype for esqueleto records: a Maybe variant, used when the table is introduced in a left join. This brings the record count up to three:

data Dog = Dog
    { name      :: String
    , age       :: Maybe Int
    , person    :: Maybe (Entity Person)
@parsonsmatt
parsonsmatt / MutDef.hs
Created November 29, 2022 19:02
How to redefine functions in Haskell, based on Hillel's article here: https://buttondown.email/hillelwayne/archive/i-am-disappointed-by-dynamic-typing/
{-# language BangPatterns #-}
module MutDef where
import Data.IORef
import System.IO.Unsafe
import Data.Map (Map)
import qualified Data.Map as Map
import GHC.Exts
-- Dependency injection using a record-of-functions, but no ReaderT.
--
-- Download in an empty folder, then run with:
--
-- $ cabal install --lib --package-env . dep-t-0.4.4.0
-- $ runghc Main.hs
--
-- Some interesting aspects:
--
-- - No ReaderT transformer! Just plain functions (wrapped in helper datatypes).
{-# language OverloadedLists #-}
{-# OPTIONS_GHC -Wall #-}
module Overlays where
import Prelude hiding ((.))
import GHC.Stack
import Debug.Trace
liftType :: forall t. Typeable t => Q Type
liftType = do
let rep = typeRep @t
go rep
where
go :: forall (a :: k). TypeRep a -> Q Type
go tr =
case tr of
Con tyCon -> do
let
{-# 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 01:45
haskell database library comparison

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 February 21, 2020 18:54
Compatibility function to make MonadUnliftIO and MonadBaseControl IO work together
{-
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 February 7, 2020 21:32
What's goin on with my skolems
-- 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 August 6, 2019 21:14
How long is your Template Haskell taking to run?
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