Skip to content

Instantly share code, notes, and snippets.

@Porges
Last active August 29, 2015 14:11
Show Gist options
  • Save Porges/b3a99df5eb540c126915 to your computer and use it in GitHub Desktop.
Save Porges/b3a99df5eb540c126915 to your computer and use it in GitHub Desktop.
what am untouchables?
{-# LANGUAGE TypeFamilies, ImplicitParams, OverloadedStrings, ConstraintKinds, ExistentialQuantification, RankNTypes, TypeOperators #-}
import GHC.Prim (Constraint)
import Data.String (IsString)
import qualified Data.Text as T
type family XString m
type family XDouble m
type m/f = f m -- cutesy syntax
type BasicModule m = (?basicOps :: BasicOperations m, Num (XDouble m), IsString (XString m))
data BasicOperations m =
BasicOperations
{
(+++!) :: m/XString -> m/XString -> m/XString,
xshowOp :: m/XDouble -> m/XString
}
(+++) :: (BasicModule m) => m/XString -> m/XString -> m/XString
(+++) = (+++!) ?basicOps
xshow :: (BasicModule m) => m/XDouble -> m/XString
xshow = xshowOp ?basicOps
data Person m =
-- This lets us write display without a constraint:
(BasicModule m) => Person
{
firstName :: m/XString,
lastName :: m/XString,
height :: m/XDouble
}
-- Inferred type signature is Person t -> String t! (Unlike original example)
display (Person firstName lastName height) = firstName +++ " " +++ lastName +++ " " +++ xshow (height + 1)
-- Inferred type here is slightly more general and lets us convert between modules as long as their datatypes are equal
-- not entirely sure why it's different...
display' p = firstName p +++ " " +++ lastName p +++ " " +++ xshow (height p + 1)
-- Prelude implementations:
data Prelude
type instance XString Prelude = String
type instance XDouble Prelude = Double
preludeOps :: BasicOperations Prelude
preludeOps =
BasicOperations
{
(+++!) = (++),
xshowOp = show
}
instance Show (Person Prelude) where
show = display
data Text
type instance XString Text = T.Text
type instance XDouble Text = Double
textOps :: BasicOperations Text
textOps =
BasicOperations
{
(+++!) = T.append,
xshowOp = T.pack . show
}
instance Show (Person Text) where
show = T.unpack . display
p :: (BasicModule m) => m/Person
p = Person "G" "P" 100
ps :: (BasicModule m) => m/XString
ps = display p
withText :: ((BasicModule Text) => t) -> t
withText x = let ?basicOps = textOps in x
withPrelude :: ((BasicModule Prelude) => t) -> t
withPrelude x = let ?basicOps = preludeOps in x
p' = withPrelude (display p +++ "!")
p'' = withText (display p +++ "!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment