Generalized type-defaulting rules - haskell

Haskell's type-defaulting rules defaults a type variable a with constraints (C1 a,...,Cn a) if:
The type variable a appears in no other constraints
All the classes Ci are standard.
At least one of the classes Ci is numeric
This makes sense to me but it's also very limited: in practice it means that you always have to specify the type when it is ambiguous when you work with custom classes. For example, this doesn't compile:
class (Show a) => MyShow a where
myShow :: a -> String
myShow = show
instance (MyShow a) => MyShow (Maybe a) where
myShow Nothing = "Nothing"
myShow (Just x) = "Just " ++ (myShow x)
main = print $ myShow Nothing -- ambiguous
GHCi extends this set of rules in this way:
All of the classes Ci are single-parameter type classes.
At least one of the classes Ci is numeric, or is Show, Eq, or Ord.
and GHC has an extension called ExtendedDefaultRules that enable these rules. However this extension is very specific: it works only on GHC and with standard classes. For instance, one can think about libraries that don't use the standard library. In that case, the GHCi extension won't work.
My question is: the only way to extend the Haskell's type-defaulting rules like GHCi does is with compiler extensions? And more generic: is there a way to define type-defaulting based on some rules on the constraints in Haskell 98?

There is no way to do what you want.
The current situation is impoverished by design. The idea was to do something minimal that could be extended in the future when we have a good design.

Related

Universally quantified (or polymorphic) type class instances

Is it possible to define a generic type class instance parameterized by a type a in Haskell?
For example:
data Box a = Box a deriving Show
class Boxable a where
create :: a -> Box a
-- pseudo syntax here
instance forall a . Boxable a where
create = Box
If no, why not?
I am aware of the fact that this example is rather simple and "useless". I just want to know whether this is theoretically possible, not whether its practically relevant.
Your code is literally legal Haskell, nothing “pseudo syntax” about it. It's not quite Haskell98, but with two very harmless syntactic extensions it does compile:
{-# LANGUAGE ExplicitForall, FlexibleInstances #-}
data Box a = Box a deriving Show
class Boxable a where
create :: a -> Box a
instance forall a . Boxable a where
create = Box
The -XExplicitForall† is required for the explicit forall (duh), but actually you don't even need this because Haskell type variables are by default universally quantified:
{-# LANGUAGE FlexibleInstances #-}
instance Boxable a where
create = Box
Except, like chepner already commented this doesn't really make sense, because now create behaves just like a regular parametric function without any typeclass needed:
create' :: a -> Box a
create' = Box
That said, such once-and-for-all instances can actually be useful, if you constrain them with some superclass:
class Foo a
class Bar a
class (Foo a, Bar a) => FooBar a
instance (Foo a, Bar a) => FooBar a
Now if you mention FooBar (someComplicatedType) in a function's constraints, it has the same effect as writing out (Foo (someComplicatedType), Bar (someComplicatedType), which can significantly de-clunk your code and error messages and also make your projects more future-safe, because you can add or remove superclasses to FooBar without changing the signatures of all the functions that have this constraint.
(A very similar thing can be achieved with -XConstraintKinds as the arguably more straightforward constraint synonym type FooBar a = (Foo a, Bar a), but this brings in the well-known problem that type isn't really an encapsulation at all but can be unravelled by the compiler at any time, which isn't normally much of a problem except it leads to much more confusing type error messages.)
†You won't find -XExplicitForall itself very often in Haskell files, because it's only really needed as part of either -XScopedTypeVariables or -XRankNTypes, both of which are common and enable the forall keyword, or ∀ as I prefer to write it (which additionally requires -XUnicodeSyntax).

Where does Haskell keep its libraries? [duplicate]

Is there a way to see Typeclass definition in ghci for a specific type?
For example, Maybe is defined like this:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
Can I see this in ghci ?
When, I use :info in ghci, I get this:
Prelude> :i Maybe
data Maybe a = Nothing | Just a -- Defined in `Data.Maybe'
instance Eq a => Eq (Maybe a) -- Defined in `Data.Maybe'
instance Monad Maybe -- Defined in `Data.Maybe'
instance Functor Maybe -- Defined in `Data.Maybe'
instance Ord a => Ord (Maybe a) -- Defined in `Data.Maybe'
instance Read a => Read (Maybe a) -- Defined in `GHC.Read'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
In the above output, I want to see how it is defined in Data.Maybe as an instance for Functor. Anyway to see that in ghci ?
No, it's not possible – not just for instances but for anything. GHC only registers the compiled version of a package, so the source code generally won't be available to ghci.
Probably, most often you'll be using stuff from Hackage; in that case it's very simple to find the source code of such instances by hoogling the module, locating the class or data declaration, and clicking on source.
When you don't have internet access or whatever else reason you can't hoogle online, you first need to find out in what package the module is included. The easiest way to do that:
$ ghc-pkg find-module Data.Maybe
/usr/local/haskell/lib/ghc-7.6.2/package.conf.d
   base-4.6.0.1
   haskell2010-1.1.1.0
~/.ghc/x86_64-linux-7.6.2/package.conf.d
Then, as I said, GHC doesn't know where the source code to these packages is located – in fact it might not even be available on your system! But if you've installed the package (or one that depends on it) with cabal install, it will be there, by default in ~/.cabal/packages/hackage.haskell.org/PᴀᴄᴋᴀɢᴇNᴀᴍᴇ (as a compressed archive, but that's not a big hurdle). Within the package project folder, you can simply locate the module via the directory structure, which represents the module hierarchy.
Other packages, like your example of Data.Maybe (package haskell2010), may have come right with your installation of GHC, e.g. the Haskell platform. In that case, I believe the easiest thing is to search there for the Haddock documentation file. In my case,
$ find /usr/local/haskell -name 'Data-Maybe.html' | head -n1 | xargs firefox
That'll open up the equivalent to what hoogle links you to (but on your local HD), where you can also browse the source code in a user-friendly way.

How to view Typeclass definitions and a type's Typeclass implementations [duplicate]

Is there a way to see Typeclass definition in ghci for a specific type?
For example, Maybe is defined like this:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
Can I see this in ghci ?
When, I use :info in ghci, I get this:
Prelude> :i Maybe
data Maybe a = Nothing | Just a -- Defined in `Data.Maybe'
instance Eq a => Eq (Maybe a) -- Defined in `Data.Maybe'
instance Monad Maybe -- Defined in `Data.Maybe'
instance Functor Maybe -- Defined in `Data.Maybe'
instance Ord a => Ord (Maybe a) -- Defined in `Data.Maybe'
instance Read a => Read (Maybe a) -- Defined in `GHC.Read'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
In the above output, I want to see how it is defined in Data.Maybe as an instance for Functor. Anyway to see that in ghci ?
No, it's not possible – not just for instances but for anything. GHC only registers the compiled version of a package, so the source code generally won't be available to ghci.
Probably, most often you'll be using stuff from Hackage; in that case it's very simple to find the source code of such instances by hoogling the module, locating the class or data declaration, and clicking on source.
When you don't have internet access or whatever else reason you can't hoogle online, you first need to find out in what package the module is included. The easiest way to do that:
$ ghc-pkg find-module Data.Maybe
/usr/local/haskell/lib/ghc-7.6.2/package.conf.d
   base-4.6.0.1
   haskell2010-1.1.1.0
~/.ghc/x86_64-linux-7.6.2/package.conf.d
Then, as I said, GHC doesn't know where the source code to these packages is located – in fact it might not even be available on your system! But if you've installed the package (or one that depends on it) with cabal install, it will be there, by default in ~/.cabal/packages/hackage.haskell.org/PᴀᴄᴋᴀɢᴇNᴀᴍᴇ (as a compressed archive, but that's not a big hurdle). Within the package project folder, you can simply locate the module via the directory structure, which represents the module hierarchy.
Other packages, like your example of Data.Maybe (package haskell2010), may have come right with your installation of GHC, e.g. the Haskell platform. In that case, I believe the easiest thing is to search there for the Haddock documentation file. In my case,
$ find /usr/local/haskell -name 'Data-Maybe.html' | head -n1 | xargs firefox
That'll open up the equivalent to what hoogle links you to (but on your local HD), where you can also browse the source code in a user-friendly way.

How to get rid of this ambiguity?

I am pretty sure this has been asked before, however I was unable to find the right answer:
I tried to eliminate the ambiguity in the following exemplary code snippet:
{-# LANGUAGE MultiParamTypeClasses #-}
class FooBar a b where
foo :: a -> a
foo = id
bar :: a -> a
bar = foo -- ERROR AT THIS LINE
I get an error message like so:
Ambiguous type variable `b0' in the constraint:
(FooBar a b0) arising from a use of `foo'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: foo
In an equation for `bar': bar = foo
which is understandable. Note however, that I'm actually unable to follow the compiler's advice and fix the type variable in question: foo doesn't contain b type variable in its type signature. Also this doesn't work:
bar = (foo :: FooBar a b => a -> a) -- ERROR, the same error message
Not even with -XScopedTypeVariables enabled.
How to tell GHC which FooBar to use? Is it even possible?
EDIT
Following some answers: yes, I've heard about both functional dependencies and associated types.
As to functional dependencies - I am looking for a way to explicitly inform GHC which instance to use (as opposed to asking it to derive the correct type all by itself).
As to both - in the real world example that this one comes from, I actually need both of the parameters a and b to be independent.
Again: I know this example is extremely silly, I know b is not used in the body of the type class, which makes no sense. This is an extreme simplification of a real world example, that actually does make sense. The real use-case involves "substitutability" of types a using types b and then "unifiability" of types a and b using types c and unfortunately is much longer.
EDIT(2)
Okay sorry. I think you convinced me after all that I have to refactor the code in order not to have any ill-defined functions (i.e. ones that don't contain all the independent types in their type signatures). Talking to you really helped me think this thing though. Appreciated.
Your class is ill-defined even if you remove bar completely from the class. Let's just assume you have the following class:
class FooBar a b
where
foo :: a -> a
foo = id
Suppose now you would like to use foo outside the definition of this class.
e = .... foo x .....
GHC will complain with a similar error message than yours, that it can't find a type for b. Simply because your code doesn't supply such a type. Your type class declaration says every pair of types a and b might get an instance. So, even when a is fixed in a call of foo there are still arbitrary many possible instances to select from.
A functional dependency a -> b would solve that problem, because it states: Given a type a there may be only one instance of Foobar a b. An associated type avoids the problem by not using multi-parameter type classes.
regarding the OP's EDIT:
If you insist on having two type parameters. Then every method's signature of the type class has to contain every type variable of the class. There is no way around it.
If you introduce a functional dependency, class FooBar a b | a -> b where, that would settle it, but without that (or associated types), I think it is impossible to resolve the instance to use.
Oh, one way, but kind of ugly: introduce a dummy parameter of type b
class FooBar a b where
foo' :: b -> a -> a
foo' _ = id
bar' :: b -> a -> a
bar' b = foo b

Transforming a function to point-free style changes its type

I'm beginning Haskell... I tried to write the following trivial function in two different ways, letting Haskell decide the types, and the type system does something different in each case. What is the explanation for that behavior?
Prelude> let f x = 2 * x
Prelude> let g = (2*)
Prelude> :info f
f :: Num a => a -> a -- Defined at <interactive>:1:5
Prelude> :info g
g :: Integer -> Integer -- Defined at <interactive>:1:5
Thanks!
This is known as the monomorphism restriction.
Basically, it means that top-level bindings that look like x = are forced to be non-polymorphic, unless you specify a type signature. Bindings with arguments, i.e. f x = are not affected. See the link for details as to why this restriction exists.
Usually, you get an error message when the restriction is applied, but in this case GHCi is able to use type defaulting to change the type Num a => a to Integer.
The easiest way to dodge it is to either use an explicit type signature, or put
{-# LANGUAGE NoMonomorphismRestriction #-}
at the top of your module, or run GHCi with -XNoMonomorphismRestriction.
As others have pointed out, this is caused by something called the "Monomorphism Restriction".
MR can be useful for writers of Haskell compilers, and there is controversy about whether or not it is worthwhile to have in the language in general. But there is one thing everyone agrees: at the GHCi prompt, MR is nothing but a nuisance.
MR will probably be turned off by default in this context in an upcoming version of GHC. For now, you should disable it in GHCi by creating a text file called ".ghci" in your home directory that contains a line like this:
:set -XNoMonomorphismRestriction
Because the definition of g doesn't explicitly name its arguments, you run into the monomorphism restriction, preventing g from being polymorphic and (in this case) causing GHC to default to Integer.

Resources