/optionally

Primary LanguageHaskellBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

optionally

DISCLAIMER: NEVER USE THIS EXCEPT FOR FUN.

Require constraints Optionally. See this blog post for implementation details and limitations.

NOTE Works only with optimisations enabled so don't forget to pass -fobject-code -O if you want to test it in ghci.

Example:

class Foo
instance Foo

class Bar

class Slow a where
  slow :: a -> String
class Fast a where
  fast :: a -> String

instance Slow () where
  slow _ = "slow @()"

instance Slow Bool where
  slow _ = "slow @Bool"
instance Fast Bool where
  fast _ = "fast @Bool"

class Baz (a :: k)

instance Baz 1
instance Baz 'True

tryShow :: forall a . Show? a => a -> Maybe String
tryShow a = tryC @(Show a) $ show a

fastOrSlow :: forall a . (Slow a, Fast? a) => a -> String
fastOrSlow = orC @(Fast a) fast slow

nubSmart :: forall a . (Eq a, Ord? a) => [a] -> [a]
nubSmart a = orC @(Ord a) (trace "nubOrd" $ nubOrd a) (trace "nubEq" $ nub a)

nubForceEq :: forall a . Eq a => [a] -> [a]
nubForceEq = discard @(Ord a) nubSmart

nubForceOrd :: forall a . Ord a => [a] -> [a]
nubForceOrd = give @(Ord a) nubSmart

newtype NoOrd a = NoOrd a
  deriving stock (Show, Eq)
isSatisfied @Foo: True
isSatisfied @Bar: False
isSatisfied @(Baz 1): True
isSatisfied @(Baz 2): False
isSatisfied @(Baz 'True): True
isSatisfied @(Baz 'False): False
isSatisfied @(Show Int): True
isSatisfied @(Show [Int]): True
isSatisfied @(Show [Int -> Int]): False
isSatisfied @(Monad IO): True
isSatisfied @(MonadReader Int IO): False
isSatisfied @(MonadReader Int (ReaderT Int IO)): True

tryShow True: Just "True"
tryShow $ id @Bool: Nothing
tryShow (True, ()): Just "(True,())"
tryShow (True, id @Bool): Nothing

fastOrSlow (): "slow @()"
fastOrSlow True: "fast @Bool"

-- traces are printed too early but you got the idea

nubOrd
nubSmart [1, 2 :: Int]: [1,2]
nubEq
nubSmart [NoOrd 1, NoOrd 2 :: NoOrd Int]: [NoOrd 1,NoOrd 2]
nubOrd
nubForceOrd [1, 2 :: Int]: [1,2]
nubEq
nubForceEq [NoOrd 1, NoOrd 2 :: NoOrd Int]: [NoOrd 1,NoOrd 2]