How does `-XOverloadedStrings` work? (in Yesod) - string

I'm following Yesod tutorials from their official yesod book. (http://www.yesodweb.com/book/basics)
Unfortunately their tutorials on the book won't work, worse is that its output is very cryptic message about types not mathcing that took me quite a while to understand. Here's their original code and error message which is produced by the code:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Yesod
data Links = Links
mkYesod "Links" [parseRoutes|
/ HomeR GET
|]
instance Yesod Links
getHomeR = return $ object ["msg" .= "Hello World"]
main :: IO ()
main = warp 3000 Links
error:
helloworld2.hs:18:36:
No instance for (ToJSON a0) arising from a use of ‘.=’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance ToJSON a => ToJSON (Control.Applicative.Const a b)
-- Defined in ‘Data.Aeson.Compat’
instance ToJSON (Data.Proxy.Proxy a)
-- Defined in ‘Data.Aeson.Compat’
instance ToJSON Data.Version.Version
-- Defined in ‘Data.Aeson.Compat’
...plus 7 others
In the expression: "msg" .= "Hello World"
In the first argument of ‘object’, namely
‘["msg" .= "Hello World"]’
In the second argument of ‘($)’, namely
‘object ["msg" .= "Hello World"]’
helloworld2.hs:18:40:
No instance for (Data.String.IsString a0)
arising from the literal ‘"Hello World"’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Data.String.IsString Value
-- Defined in ‘aeson-0.9.0.1:Data.Aeson.Types.Internal’
instance (a ~ Data.ByteString.Internal.ByteString) =>
Data.String.IsString
(attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Internal.Parser a)
-- Defined in ‘Data.Attoparsec.ByteString.Char8’
instance (a ~ Data.Text.Internal.Text) =>
Data.String.IsString
(attoparsec-0.13.0.1:Data.Attoparsec.Text.Internal.Parser a)
-- Defined in ‘attoparsec-0.13.0.1:Data.Attoparsec.Text.Internal’
...plus 9 others
In the second argument of ‘(.=)’, namely ‘"Hello World"’
In the expression: "msg" .= "Hello World"
In the first argument of ‘object’, namely
‘["msg" .= "Hello World"]’
it seems object ["msg" .= "Hello World"] is the problem. GHC doesn't understand what are types of "msg" and "Hello World", and can't build a JSON object out of them. I had to make their types explicit, that:
import Data.Text (Text)
getHomeR = return $ object [("msg" :: Text) .= ("Hello World" :: Text)]
it seems Aeson has toJSON instances for Text type, and I've heard that most of the text-processing codes use Text type, not String ([Char]) for efficiency reasons. But wouldn't it be nice, if every double-quoted code ("msg", "Hello World") is parsed as Text instead of String automatically? I've thought the OverloadedStrings pragma tells the compiler to do exactly that("overload" the strings into Text), but above errors without type signature indicates that I was wrong.
of course, If I have to give :: Text type signature for every string I write for output it would be very tedious and cumbersome - is there any solution for this, or is it me just don't understand enough to write Haskell and Yesod codes?

When you use OverloadedStrings, explicit strings are treated in a similar way to explicit numbers. So
x = "foo"
is desugared into
x = fromString "foo"
The IsString class defines the "fromString" function, so now all the type checker knows is that
x :: (IsString a) => a
So this is why the compiler is complaining that the type is ambiguous. There are several different string types with a ToJSON instance, and the compiler is complaining that it doesn't know which one to pick.
The only solutions, I'm afraid, are to lose the OverloadedStrings or to put in explicit type annotations to tell the compiler which instance to pick.
On String versus Text: efficiency is not a particularly big issue when you are using short constant strings like this. If you are processing text in bulk then its a bigger issue, and also the Haskell concept of String = [Char] breaks down in some languages. Text handles these properly, but String doesn't. So if you ever need to internationalise your code then String can present you with obscure problems when you try to do things like capitalise words.

The JSON code snippet you're looking at does work correctly straight out of the book. There's an additional pragma at the top of it that's missing from your code:
{-# LANGUAGE ExtendedDefaultRules #-}
I'm not a huge fan of the code snippet doing that, since I'm pretty sure people don't use that pragma in production code. It would be more typical to write the code like this:
getHomeR = return $ object ["msg" .= ("Hello World" :: String)]
Note that GHCi uses ExtendedDefaultRules to make it easier to enter expressions into the REPL without having to specify their type. If you type object ["msg" .= "Hello World"] into GHCi it'll tell you what it's defaulting to:
ghci > object ["msg" .= "Hello World"]
<interactive>:2:18: Warning:
Defaulting the following constraint(s) to type ‘String’
(IsString a0)
arising from the literal ‘"Hello World"’ at <interactive>:2:18-30
(ToJSON a0) arising from a use of ‘.=’ at <interactive>:2:15-16
In the second argument of ‘(.=)’, namely ‘"Hello World"’
In the expression: "msg" .= "Hello World"
In the first argument of ‘object’, namely
‘["msg" .= "Hello World"]’
<interactive>:2:18: Warning:
Defaulting the following constraint(s) to type ‘String’
(IsString a0)
arising from the literal ‘"Hello World"’ at <interactive>:2:18-30
(ToJSON a0) arising from a use of ‘.=’ at <interactive>:2:15-16
In the second argument of ‘(.=)’, namely ‘"Hello World"’
In the expression: "msg" .= "Hello World"
In the first argument of ‘object’, namely
‘["msg" .= "Hello World"]’
Object (fromList [("msg",String "Hello World")])

object takes a list of Pair values as argument. Pair is type Pair = (Text, Value) and it is an instance of tye KeyValue typeclass, which provides the convenience constructor (.=) :: ToJSON v => Text -> v -> kv.
The problem is as follows: .= requires the value type to have a ToJSON instance, but doesn't force the caller into any concrete type.
Meanwhile, the fromString function from IsString is overloaded on its return type: fromString :: String -> a. The precise implementation to call is determined from the return type. When OverloadedStrings is used, fromString is called implicitly for string literals.
If we feed directly the result of fromString as the value argument of .=, the compiler doesn't have enough information to assing a concrete type to the value. Should it create a Text value and convert it to json? Or perhaps create a ByteString instead and convert it to json? The problem is similar to ambiguous compositions like show . read.
Personally, instead of using type annotations I would solve the ambiguity by wrapping the string literals using the String constructor of the Value type. It tells the compiler that the literal will be Text, and of course Value is an instance of ToJSON. This is a bit less verbose than type annotations:
foo :: Value
foo = object ["foo" .= String "faa"]
You could also define a specialization of .= that took a concrete Text as the value:
(.=|) :: KeyValue kv => Text -> Text -> kv
(.=|) = (.=)
foo :: Value
foo = object ["foo" .=| "faa"]

Related

Matching on a particular type of a parametric type

I'm trying to work with an external library that has provided a parametric type like this:
data ParametricType a = TypeConstructor a
I have a typeclass, something like this:
class GetsString a where
getString :: a -> String
and I'd like to execute some code if ParametricType's a is a specific type. I've tried narrowing the type when instantiating the typeclass:
data HoldsString = HoldsString String
instance GetsString (ParametricType HoldsString) where
getString (TypeConstructor (HoldsString str)) = str
which errors with Illegal instance declaration for‘GetsString (ParametricType HoldsString)’(All instance types must be of the form (T a1 ... an)
and I've tried pattern matching on the type:
instance GetsString (ParametricType a) where
getString (TypeConstructor (HoldsString str)) = str
for which I receive Couldn't match expected type ‘a’ with actual type ‘HoldsString’‘a’ is a rigid type variable bound by the instance declaration.
Is there a way to do this, or am I conceptually on the wrong track here?
You're just missing the FlexibleInstances extension. Put {-# LANGUAGE FlexibleInstances #-} at the top of your file, or do :set -XFlexibleInstances if you're typing into GHCi directly, and then your first attempt will work.

Pattern bindings for existential constructors

While writing Haskell as a programmer that had exposure to Lisp before, something odd came to my attention, which I failed to understand.
This compiles fine:
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Show a => Foo { getFoo :: a }
showfoo :: Foo -> String
showfoo Foo{getFoo} = do
show getFoo
whereas this fails:
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Show a => Foo { getFoo :: a }
showfoo :: Foo -> String
showfoo foo = do
let Foo{getFoo} = foo
show getFoo
To me it's not obvious why the second snippet fails.
The question would be:
Do I miss something or stems this behaviour from the fact that haskell is not homoiconic?
My reasoning is, given that:
Haskell needs to implement record pattern matching as a compiler extension, because of it's choice to use syntax rather than data.
Matching in a function head or in a let clause are two special cases.
It is difficult to understand those special cases, as they cannot be either implemented nor looked up directly in the language itself.
As an effect of this, consistent behaviour throughout the language is not guaranteed. Especially together with additional compiler extensions, as per example.
ps: compiler error:
error:
• My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
• In the pattern: Foo {getFoo}
In a pattern binding: Foo {getFoo} = foo
In the expression:
do { let Foo {getFoo} = foo;
show getFoo }
edit:
A different compiler version gives this error for the same problem
* Couldn't match expected type `p' with actual type `a'
because type variable `a' would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor: Foo :: forall a. Show a => a -> Foo
Do I miss something or stems this behaviour from the fact that haskell is not homoiconic?
No. Homoiconicity is a red herring: every language is homoiconic with its source text and its AST1, and indeed, Haskell is implemented internally as a series of desugaring passes between various intermediate languages.
The real problem is that let...in and case...of just have fundamentally different semantics, which is intentional. Pattern-matching with case...of is strict, in the sense that it forces the evaluation of the scrutinee in order to choose which RHS to evaluate, but pattern bindings in a let...in form are lazy. In that sense, let p = e1 in e2 is actually most similar to case e1 of ~p -> e2 (note the lazy pattern match using ~!), which produces a similar, albeit distinct, error message:
ghci> case undefined of { ~Foo{getFoo} -> show getFoo }
<interactive>:5:22: error:
• An existential or GADT data constructor cannot be used
inside a lazy (~) pattern
• In the pattern: Foo {getFoo}
In the pattern: ~Foo {getFoo}
In a case alternative: ~Foo {getFoo} -> show getFoo
This is explained in more detail in the answer to Odd ghc error message, "My brain just exploded"?.
1If this doesn’t satisfy you, note that Haskell is homoiconic in the sense that most Lispers use the word, since it supports an analog to Lisp’s quote operator in the form of [| ... |] quotation brackets, which are part of Template Haskell.
I thought about this a bit and albeit the behaviour seems odd at first, after some thinking I guess one can justify it perhaps thus:
Say I take your second (failing) example and after some massaging and value replacements I reduce it to this:
data Foo = forall a. Show a => Foo { getFoo :: a }
main::IO()
main = do
let Foo x = Foo (5::Int)
putStrLn $ show x
which produces the error:
Couldn't match expected type ‘p’ with actual type ‘a’ because type variable ‘a’ would escape its scope
if the pattern matching would be allowed, what would be the type of x? well.. the type would be of course Int. However the definition of Foo says that the type of the getFoo field is any type that is an instance of Show. An Int is an instance of Show, but it is not any type.. it is a specific one.. in this regard, the actual specific type of the value wrapped in that Foo would become "visible" (i.e. escape) and thus violate our explicit guarantee that forall a . Show a =>...
If we now look at a version of the code that works by using a pattern match in the function declaration:
data Foo = forall a . Show a => Foo { getFoo :: !a }
unfoo :: Foo -> String
unfoo Foo{..} = show getFoo
main :: IO ()
main = do
putStrLn . unfoo $ Foo (5::Int)
Looking at the unfoo function we see that there is nothing there saying that the type inside of the Foo is any specific type.. (an Int or otherwise) .. in the scope of that function all we have is the original guarantee that getFoo can be of any type which is an instance of Show. The actual type of the wrapped value remains hidden and unknowable so there are no violations of any type guarantees and happiness ensues.
PS: I forgot to mention that the Int bit was of course an example.. in your case, the type of the getFoo field inside of the foo value is of type a but this is a specific (non existential) type to which GHC's type inference is referring to (and not the existential a in the type declaration).. I just came up with an example with a specific Int type so that it would be easier and more intuitive to understand.

IsString instance not automatically converted to String

I have a type a which is an instance of the IsString typeclass.
If I use something like
"foobar" :: a
everything works fine.
As soon as I use a function that returns a string, as in
("foo" ++ "bar") :: a
I get a compilation error telling me that
Couldn't match expected type ‘a’ with actual type ‘[Char]’
Expected type: a
Actual type: String
Notice that I have the {-# LANGUAGE OverloadedStrings #-} pragma.
Is there something else I should do to solve the compilation error?
The idea of the IsString typeclass is to specify that we can convert a String object to such object (with the fromString :: String -> a function). Furthermore by enabling the OverloadedStrings pragma, we can also write a objects as string literals (in that case these String literals will transparently be converted to as by calling the fromString function).
Note however that IsString does not results in a way to convert as back to Strings. Furthermore functions that are defined on Strings can not be used for such instances (at least not without doing some implementation work).
If you write:
("foo" ++ "bar") :: a
Haskell will derive that you call (++) :: [b] -> [b] -> [b], so as a result it knows that the type of these string literals is a IsString [b] => [b]. So that means that a ~ [b]. Since your type is probably not a list, there is no way that this can match.

Extension OverloadedString doesn't fully infer IsString. Why? Or what am I missing?

ghc 7.6.3
is quite upset for some code i'm trying to compile
the error is
No instance for (Data.String.IsString t3)
arising from the literal `"meh"'
The type variable `t3' is ambiguous
i don't understand. it's a literal. what is ambiguous? why can't it infer this as a string?
this is coming in a call like
foo bar "meh"
where foo doesn't require the second argument to be anything in particular (it must satisfy some typeclass, and it does for the particular combos it is getting.)
i'll note i can fix this error by changing the call to
foo bar ("meh" :: String)
which is clearly insane.
-- edit
maybe it has nothing to do with overloadedStrings
i can "reproduce" this error just with
data B a where
Foo :: a -> B A
then in GHCi writing simply
Foo "ok"
(clearly this fails as i'm not deriving Show, but why do i also get
No instance for (Data.String.IsString a0)
arising from the literal `"ok"'
The type variable `a0' is ambiguous
...
? what's going on here? what does this mean?)
it's a literal. what is ambiguous? why can't it infer this as a string?
When you use OverloadedStrings "meh" is not a literal String. It's a literal polymorphic value of type IsString a => a. Its type can't be inferred as String because it could also be used as a lazy ByteString, strict ByteString, Text, etc..
foo doesn't require the second argument to be anything in particular
If foo doesn't require the second argument to be anything in particular how does the type checker know the argument to foo should be a String, rather than a Text, etc.?
i'll note i can fix this error by changing the call to foo bar ("meh" :: String) which is clearly insane.
Now you are telling the type checker which specific type you want for "meh".
maybe it has nothing to do with overloadedStrings
It is exactly to do with OverloadedStrings. Personally I recommend not using OverloadedStrings and just using Data.String.fromString precisely because of the confusing behaviour you are seeing.
i can "reproduce" this error just with ... what's going on here? what does this mean?
Here's a concrete example of the ambiguity.
{-# LANGUAGE OverloadedStrings, FlexibleInstances #-}
import Data.Text
class Foo a where
foo :: a -> String
instance Foo String where
foo _ = "String"
instance Foo Text where
foo _ = "Text"
main :: IO ()
main = print (foo "meh")
What should main print? It depends on the type of "meh". What type did the user want for "meh"? With OverloadedStrings on, there's no way to know.

How do I resolve this compile error: Ambiguous type variable `a1' in the constraint

One could think of this case as follows:
The application dynamically loads a module, or there is a list of functions from which the user chooses, etc. We have a mechanism for determining whether a certain type will successfully work with a function in that module. So now we want to call into that function. We need to force it to make the call. The function could take a concrete type, or a polymorphic one and it's the case below with just a type class constraint that I'm running into problems with it.
The following code results in the errors below. I think it could be resolved by specifying concrete types but I do not want to do that. The code is intended to work with any type that is an instance of the class. Specifying a concrete type defeats the purpose.
This is simulating one part of a program that does not know about the other and does not know the types of what it's dealing with. I have a separate mechanism that allows me to be sure that the types do match up properly, that the value sent in really is an instance of the type class. That's why in this case, I don't mind using unsafeCoerce. But basically I need a way to tell the compiler that I really do know it's ok and do it anyway even though it doesn't know enough to type check.
{-# LANGUAGE ExistentialQuantification, RankNTypes, TypeSynonymInstances #-}
module Main where
import Unsafe.Coerce
main = do
--doTest1 $ Hider "blue"
doTest2 $ Hider "blue"
doTest1 :: Hider -> IO ()
doTest1 hh#(Hider h) =
test $ unsafeCoerce h
doTest2 :: Hider -> IO ()
doTest2 hh#(Hider h) =
test2 hh
test :: HasString a => a -> IO ()
test x = print $ toString x
test2 :: Hider -> IO ()
test2 (Hider x) = print $ toString (unsafeCoerce x)
data Hider = forall a. Hider a
class HasString a where
toString :: a -> String
instance HasString String where
toString = id
Running doTest1
[1 of 1] Compiling Main ( Test.hs, Test.o )
Test.hs:12:3:
Ambiguous type variable `a1' in the constraint:
(HasString a1) arising from a use of `test'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: test
In the expression: test $ unsafeCoerce h
In an equation for `doTest1':
doTest1 hh#(Hider h) = test $ unsafeCoerce h
Running doTest2
[1 of 1] Compiling Main ( Test.hs, Test.o )
Test.hs:12:3:
Ambiguous type variable `a1' in the constraint:
(HasString a1) arising from a use of `test'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: test
In the expression: test $ unsafeCoerce h
In an equation for `doTest1':
doTest1 hh#(Hider h) = test $ unsafeCoerce h
I think it could be resolved by specifying concrete types but I do not want to do that.
There's no way around it though with unsafeCoerce. In this particular case, the compiler can't infer the type of unsafeCoerce, because test is still to polymorphic. Even though there is just one instance of HasString, the type system won't use that fact to infer the type.
I don't have enough information about your particular application of this pattern, but I'm relatively sure that you need to rethink the way you use the type system in your program. But if you really want to do this, you might want to look into Data.Typeable instead of unsafeCoerce.
Modify your data type slightly:
data Hider = forall a. HasString a => Hider a
Make it an instance of the type class in the obvious way:
instance HasString Hider where
toString (Hider x) = toString x
Then this should work, without use of unsafeCoerce:
doTest3 :: Hider -> IO ()
doTest3 hh = print $ toString hh
This does mean that you can no longer place a value into a Hider if it doesn't implement HasString, but that's probably a good thing.
There's probably a name for this pattern, but I can't think what it is off the top of my head.

Resources