Reputation: 2515
data A = Num Int
| Fun (A -> A) String deriving Show
instance Show (Fun (A -> A) String) where
show (Fun f s) = s
I would like to have an attribute for a function A -> A
to print it, therefore there is a String
type parameter to Fun
. When I load this into ghci, I get
/home/kmels/tmp/show-abs.hs:4:16:
Not in scope: type constructor or class `Fun'
I guess this could be achieved by adding a new data type
data FunWithAttribute = FA (A -> A) String
adding data A = Num Int | Fun FunWithAttribute
and writing an instance Show FunWithAttribute
. Is the additional data type avoidable?
Upvotes: 6
Views: 221
Reputation: 77404
Instances are defined for types as a whole, not individual constructors, which is why it complains about Fun
not being a type.
I assume your overall goal is to have a Show
instance for A
, which can't be derived because functions can't (in general) have a Show
instance. You have a couple options here:
Show
instance outright:That is, something like:
instance Show A where
show (Num n) = "Num " ++ show n
show (Fun _ s) = s
In many cases, this makes the most sense. But sometimes it's nicer to derive Show
, especially on complex recursive types where only one case of many is not automatically Show
-able.
A
derivable:You can only derive Show
for types that contain types that themselves have Show
instances. There's no instance for A -> A
, so deriving doesn't work. But you can write one that uses a placeholder of some sort:
instance Show (A -> A) where
show _ = "(A -> A)"
Or even just an empty string, if you prefer.
Note that this requires the FlexibleInstances
language extension; it's one of the most harmless and commonly used extensions, is supported by multiple Haskell implementations, and the restrictions it relaxes are (in my opinion) a bit silly to begin with, so there's little reason to avoid it.
An alternate approach would be to have a wrapper type, as you mention in the question. You could even make this more generic:
data ShowAs a = ShowAs a String
instance Show (ShowAs a) where
show (ShowAs _ s) = s
...and then use (ShowAs (A -> A))
in the Fun
constructor. This makes it a bit awkward by forcing you to do extra pattern matching any time you want to use the wrapped type, but it gives you lots of flexibility to "tag" stuff with how it should be displayed, e.g. showId = id `ShowAs` "id"
or suchlike.
Upvotes: 11
Reputation: 1991
Perhaps I'm not following what you are asking for. But the above code could be written like this in order to compile:
data A = Num Int
| Fun (A -> A) String
instance Show A where
show (Fun f s) = s
show (Num i) = show i
It looked like you were trying to write a show instance for a constructor (Fun). Class instances are written for the entire data type (there might be exceptions, dunno). So you need to write one show matching on each constructor as part of the instance. Num and Fun are each constructors of the data type A.
Also, deriving
can't be used unless each parameter of each constructor is, in turn, member of, in this case, Show
. Now, your example is a bit special since it wants to Show (A -> A)
. How to show a function is somewhat explained in the other responses, although I don't think there is an exhaustive way. The other examples really just "show" the type or some place holder.
Upvotes: 5
Reputation: 120711
A Show
instance (or any class instance) needs to be defined for a data type, not for a type constructor. That is, you need simply
instance Show A where
Apparently, you're trying to get this instance with the deriving
, but that doesn't work because Haskell doesn't know how to show A->A
. Now it seems you don't even want to show that function, but deriving Show
instances always show all available information, so you can't use that.
The obvious, and best, solution to your problem is worldsayshi's: don't use deriving
at all, but define a proper instance yourself. Alternatively, you can define a pseudo-instance for A->A
and then use deriving:
{-# LANGUAGE FlexibleInstances #-}
data A = Num Int | Fun (A->A) String deriving(Show)
instance Show (A->A) where show _ = ""
This works like
Prelude> Fun (const $ Num 3) "bla"
Fun "bla"
Upvotes: 4