简体   繁体   中英

Haskell: “ambiguous type variable arising from using a function”, where said variable actually doesn't matter

Consider the following function:

foo :: Show a => Maybe a -> [Char] 
foo (Just x) = show x 
foo Nothing = "Nothing"

Then I try to use this function:

bar :: [Char]
bar = foo Nothing

The argument that has been passed to foo is of type Maybe a where a is not specified, and indeed we don't care about a , because we use only the case of foo for the Nothing . But the GHC claims to provide the concrete type:

Ambiguous type variable a0 arising from a use of foo
prevents the constraint (Show a0) from being solved. Probable fix: use a type annotation to specify what a0 should be.

GHC hints to specify the type. So the only fix I see there is to create a fake type which has an instance of Show type class:

{-# LANGUAGE EmptyDataDecls, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}

data Dummy :: *

instance Show Dummy

bar :: [Char]
bar = foo (Nothing :: Maybe Dummy)

foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"

It works, but seems to be pretty straightforward. But the real reason why I don't like this solution is because for my purposes this code is automatically generated from some meta data, which doesn't provide information about which particular polymorph type must be specified as Dummy (there are may be user data types with more than one parameters). So I wonder, is there any way to tell GHC, that if the type is not specified, this type doesn't matter?

"doesn't matter" is a property of the instance, and ghc doesn't introspect instances like that. For some types, it does matter. The Show instance for [a] depends on the type a , even when the list is empty. Check out the result of show ([] :: [Char]) vs the result of show ([] :: [Int]) .

But all of that is sort of an aside. The fact is, types are determined at compile time, but values are determined at run time. You have presented a situation for which the type variables don't matter for only some input values. In this case, the type variables still matter, because they control behavior in the other cases.

You're going to have to properly resolve the ambiguous types, because that's how ghc knows which code to use. There are some techniques for doing it conveniently, like using the ScopedTypeVariables extension, but it's hard to recommend one without having a more representative piece of code. The most important thing I can say is that it really does matter, though, because instance selection is done at compile time, long before a value is ever seen.

The type checker doesn't know what foo does with its argument, and specifically doesn't know that Nothing won't actually be used. But it does know that the argument must have type Show a => Maybe a , and Nothing has the more general type Maybe a . It's up to you to provide a sufficiently narrowly typed argument when calling foo .

There's no need to define a new dummy type; any existing type with a Show instance will do.

bar :: [Char]
bar = foo (Nothing :: Maybe ())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM