Skip to content

Instantly share code, notes, and snippets.

@cdepillabout
Created April 13, 2018 16:30
Show Gist options
  • Save cdepillabout/2f7fe4581a915c6962747b275dddf7c0 to your computer and use it in GitHub Desktop.
Save cdepillabout/2f7fe4581a915c6962747b275dddf7c0 to your computer and use it in GitHub Desktop.
Example of how it is possible to override the functions that get called for a typeclass.
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
-- | This modules shows how it is possible to override the functions that get
-- called for a typeclass.
--
-- For instance, the 'foo' function overrides the '(<>)' function for
-- 'Semigroup', making it work differently for 'Sum' 'Int'.
module Magic2 where
import Data.Semigroup (Sum)
import Unsafe.Coerce
-- | This is a wrapper used in 'doMagic'
newtype Magic c r = Magic { unMagic :: c => r }
-- | This function is where the magic happens. The first argument is run with
-- the second argument passed as the typeclass dictionary.
doMagic :: forall c b r. (c => r) -> b -> r
doMagic r b =
let magic = Magic r :: Magic c r
in unsafeCoerce magic b
-- | This is a wrapper for the 'Semigroup' typeclass dictionary.
data MySemi a = MySemi { app :: a -> a -> a }
badMinusSemi :: MySemi (Sum Int)
badMinusSemi = MySemi (-)
-- This function is a wrapper around 'f' that calls it with a different '(<>)'
-- function.
--
-- >>> bar
-- Sum {getSum = 1}
bar :: Sum Int
bar = doMagic @(Semigroup (Sum Int)) (f 4 3) badMinusSemi
-- | This is a function that we want to run with a different typeclass
-- dictionary.
f :: forall a. Semigroup a => a -> a -> a
f a b = a <> b
@cdepillabout
Copy link
Author

Can be loaded into GHCi like the following:

stack --resolver nightly-2018-03-18 ghci

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment