packages feed

bidirectional-instances-0.1.0.0: examples/Example1TH.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

{-
  This module contains solution for example from "Bidirectional type instances"
  by Koen Pauwels, Georgios Karachalias, Michiel Derhaeg and Tom Schrijvers
  (https://arxiv.org/pdf/1906.12242.pdf), using this package
-}

module Example1TH where

import Data.Kind (Constraint, Type)
import Control.Bidirectional ( Bidirectional, makeBidirectionalInstances, BidirectionalRec ) 

data Term :: Type -> Type where
  Con :: a -> Term a
  Tup :: Term b -> Term c -> Term (b, c)

{-
-- Fails to type check:
instance Show a => Show (Term a) where
  show (Con x) = show x
  show (Tup x y) = unwords ["(", show x, ",", show y, ")"]
-}

{-
  Some kind of solution using modern haskell without new extensions
-}

-- provide instances for which we want bidirectional constraints
makeBidirectionalInstances [d|
    instance (Show b, Show c)  => Show (b, c)
  |]

-- then the following typechecks
instance BidirectionalRec Show a => Show (Term a) where
  show (Con x) = show x
  show (Tup x y) = unwords ["(", show x, ",", show y, ")"]

-- of course we can also provide Bidirectional Show instance for Term, but it 
-- isn't  necessary, unless we want to have bidirectional constraint for it