Skip to content

Instantly share code, notes, and snippets.

@gallais
Created September 13, 2016 14:25
Show Gist options
  • Save gallais/3b7c7d9488b25978caa278bc18617f79 to your computer and use it in GitHub Desktop.
Save gallais/3b7c7d9488b25978caa278bc18617f79 to your computer and use it in GitHub Desktop.
Instance disambiguation using a type family
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PolyKinds #-}
module Provider2 where
import Data.Proxy
import Data.Type.Equality
data Location = IsLeft | IsRight | IsNone
class Provider a b (f :: Location) where
getInstance' :: Proxy f -> a -> b
type family If (b :: Bool) (l :: k) (r :: k) :: k where
If 'True l r = l
If 'False l r = r
type family Inspect t x :: Location where
Inspect (l, r) x = If (x == l) IsLeft (If (x == r) IsRight IsNone)
instance Provider r x (Inspect r x) => Provider (l, r) x 'IsNone where
getInstance' _ (l, r) = getInstance' (Proxy :: Proxy (Inspect r x)) r
instance Provider (l, r) l 'IsLeft where
getInstance' _ (l, _) = l
instance Provider (l, r) r 'IsRight where
getInstance' _ (_, r) = r
getInstance :: forall t x. Provider t x (Inspect t x) => t -> x
getInstance = getInstance' (Proxy :: Proxy (Inspect t x))
tryFunc1 :: Int
tryFunc1 =
let provider = ("test", (10, ())) :: (String, (Int, ()))
in getInstance provider
tryFunc2 :: String
tryFunc2 =
let provider = ("test", (10, ())) :: (String, (Int, ()))
in getInstance provider
tryFunc3 :: Int
tryFunc3 =
let provider = ("test", ((), 10)) :: (String, ((), Int))
in getInstance provider
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment