How to constrain type family to Show - haskell

I'm currently working on an interpreter, which should be able to handle multiple variations of a language.
Therefore I'm designing my AST with type families (a simple example is given below).
How do I tell GHC that my type families need to have Show (and Eq) instances?
I have tried to use StandaloneDeriving, but can't find out how to define the dependency/ constraint.
-- Types.hs
{-# LANGUAGE TypeFamilies #-}
module Types where
data Statement v = CommonStatement (CommonStatement v)
| VariantStatement (VariantStatement v)
deriving (Show)
data CommonStatement v = Skip deriving (Show)
data family VariantStatement v
-- Coroutine.hs
{-# LANGUAGE TypeFamilies #-}
module Coroutine (module Coroutine, module Types) where
import Types
newtype Coroutine = Coroutine [Statement Coroutine]
data instance VariantStatement Coroutine = SomeStatement deriving (Show)
When trying to build this (with stack and resolver lts-16.16), it fails since it can't deduce an instance of Show for (VariantStatement v):
• No instance for (Show (VariantStatement v))
arising from the first field of ‘VariantStatement’
(type ‘VariantStatement v’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Show (Statement v))
|
7 | deriving (Show)
| ^^^^

This is basically just a matter of chasing down and squashing the errors:
{-# LANGUAGE TypeFamilies, StandaloneDeriving, UndecidableInstances #-}
main= print SomeStatement
data Statement v
= CommonStatement (CommonStatement v)
| VariantStatement (VariantStatement v)
-- StandaloneDeriving and UndecidableInstances
-- are required for this one.
deriving instance Show (VariantStatement v) => Show (Statement v)
data CommonStatement v = Skip deriving (Show)
data family VariantStatement v
newtype Coroutine = Coroutine [Statement Coroutine]
data instance VariantStatement Coroutine = SomeStatement deriving Show

Related

Deriving Show Instance for ADT not working with Higher Kinded Type Families

I was just working through Chris Done's ADT with default example gist available here and ran into a problem: my ADT, with fields defined by higher kinded type families, is not working with a deriving show instance. GHC is telling me I need to derive a Show instance for a Type Family, but I'm not sure how to do. Here's what I have, so far, any comments would be helpful.
In the following example (using ghc 8.8.1), the objective is to define an instance of Show for ShowMe, using derive if possible.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE ConstraintKinds #-}
data Tag = A | B deriving (Show)
type family TF (p :: Tag) a where
TF 'A a = ()
TF 'B a = a
data ShowMe p = ShowMe
{ a :: !(TF p String)
, b :: String
}
main = connect showMeDefaults { a = "some string" }
where
connect :: ShowMe B -> IO ()
connect _ = pure ()
showMeDefaults :: ShowMe A
showMeDefaults = ShowMe { a = (), b = "asdf" }
-- This works to define Show
{-
instance Show (ShowMe p) where
show _ = "hello"
-}
-- This instance is the line that causes an error
deriving instance Show (ShowMe p)
Subsequently, I'm getting an error that I'm not familiar with from GHC:
show_tf.hs:35:1: error:
• No instance for (Show (TF p String))
arising from a use of ‘showsPrec’
• In the first argument of ‘(.)’, namely ‘(showsPrec 0 b1)’
In the second argument of ‘(.)’, namely
‘((.)
(showsPrec 0 b1)
((.)
GHC.Show.showCommaSpace
((.)
(showString "b = ") ((.) (showsPrec 0 b2) (showString "}")))))’
In the second argument of ‘(.)’, namely
‘((.)
(showString "a = ")
((.)
(showsPrec 0 b1)
((.)
GHC.Show.showCommaSpace
((.)
(showString "b = ") ((.) (showsPrec 0 b2) (showString "}"))))))’
When typechecking the code for ‘showsPrec’
in a derived instance for ‘Show (ShowMe p)’:
To see the code I am typechecking, use -ddump-deriv
|
35 | deriving instance Show (ShowMe p)
If we recompile, using the ghc -ddump-deriv, the following is returned:
[1 of 1] Compiling Main ( show_tf.hs, show_tf.o )
==================== Derived instances ====================
Derived class instances:
instance GHC.Show.Show Main.Tag where
GHC.Show.showsPrec _ Main.A = GHC.Show.showString "A"
GHC.Show.showsPrec _ Main.B = GHC.Show.showString "B"
Derived type family instances:
==================== Filling in method body ====================
GHC.Show.Show [Main.Tag]
GHC.Show.show = GHC.Show.$dmshow #(Main.Tag)
==================== Filling in method body ====================
GHC.Show.Show [Main.Tag]
GHC.Show.showList = GHC.Show.$dmshowList #(Main.Tag)
Linking show_tf ...
Conceptually, I think what I should be able to derive a Show instance for TF, but when I do that, I get the following:
show_tf.hs:36:31: error:
• Illegal type synonym family application ‘TF 'A a’ in instance:
Show (TF 'A a)
• In the stand-alone deriving instance for
‘(Show a) => Show (TF 'A a)’
|
36 | deriving instance (Show a) => Show (TF 'A a)
This error also appears if I just try to define the Show instance myself for TF 'A a. I've searched "Illegal type synonym", and haven't come up up with a way around this.
You need to add
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
and then suggest the wanted context to GHC:
deriving instance Show (TF p String) => Show (ShowMe p)
GHC won't add that context automatically since it can be surprising to the programmer.

How can I implement fromJSON on a GADT with custom type class constraints?

I have the following GADT:
{-# LANGUAGE GADTs #-}
data LogProtocol a where
Message :: String -> LogProtocol String
StartRun :: forall rc. (Show rc, Eq rc, Titled rc, ToJSON rc, FromJSON rc)
=> rc -> LogProtocol rc
... and many more...
toJSON is straight forward and not shown.
fromJSON implementation is based on:
This SO Question and
This Blog Post - pattern 2
and is as follows:
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
-- tag type is used in to/ from JSON to reduce the use of magic strings
data LPTag = MessageT |
StartRunT |
... and many more...
deriving (Show, Eq, Enum)
tagList :: Enum a => [a]
tagList = enumFrom $ toEnum 0
$(deriveJSON defaultOptions ''LPTag)
-- a wrapper to hide the a type param in the GADT
data Some (t :: k -> *) where
Some :: t x -> Some t
instance FromJSON (Some LogProtocol) where
parseJSON :: Value -> Parser (Some LogProtocol)
parseJSON v#(Object o) =
let
tag :: Maybe LPTag
tag = do
t <- (HML.lookup "type" o)
parseMaybe parseJSON t
failMessage :: [Char]
failMessage = toS $ "Could not parse LogProtocol no type field or type field value is not a member of specified in: "
<> (show(tagList :: [LPTag]))
<> show v
in
maybe
(fail failMessage )
(
\case
MessageT -> Some <$> (Message <$> o .: "txt")
StartRunT -> Some <$> (StartRun <$> o .: "runConfig")
)
tag
parseJSON wrng = typeMismatch "LogProtocol" wrng
The case for '''Message''' is fine. The problem I am having are errors such as:
* No instance for (Titled x2) arising from a use of `StartRun'
* In the first argument of `(<$>)', namely `StartRun'
In the second argument of `(<$>)', namely
`(StartRun <$> o .: "runConfig")'
In the expression: Some <$> (StartRun <$> o .: "runConfig")
Anywhere I have my own type class constraints (such as Titled)
in the data constructor the compiler says "No".
Is there a way to resolve this?
Existential types are an antipattern, especially if you need to do deserialization. StartRun should contain a concrete type instead. Deserialization requires a concrete type anyway, hence you might as well specialize StartRun to it.

Haskell: deriving Show for Fix types

I'm trying to implement a recursive datatype using recursion-schemes. I would like to be able to print it.
import Data.Functor.Foldable
data T1F a = Foo deriving Show
type T1 = Fix T1F
data T2 = Bar T1 deriving Show -- error here
Error message:
No instance for (Data.Functor.Classes.Show1 T1F)
arising from the first field of ‘Bar’ (type ‘T1’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (Show T2)
How do I make T1 derive Show?
Using the package deriving-compat:
{-# LANGUAGE TemplateHaskell #-}
import Data.Functor.Foldable
import Text.Show.Deriving
data T1F a = Foo deriving Show
$(deriveShow1 ''T1F)
type T1 = Fix T1F
data T2 = Bar T1 deriving Show

How to make lenses for records with type-families [duplicate]

This question already has answers here:
How to derive instances for records with type-families
(2 answers)
Closed 6 years ago.
Here's what I've got, which is not compiling:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
import Data.Text as T
import Data.Int (Int64)
import Control.Lens
type family Incoming validationResult baseType
type instance Incoming Validated baseType = baseType
type instance Incoming ValidationErrors baseType = Either [T.Text] baseType
data Validated
data ValidationErrors
data Tag = Tag {unTag :: T.Text} deriving (Eq, Show)
data NewTag f = NewTag
{
ntClientId :: Incoming f Int64
, ntTag :: Incoming f Tag
}
$(makeLensesWith abbreviatedFields ''NewTag)
Compilation error:
27 3 error error:
• Illegal type synonym family application in instance:
Incoming f_a1Kvx Int64
• In the instance declaration for
‘HasClientId (NewTag f_a1Kvx) (Incoming f_a1Kvx Int64)’ (intero)
27 3 error error:
• Illegal type synonym family application in instance:
Incoming f_a1Kvx Tag
• In the instance declaration for
‘HasTag (NewTag f_a1Kvx) (Incoming f_a1Kvx Tag)’ (intero)
The problem here is that makeLensesFor will try to generate an instance as follows:
instance HasClientId (NewTag f) (Incoming f Int64) where
....
This, however, is an error because you cannot create an instance for the result of a type family application. To avoid this, we can write the instance manually for each of the two possible choices for f:
-- generate lenses _foo for each record selector foo
-- (in this case, generates _ntClientId and _ntTag lenses)
makeLensesWith (lensRules & lensField .~ mappingNamer (\x -> ['_' : x])) ''NewTag
class HasClientId s a | s -> a where
clientId :: Lens' s a
instance HasClientId (NewTag Validated) Int64 where
clientId = _ntClientId
instance HasClientId (NewTag ValidationErrors) (Either [T.Text] Int64) where
clientId f a = f (ntClientId a) <&> \ntClientId' -> a { ntClientId = ntClientId' }
class HasTag s a | s -> a where
tag :: Lens' s a
instance HasTag (NewTag Validated) Tag where
tag = _ntTag
instance HasTag (NewTag ValidationErrors) (Either [T.Text] Tag) where
tag = _ntTag

Constraining the return type to a Context

Here are my attempts so far:
module Main where
data FooT = One | Two deriving (Show, Read)
{-
That is what I want
foo :: (Show a, Read a) => a
foo = One
-}
--class Footable (Show a, Read a) => a where
class Footable a where
--foo2 :: (Show a, Read a) => a
foo2 :: a
instance Footable FooT where
foo2 = One
-- test = print foo2
I want test to compile. I don't think the problem revolves around universal quantification. ghc says that a is a 'strict type-variable' edit (rigid type variable) but I don't really comprehend what this is. The question seems to be related to this
Edit
As I wrote in my comment #sepp2k it's probably about the existential type but I have stumbled over a curious behaviour:
This does compile:
{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverlappingInstances,
UndecidableInstances, MonomorphismRestriction, PolymorphicComponents #-}
{-# OPTIONS_GHC -fno-monomorphism-restriction #-}
module Main where
class (Num a) => Numable a where
foo2 :: a
instance (Num a) => Numable a where
foo2 = 1
instance Numable Int where
foo2 = 2
instance Numable Integer where
foo2 = 3
--test = foo2 + foo2 -- This does NOT compile (ambiguous a)
test = (foo2::Integer) + foo2 --this works
but this does not (`a' is a rigid type variable message)
{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverlappingInstances,
UndecidableInstances, MonomorphismRestriction, PolymorphicComponents #-}
{-# OPTIONS_GHC -fno-monomorphism-restriction #-}
module Main where
data FooT = One | Two deriving (Show, Read)
data BarT = Ten deriving (Show, Read)
class (Show a, Read a) => Footable a where
foo2 :: a
instance (Show a, Read a) => Footable a where
foo2 = Ten
instance Footable FooT where
foo2 = One
main = print foo2
that's so because 1 :: (Num t) => t. Can I define something (typeconstructor, consts dunno) like that?
When I uncomment the definition of test and try to compile your code, I get "ambiguous type variable". Nothing about strictness. To understand why this is ambiguous consider this:
module Main where
data FooT = One | Two deriving (Show, Read)
data BarT = Three | Four deriving Show
class Footable a where
foo2 :: a
instance Footable FooT where
foo2 = One
instance Footable BarT where
foo2 = Three
main = print foo2 -- Should this print One or Three?
Of course in your code there is only one instance of Footable, so haskell could in theory infer that you want to use the foo2 defined for FooT because that's the only instance in scope. However if it did that, the code would break as soon as you import a module that happens to define another instance of Footable, so haskell doesn't do that.
To fix your problem you need to annotate foo2 with its type like so:
module Main where
data FooT = One | Two deriving (Show, Read)
class Footable a where
foo2 :: a
instance Footable FooT where
foo2 = One
main = print (foo2 :: FooT)
To require that all Footables be instances of Show and Read simply do:
class (Show a, Read a) => Footable a where
foo2 :: a
Like you did in your comments, but without specifying the constraint again in the signature of foo2.
As sepp2k said, Ghc can't guess the return type of foo2. Do constraint it (which is the title of your question) add an inline type signature.
test = print (foo2 :: FooT)

Resources