Skip to content

Instantly share code, notes, and snippets.

@jkarni
jkarni / pre-push
Last active December 20, 2015 16:09
Keep master safe.
#!/bin/bash
# Prompt before pushing to master. If it's a force push or delete, bail
# Don't be overly reliant on this, though; I'm not sure what the corner cases are.
# As usual, put this is .git/hooks directory, and make it executable with "chmod 755 pre-push"
# Requires git >= 1.8.3
PROT_BRANCH='master'
UNSAFE='force|delete|\-f'
CONFIRM_MSG="Pushing to master - are you absolutely sure you want to continue?"
@jkarni
jkarni / HUGSAug2014.md
Last active August 29, 2015 14:05
Polycephaly presentation source.

name: inverse layout: true class: center, middle, inverse

#Polycephaly Or, multiplying instance heads


The Problem


{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Typeable
import Data.Data
import Data.Proxy
import GHC.TypeLits
class PushReaderT a where
type PushReaderSubType a
unPushReaderT :: String -> PushReaderSubType a -> a
instance (PushReaderT b) => PushReaderT (a -> b) where
type PushReaderSubType (a -> b) = a -> PushReaderSubType b
unPushReaderT str f = unPushReaderT str . f
instance (PushReaderT a, PushReaderT b) => PushReaderT (a :<|> b) where
@jkarni
jkarni / gist:a710bf43931ad3bf6b92
Last active August 29, 2015 14:16
GetWithCookie
data GetWithCookie (a :: *)
type Short a = EitherT (Int,String) IO a
instance HasServer (GetWithCookie a) where
type Server (GetWithCookie a) = EitherT (Int,String) IO (a, ByteString) -- the ByteString is the cookie
route Proxy action request respond = do
e <- runEitherT (action)
respond . succeedWith $ case e of
-- completely untested
type MyEndpoint = "something" :> Get Int
class GetMethod a where
getMethod :: Proxy a -> String
instance GetMethod (Get x) where
getMethod _ = "GET"
performRequest' :: Method -> Req -> (Int -> Bool) -> BaseUrl -> EitherT ServantError IO (Int, ByteString, MediaType)
performRequest' reqMethod req isWantedStatus reqHost = do
partialRequest <- liftIO $ reqToRequest req reqHost
let request = partialRequest { Client.method = reqMethod
, checkStatus = \ _status _headers _cookies -> Nothing
}
eResponse <- liftIO $ __withGlobalManager $ \ manager ->

At first we had "Get a" [note that I'm going to be pretty loose about distinguishing type variables in Haskell and in the metalanguage]. OK, the "Get" part should be static - each endpoint can only "be" one method. The 'a' type can be anything, but in the description (i.e., the API type) it is static and that's fine, since these are algebraic data types, and can themselves represent sums and products of other things (in comparison, the method "place" for the endpoints is just a sum.)

So far we pretended status codes didn't need to be represented, because they could be statically determined by the method type. But of course that's bad HTTP practice - an empty body should probably cause a 204 No Content, for instance. So what we did was defined instances that overlapped on the method argument ("a" in "Get a"). Kind of ugly.

Then came content types. That turned out okay, because generally we're fine considering the acceptable content-types for and endpoint to be static. It would be more general to consider

-- first a separate class to interpret the access/permission DSL
class IsAccess a where
getAccess :: Proxy a -> Id -> Bool
-- ^ probably something quite different here. The two main options I see generally
-- are evaluating to some normal form (like AccessType) and not requiring Id, or
-- having Id and then directly evaluating to Bool
-- If you want to be allowed to require other values depending on the type (which I
-- think you do) you'd need an associated type synonym).
instance (IsAccess a, IsAccess b) => IsAccess (a :|| b) where
@jkarni
jkarni / show.hs
Last active September 3, 2015 00:32
{-# LANGUAGE ConstraintKinds #-}
module Main where
import Data.Constraint
show' :: (Maybe (Dict (Show a))) -> a -> String
show' (Just Dict) x = show x
show' Nothing _ = "<<not showable>>"
t1 = show' (Just Dict) 5