Haskell: deriving Show for Fix types - haskell

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

Related

How to constrain type family to Show

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

What is the difference between `DeriveAnyClass` and an empty instance?

Using the cassava package, the following compiles:
{-# LANGUAGE DeriveGeneric #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic)
instance ToNamedRecord Foo
However, the following does not:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord)
The compiler reports:
test.hs:7:50:
No instance for (ToNamedRecord Int)
arising from the first field of ‘Foo’ (type ‘Int’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (ToNamedRecord Foo)
This leaves me with two questions: Why isn't the second version identical to the first? And why is the compiler hoping to find an instance for ToNamedRecord Int?
NB: As pointed out by David in the comments, GHC has been updated since I wrote this. The code as written in the question compiles and works correctly. So just imagine everything below is written in the past tense.
The GHC docs say:
The instance context will be generated according to the same rules
used when deriving Eq (if the kind of the type is *), or the rules for
Functor (if the kind of the type is (* -> *)). For example
instance C a => C (a,b) where ...
data T a b = MkT a (a,b) deriving( C )
The deriving clause will
generate
instance C a => C (T a b) where {}
The constraints C a and C (a,b) are generated from the data constructor arguments, but the
latter simplifies to C a.
So, according to the Eq rules, your deriving clause generates...
instance ToNamedRecord Int => ToNamedRecord Foo where
... which is not the same as...
instance ToNamedRecord Foo where
... in that the former is only valid if there's an instance ToNamedRecord Int in scope (which is appears there isn't in your case).
But I find the spec to be somewhat ambiguous. Should the example really generate that code, or should it generate instance (C a, C (a, b)) => instance C (T a b) and let the solver discharge the second constraint? It appears, in your example, that it's generating such constraints even for fields with fully-concrete types.
I hesitate to call this a bug, because it's how Eq works, but given that DeriveAnyClass is intended to make it quicker to write empty instances it does seem unintuitive.

Haskell: How to make a type an instance of two typeclasses?

Is it possible to make Level an instance of Eq and Ord?
instance Eq Ord Level where
compare First Second = LT
...
I've tried this
instance (Ord, Eq) => Level where ...
But I've got an error
‘compare’ is not a (visible) method of class ‘Level’
I know I can use deriving (Eq) on my data Level. But I cannot change my data.
Use two instances
instance Eq Level where
x == y = ...
instance Ord Level where
compare x y = ...
Alternatively, use the standalone deriving extension:
{-# LANGUAGE StandaloneDeriving #-}
... -- ^^^^^^^^^^^^^^^^^^ must be at the top of the file
deriving instance (Eq Level)
deriving instance (Ord Level)

To what extent can I get Aeson to do the heavy lifting?

I'm trying to avoid writing definitions for toJSON. This is the error I encounter:
Datatypes.hs:92:10:
No instance for (aeson-0.6.0.2:Data.Aeson.Types.Class.GToJSON
(GHC.Generics.Rep (HashMap Key Project)))
arising from a use of `aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON'
Possible fix:
add an instance declaration for
(aeson-0.6.0.2:Data.Aeson.Types.Class.GToJSON
(GHC.Generics.Rep (HashMap Key Project)))
In the expression:
(aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON)
In an equation for `toJSON':
toJSON = (aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON)
In the instance declaration for `ToJSON (HashMap Key Project)'
I get similar errors for all my HashMap data declarations.
Here's the relevant code. Let me know if there is missing information.
{-# LANGUAGE DeriveGeneric #-} -- for JTask and Fields ToJSON instances:w!
{-# LANGUAGE DeriveDataTypeable #-} -- This may be needed for HashMaps
{-# LANGUAGE FlexibleInstances #-} -- for the HashMap ToJSON instances
{-# LANGUAGE DefaultSignatures #-}
import Prelude
import Data.ByteString
import GHC.Generics (Generic )
import Data.Data
import Data.Typeable (Typeable) -- fix HashMap ToJSON instances? maybe
import Data.Aeson
import Data.Aeson.Generic
import Data.Aeson.Types -- (ToJSON,FromJSON)
import Data.HashMap.Strict (HashMap)
data JTask = JTask {fields :: Fields} deriving (Typeable,Data,Generic)
data Fields = Fields { project :: HashMap Key Project
, summary :: ByteString
, issuetype :: HashMap Name Task
, versions :: [HashMap Name Version]
, description :: ByteString
} deriving (Typeable,Data,Generic)
data Key = Key deriving (Typeable,Data,Generic)
instance Show Key where
show Key = "key"
data Name = Name deriving (Typeable,Data,Generic)
instance Show Name where
show Name = "name"
data Task = Task deriving (Typeable,Data,Generic)
type Version = ByteString -- Placeholder type. Probably using Day for realsies.
data Project = BNAP deriving (Typeable,Data,Generic) -- Fill this out as we go
instance Generic (HashMap Key Project)
instance Data (HashMap Key Project)
--instance GToJSON (HashMap Key Project)
instance Generic (HashMap Name ByteString)
instance Data (HashMap Name ByteString)
instance Generic (HashMap Name Task)
instance Data (HashMap Name Task)
-- JSON instances
instance ToJSON CreateError
instance ToJSON Fields
instance ToJSON JTask
instance ToJSON Key
instance ToJSON Name
instance ToJSON Task
instance ToJSON Project
instance ToJSON (HashMap Key Project)
instance ToJSON (HashMap Name Task)
instance ToJSON (HashMap Name ByteString)
-- instance ToJSON Version uncomment when we change Version's type.
I cannot make an instance for Data.Aeson.Types.Class.GToJSON because Data.Aeson.Types.Class
is not exported. What are my options? What will I have to write manually? Is deriveJSON the best choice?
Update:
I implemented the suggestion below.
Here's the code
createObject :: CreateConf -> ResourceT IO Value
createObject (CreateConf iSummary iDesc dd) = do
let jfields = Fields {project = singleton Key BNAP
,summary = iSummary
,issuetype = singleton Name Task
,versions = [singleton Name (calcVersion dd)]
,description = iDesc
}
return $ toJSON (JTask jfields)
The first instance yields Object fromList [("key",Array (fromList []))])
Second instance yields Object fromList [("name",Array (fromList []))]
any idea why name and key are empty?
How could I find out?
Would it be easier to just use deriveJSON.
update:
Thanks to help from NathanHowell the more important problem has been solved, which is the GToJSON instance for unary types. The solution was to make my own instances for the unary types. The JSON objects are out of order, but I don't know if that matters. If it does, it seems another manual ToJSON instance for Fields would fix that.
update:
Okay a little context. I'm writing a JIRA front-end. I mention that because people in the future may come here to discover the following good news: JIRA doesn't care about Object order.
Aeson provides a ToJSON instance for HashMap String a. The easiest way to get things working is to use this instance by converting the HashMap keys to Strings. Just a touch of boilerplate and it uses the Generic instances for everything else.
{-# LANGUAGE DeriveGeneric #-} -- for JTask and Fields ToJSON instances:w!
{-# LANGUAGE FlexibleInstances #-} -- for the HashMap ToJSON instances
{-# LANGUAGE DefaultSignatures #-}
import Prelude
import Data.ByteString
import GHC.Generics (Generic )
import Data.Aeson
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
data JTask = JTask {fields :: Fields} deriving (Generic)
data Fields = Fields { project :: HashMap Key Project
, summary :: ByteString
, issuetype :: HashMap Name Task
, versions :: [HashMap Name Version]
, description :: ByteString
} deriving (Generic)
data Key = Key deriving (Generic)
instance Show Key where
show Key = "key"
data Name = Name deriving (Generic)
instance Show Name where
show Name = "name"
data Task = Task deriving (Generic)
type Version = ByteString -- Placeholder type. Probably using Day for realsies.
data Project = BNAP deriving (Generic) -- Fill this out as we go
instance ToJSON Fields
instance ToJSON JTask
instance ToJSON Key
instance ToJSON Name
instance ToJSON Task
instance ToJSON Project
mapfst :: (a -> b) -> [(a, v)] -> [(b, v)]
mapfst f = fmap $ \ (k, v) -> (f k, v)
instance ToJSON a => ToJSON (HashMap Key a) where
toJSON = toJSON . HashMap.fromList . mapfst show . HashMap.toList
instance ToJSON a => ToJSON (HashMap Name a) where
toJSON = toJSON . HashMap.fromList . mapfst show . HashMap.toList

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