Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: variant of `show` that doesn't wrap String and Char in quotes

I'd like a variant of show (let's call it label) that acts just like show, except that it doesn't wrap Strings in " " or Chars in ' '. Examples:

> label 5
"5"
> label "hello"
"hello"
> label 'c'
"c"

I tried implementing this manually, but I ran into some walls. Here is what I tried:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Label where

class (Show a) => Label a where
    label :: a -> String

instance Label [Char] where
    label str = str

instance Label Char where
    label c = [c]

-- Default case
instance Show a => Label a where
    label x = show x

However, because the default case's class overlaps instance Label [Char] and instance Label Char, those types don't work with the label function.

Is there a library function that provides this functionality? If not, is there a workaround to get the above code to work?

like image 874
Joey Adams Avatar asked Dec 04 '25 17:12

Joey Adams


1 Answers

The code above isn't going to work because instances are chosen only based on the "head", that is, the part after the class name. The "context", the stuff before the => such as `Show a' is only examined afterwards. The context can eliminate an instance and produce a compiler error, but not cause the compiler to pick a different instance. Because of this behavior, overlapping instances are a potential ambiguity.

There are compiler extensions that can let you write more complicated instances, but I suspect you're probably best off just writing individual instances of your Label class. What purpose do you have in mind for this? Depending on what you're trying to accomplish, there might be something more special-purpose already out there.

Your example code is pretty simple, though--if you want, simply adding the OverlappingInstances extension should make it work with no further modifications. Using OverlappingInstances causes GHC to tolerate some ambiguity, so long as there's an obvious "most specific" instance. In your code, the two instances with concrete types are as specific as it gets, so there shouldn't be any problems.

Might as well add TypeSynonymInstances while you're at it, for better readability:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Label where

class (Show a) => Label a where
    label :: a -> String

instance Label String where label x = x

instance Label Char where label x = [x]

instance (Show a) => Label a where label = show
like image 169
C. A. McCann Avatar answered Dec 06 '25 09:12

C. A. McCann