How do I get rid of "Defaulting the following constraints to type ‘[Char]’" warnings? - haskell

I'm using the Aeson library and the OverloadedStrings pragma, but this question is more general. The immediate context is that I'm writing code for a sum type so I have a "kind" field in the JSON to say which variant is being represented. In the ToJSON instance I write code like this:
toJSON (Foo v) = ["kind" .= "foo" ...]
toJSON (Bar v) = ["kind" .= "bar" ...]
GHC gives me the following warning for "foo" and "bar":
Defaulting the following constraints to type ‘[Char]’
(ToJSON v0)
arising from a use of ‘.=’
The reason is that both String and Text are instances of ToJSON, so the compiler has to pick one, and in this case it has picked String.
I know I can suppress the warning with an in-line type, like this:
toJSON (Foo v) = ["kind" := ("foo" :: Text) ...]
However that clutters up the code with redundant information. Also I've got quite a lot of these warnings.
I've tried putting default (Text) at the top of the file, but that just changes the warning to tell me its defaulted to type Text.
Is there a way of disabling the warnings for Text/String defaults but leaving any others in place?

Why not lift that part of the serialisation logic out into a separate function? It's kind of hacky anyway, so better to section it off. And you'll silence the warning (provided you give the function a type).
Something along the lines of...
toJSON thing#(Foo v) = ["kind" .= kind thing ...]
toJSON thing#(Bar v) = ["kind" .= kind thing ...]
kind :: T -> Text
kind (Foo _) = "foo"
kind (Bar_) = "bar"
However you want to to do it. Maybe use a ViewPattern or maybe make kind :: KeyValue kv => T -> kv. Just don't inline it, IMO.

In the end I took Thomas DuBuisson's suggestion from the comments and added a couple of specialized functions:
-- | Type-restricted version of "(.=)" to silence compiler warnings about defaults.
(..=) :: (KeyValue kv) => Text -> Text -> kv
(..=) = (.=)
-- | Type restricted version of "(.:)" to silence compiler warnings about defaults.
(..:) :: Object -> Text -> Parser Text
(..:) = (.:)

I think I'd probably abstract the key-value pair you're making, like this:
kind :: KeyValue kv => Text -> kv
kind lbl = "kind" .= lbl
toJSON (Foo v) = [kind "foo", ...]
toJSON (Bar v) = [kind "bar", ...]

Related

Type deduction in function composition

Hello i have a type with a type parameter:
data A=A1| A2 deriving (Show)
data B=B1| B2 deriving(Show)
data C a=C{var::a,var2::Int}
getters=[show . var,show .var2]
I get the following error in the getters at show . var :
Ambiguous type variable `a0' arising from a use of `show'
prevents the constraint `(Show a0)' from being solved.
Relevant bindings include
getters:: [Worker a0 -> String]
Do i have to explicitly state the type ,something like : show. (var::B).I do not really understand the error since both types A and B are implementing Show
Edit: updated below to answer your follow-up question.
To answer your original question, this is just a situation where the type checker needs a little help. You can get your code to type check by adding an explicit signature for getters, as #WillemVanOnsem has suggested:
data A = A1 | A2 deriving (Show)
data B = B1 | B2 deriving (Show)
data C a = C { var :: a, var2 :: Int }
getters :: (Show a) => [C a -> String]
getters = [show . var, show . var2]
or, alternatively, by turning on the NoMonomorphismRestriction GHC extension, as #DanielWagner points out. After doing either of these, the following works fine:
> map ($ C A1 10) getters
["A1","10"]
> map ($ C B2 10) getters
["B2","10"]
>
This signature doesn't make getters a "method", if your comment about methods was directed at Willem. It's still a polymorphic expression with type [C a -> String] (for any type a with a Show a constraint).
Update: As per your comments, you think you want to define a data type with a constraint on the type of one or more of its fields. (You don't actually want to do this -- you just think you do -- but who am I to stop you?)
So, to do this, you'll need to enable the DatatypeContexts extension and write:
{-# LANGUAGE DatatypeContexts #-}
class Mytypeclass a where
whatever :: a -> String
data Mytypeclass a => MyType a = M { var :: a, var2 :: a }
The compiler will generate a warning that this extension was deprecated because it was widely considered a misfeature and removed from the language.
Now, you can define:
getters = [whatever . var, whatever . var2]
This will give you an error, though a different error message than before, after which you can either add the signature:
getters :: (Mytypeclass a) => [MyType a -> String]
getters = [whatever . var, whatever . var2]
or else enable the NoMonomorphismRestriction extension in order to get it to compile, just like before.

How do I let a function in Haskell depend on the type of its argument?

I tried to write a variation on show that treats strings differently from other instances of Show, by not including the " and returning the string directly. But I don't know how to do it. Pattern matching? Guards? I couldn't find anything about that in any documentation.
Here is what I tried, which doesn't compile:
show_ :: Show a => a -> String
show_ (x :: String) = x
show_ x = show x
If possible, you should wrap your values of type String up in a newtype as #wowofbob suggests.
However, sometimes this isn't feasible, in which case there are two general approaches to making something recognise String specifically.
The first way, which is the natural Haskell approach, is to use a type class just like Show to get different behaviour for different types. So you might write
class Show_ a where
show_ :: a -> String
and then
instance Show_ String where
show_ x = x
instance Show_ Int where
show_ x = show x
and so on for any other type you want to use. This has the disadvantage that you need to explicitly write out Show_ instances for all the types you want.
#AndrewC shows how you can cut each instance down to a single line, but you'll still have to list them all explicitly. You can in theory work around this, as detailed in this question, but it's not pleasant.
The second option is to get true runtime type information with the Typeable class, which is quite short and simple in this particular situation:
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ x =
case cast x :: Maybe String of
Just s -> s
Nothing -> show x
This is not a natural Haskell-ish approach because it means callers can't tell much about what the function will do from the type.
Type classes in general give constrained polymorphism in the sense that the only variations in behaviour of a particular function must come from the variations in the relevant type class instances. The Show_ class gives some indication what it's about from its name, and it might be documented.
However Typeable is a very general class. You are delegating everything to the specific function you are calling; a function with a Typeable constraint might have completely different implementations for lots of different concrete types.
Finally, a further elaboration on the Typeable solution which gets closer to your original code is to use a couple of extensions:
{-# LANGUAGE ViewPatterns, ScopedTypeVariables #-}
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ (cast -> Just (s :: String)) = s
show_ x = show x
The use of ViewPatterns allows us to write the cast inside a pattern, which may fit in more nicely with more complicated examples. In fact we can omit the :: String type constraint because the body of this cases forces s to be the result type of show_, i.e. String, anyway. But that's a little obscure so I think it's better to be explicit.
You can wrap it into newtype and make custom Show instance for it:
newtype PrettyString = PrettyString { toString :: String }
instance Show PrettyString where
show (PrettyString s) = "$$" ++ s ++ "$$" -- for example
And then use it like below:
main = getLine >>= print . PrettyString
TL;DR:
Copy the prelude's way and use showList_ as a class function to generate instances for lists so you can override the definition for String.
Caveat
For the record, wowofbob's answer using a newtype wrapper is the simple, clean solution I would use in real life, but I felt it was instructive to also look at some of how the Prelude does this.
intercalate commas by default
The way this is done in the prelude is to make the Show class have a function for showing lists, with a default definition that you can override.
import Data.List (intercalate)
I'll use intercalate :: [a] -> [[a]] -> [a] to put commas in between stuff:
ghci> intercalate "_._" ["intercalate","works","like","this"]
"intercalate_._works_._like_._this"
Make a showList_ class function, and default to show and comma-separated lists.
So now the class with the default implementation of the showList function and, importantly, a default show_ implementation that just uses the ordinary show function. To be able to use that, we have to insist that the type is already in the Show typeclass, but that's OK as far as I understand you.
class Show a => Show_ a where
show_ :: a -> String
showList_ :: [a] -> String
show_ = show
showList_ xs = '[' : intercalate ", " (map show_ xs) ++ "]"
The real Show class uses functions of type String -> String instead of String directly for efficiency reasons, and a precedence argument to control the use of brackets, but I'll skip all that for simplicity.
Automatically make instances for lists
Now we can use the showList function to provide an instance for lists:
instance Show_ a => Show_ [a] where
show_ xs = showList_ xs
The Show a => superclass makes instances super-easy
Now we come to some instances. Because of our default show_ implementation, we don't need to do any actual programming unless we want to override the default, which we'll do for Char, because String ~ [Char].
instance Show_ Int
instance Show_ Integer
instance Show_ Double
instance Show_ Char where
show_ c = [c] -- so show_ 'd' = "d". You can put show_ = show if you want "'d'"
showList_ = id -- just return the string
In practice:
Now that's not much use to hide " from your output in ghci, because the default show function is used for that, but if we use putStrLn, the quotes disappear:
put :: Show_ a => a -> IO ()
put = putStrLn . show_
ghci> show "hello"
"\"hello\""
ghci> show_ "hello"
"hello"
ghci> put "hello"
hello
ghci> put [2,3,4]
[2, 3, 4]
ghci>

Removing backslashes when show Strings?

I have parametric method which concats a String onto a parametric input:
foo::(Show a) => a -> String
foo f = show f ++ " string"
it is fine when I don pass in a string, but when I pass in a string I get extra blackslashes.
is there a way i avoid ths?
show is not really a toString equivalent but rather an inspect or var_dump equivalent. It's not meant for formatting for human output.
You might consider http://hackage.haskell.org/package/text-format
Don't know about "standard" library function but can be simply done with own show-like implementation:
class StrShow a where
showStr :: a -> String
instance StrShow String where
showStr = id
instance Show a => StrShow a where
showStr = show
GHCi> showStr 1
"1"
GHCi> showStr "hello"
"hello"
This way you don't need extra library but have to use lot of ghc's extensions (TypeSynonymInstances, FlexibleInstances, UndecidableInstances, OverlappingInstances) if this is not an issue.
One way of doing this, which isn't very nice but it's certainly possible, is to use the Typeable class.
import Data.Maybe (fromMaybe)
import Data.Typeable (cast)
foo :: (Show a, Typeable a) => a -> String
foo f = fromMaybe (show f) (cast f)
However, this restricts it to members of the Typeable class (which is included in base, so you won't need to depend on any more libraries, and most things will have defined it).
This works by checking if f is a String (or pretending to be a String, which will only happen if someone's been REALLY evil when writing a library), and if it is, returning it, otherwise showing it.

Is there a polymorphic `toString` function that doesn't add quotes?

In most OO languages that I'm familiar with, the toString method of a String is actually just the identity function. But in Haskell show adds double quotes.
So if I write a function something like this
f :: Show a => [a] -> String
f = concat . map show
it works as expected for numbers
f [0,1,2,3] -- "0123"
but Strings end up with extra quotes
f ["one", "two", "three"] -- "\"one\"\"two\"\"three\""
when I really want "onetwothree".
If I wanted to write f polymorphically, is there a way to do it with only a Show constraint, and without overriding the Show instance for String (if that's even possible).
The best I can come up with is to create my own type class:
class (Show a) => ToString a where
toString = show
and add an instance for everything?
instance ToString String where toString = id
instance ToString Char where toString = pure
instance ToString Int
instance ToString Maybe
...etc
I think the root cause of your problem is that show isn't really renderToText. It's supposed to produce text that you could paste into Haskell code to get the same value, or convert back to the same value using read.
For that purpose, show "foo" = "foo" wouldn't work, because show "1" = "1" and show 1 = "1", which loses information.
The operation you want to be able to apply to "foo" to get "foo" and to 1 to get "1" is something other than show. show just isn't a Java-esque toString.
When I've needed this before, I have indeed made my own new type class and made a bunch of things instances of it, and then used that rather than Show. Most of the instances were implemented with show, but String wasn't the only one I wanted to customise so the separate type class wasn't completely wasted. In practice, I found there were only a handful of types that I actually needed the instance for, and it was pretty trivial to add them as I got compile errors.
The Pretty class and its corresponding type Doc have the needed behavior for Show. Your link shows a different use case, however; maybe you could edit the question?
You could do this:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class Show a => ToString a where
toString :: a -> String
instance Show a => ToString a where
toString = show
instance ToString String where
toString = id
Prelude> toString "hello"
"hello"
Prelude> toString 3
"3"
Note that this is probably a terrible idea.
You could use newtype with OverloadedStrings:
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
newtype LiteralString = LS ByteString
instance IsString LiteralString where fromString = LS . B.pack
instance Show LiteralString where show (LS x) = B.unpack x
instance Read LiteralString where readsPrec p s = map (\(!s, !r) -> (LS s,r)) $! readsPrec p s
hello :: LiteralString
hello = "hello world"
main :: IO ()
main = putStrLn . show $! hello
output:
hello world
The double quotes in the normal case are actually useful when reading a shown string back in the context of larger expression as they clearly delimit shown string values from values of other shown types:
x :: (ByteString, Int)
x = read . show $! ("go", 10)
-- string value starts --^^-- ends
y :: (LiteralString, Int)
y = read . show $! ("go", 10)
-- string value starts --^ ^ consumes all characters; read fails

Binary instance for an existential

Given an existential data type, for example:
data Foo = forall a . (Typeable a, Binary a) => Foo a
I'd like to write instance Binary Foo. I can write the serialisation (serialise the TypeRep then serialise the value), but I can't figure out how to write the deserialisation. The basic problem is that given a TypeRep you need to map back to the type dictionary for that type - and I don't know if that can be done.
This question has been asked before on the haskell mailing list http://www.haskell.org/pipermail/haskell/2006-September/018522.html, but no answers were given.
You need some way that each Binary instance can register itself (just as in your witness version). You can do this by bundling each instance declaration with an exported foreign symbol, where the symbol name is derived from the TypeRep. Then when you want to deserialize you get the name from the TypeRep and look up that symbol dynamically (with dlsym() or something similar). The value exported by the foreign export can, e.g., be the deserializer function.
It's crazy ugly, but it works.
This can be solved in GHC 7.10 and onwards using the Static Pointers Language extension:
{-# LANGUAGE StaticPointers #-}
{-# LANGUAGE InstanceSigs #-}
data Foo = forall a . (StaticFoo a, Binary a, Show a) => Foo a
class StaticFoo a where
staticFoo :: a -> StaticPtr (Get Foo)
instance StaticFoo String where
staticFoo _ = static (Foo <$> (get :: Get String))
instance Binary Foo where
put (Foo x) = do
put $ staticKey $ staticFoo x
put x
get = do
ptr <- get
case unsafePerformIO (unsafeLookupStaticPtr ptr) of
Just value -> deRefStaticPtr value :: Get Foo
Nothing -> error "Binary Foo: unknown static pointer"
A full description of the solution can be found on this blog post, and a complete snippet here.
If you could do that, you would also be able to implement:
isValidRead :: TypeRep -> String -> Bool
This would be a function that changes its behavior due to someone defining a new type! Not very pure-ish.. I think (and hope) that one can't implement this in Haskell..
I have an answer that slightly works in some situations (not enough for my purposes), but may be the best that can be done. You can add a witness function to witness any types that you have, and then the deserialisation can lookup in the witness table. The rough idea is (untested):
witnesses :: IORef [Foo]
witnesses = unsafePerformIO $ newIORef []
witness :: (Typeable a, Binary a) => a -> IO ()
witness x = modifyIORef (Foo x :)
instance Binary Foo where
put (Foo x) = put (typeOf x) >> put x
get = do
ty <- get
wits <- unsafePerformIO $ readIORef witnesses
case [Foo x | Foo x <- wits, typeOf x == ty] of
Foo x:_ -> fmap Foo $ get `asTypeOf` return x
[] -> error $ "Could not find a witness for the type: " ++ show ty
The idea is that as you go through, you call witness on values of every type that you may plausibly encounter when deserialising. When you deserialise you search this list. The obvious problem is that if you fail to call witness before deserialisation you get a crash.

Resources