Haskell Constraint Kinds - default constraint for default implementation - haskell

Headline: I would like to provide a default implementation for a class method parametrised over a constraint, which uses the default instance for that constraint.
Consider the following:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts (Constraint)
class Foo a where
type Ctx a :: Constraint
type Ctx a = Show a
foo :: (Ctx a) => a -> String
foo = show
main :: IO ()
main = putStrLn "Compiles!"
This fails to compile with the error of:
Could not deduce (Show a) arising from a use of ‘show’
from the context (Foo a)
From my perspective, it should be using the default constraint of Show, which would let this compile. Is there any reason this doesn't work, or can anyone suggest a good way to achieve this?

You can achieve this using DefaultSignatures:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DefaultSignatures #-}
import GHC.Exts (Constraint)
class Foo a where
type Ctx a :: Constraint
type Ctx a = Show a
foo :: (Ctx a) => a -> String
default foo :: Show a => a -> String
foo = show
main :: IO ()
main = putStrLn "Compiles!"
From my perspective, it should be using the default constraint of Show, which would let this compile.
The reason your approach doesn't work is that the user of your class should be able to override any number of defaults. Your code would break if someone tried to override Ctx but not foo.

Related

Avoid `undefined` when using `TypeError` in type-class constraint

I have a type-class instance like this:
instance {-# OVERLAPPABLE #-} (TypeError ( 'Text "Some error")) => SomeClass x where
someMethod = undefined
This instance exists at the end of other (valid) instances. The idea is to have the compiler throw a type error when the user writes a type that doesn't adhere to these valid instances. TypeError in instance constraint achieves this, but this also forces me to fill in the method with undefined, which feels like a hack.
Is there a way to avoid this? Or do it better?
Here's the real-world code with this pattern.
The best I could achieve is this. Essentially, I defined a TypeErr type family standing for both the standard TypeError constraint and an additional Impossible constraint providing the needed witness. Impossible would always fail to resolve as a constraint, but the type error is triggered first anyway.
{-# LANGUAGE DataKinds, UndecidableInstances, TypeFamilies #-}
import GHC.TypeLits (
ErrorMessage (Text),
TypeError,
)
class Impossible where
impossible :: a
type family TypeErr t where
TypeErr t = (TypeError t, Impossible)
-- Dummy example
class SomeClass x where
someMethod :: x -> Maybe x
instance {-# OVERLAPPABLE #-} (TypeErr ( 'Text "Some error"))
=> SomeClass x where
someMethod = impossible
main :: IO ()
main = print (someMethod True)
{-
<source>:19:15: error:
* Some error
* In the first argument of `print', namely `(someMethod True)'
In the expression: print (someMethod True)
In an equation for `main': main = print (someMethod True)
-}
We have the Disallowed class in the trivial-constraint package. It offers the nope pseudo-method, which is a version of undefined that can only be used in impossible contexts (and witnesses this by being possible to “use” unboxed, which you can't do with standard undefined).
instance {-# OVERLAPPABLE #-} (Disallowed "fallback for `SomeClass`")
=> SomeClass x where
someMethod = nope

Why can I not use type variables in this instance declaration?

I'm trying to use TypeApplications to disambiguate between which instance of a type class I am calling. Unfortunately, it seems that an instance declaration's type parameters cannot be used in the instance body. Specifically, in this toy example:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
class Foo a where
foo :: String
instance Foo () where
foo = "()"
instance Foo Int where
foo = "Int"
class Bar b where
bar :: String
instance Foo a => Bar a where
bar = foo #a
will error with Not in scope: type variable 'a' at the last line. If I remove the type application, instead the error Could not deduce (Foo a0) from the context Foo a is given, which is reasonable, ass foo by itself is ambiguous.
Is there some way for me to access the type parameter, or otherwise coerce the compiler into recognising this?
A type variable can be used in an instance declaration, but only if it's scoped:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE TypeApplications, AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax #-}
class Foo a where foo :: String
class Bar b where bar :: String
instance ∀ a . Foo a => Bar a where
bar = foo #a
As always, ∀ can also be written forall if you prefer ASCII.

Why does GHC think that the type variable is ambiguous for a class with a default implementation?

In the following example I would expect GHC to be able to constrain the variable a to type A because that's what I say in instance EAmbiguous A. However when loading this into ghci I get:
Ambiguous type variable ‘a0’ arising from a use of ‘Main.$dmcount’
The code in question:
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics (Rep, Generic)
import GHC.Base (Type)
class EAmbiguous a where
count :: Int
default count :: (Generic a, GenericAmbiguous (Rep a)) => Int
count = genericCount #(Rep a)
class GenericAmbiguous (a :: Type -> Type) where
genericCount :: Int
instance GenericAmbiguous (f p) where
genericCount = 10
data A = A deriving Generic
-- The error happens when defining a body-less instance:
-- • Ambiguous type variable ‘a0’ arising from a use of ‘Main.$dmcount’
-- prevents the constraint ‘(Generic a0)’ from being solved.
instance EAmbiguous A
I've been looking at this for a good while and I'm convinced that this should work, but I'm clearly missing something. So my question is: Why can't GHC solve a to A?
This turned out to be a GHC bug which is fixed in GHC 8.0.2: https://ghc.haskell.org/trac/ghc/ticket/12220

Haskell -- get TypeRep from concrete type instance

I want to write a function with this type signature:
getTypeRep :: Typeable a => t a -> TypeRep
where the TypeRep will be the type representation for a, not for t a. That is, the compiler should automatically return the correct type representation at any call sites [to getTypeRep], which will have concrete types for a.
To add some context, I want to create a "Dynamic type" data type, with the twist that it will remember the top-level type, but not its parameter. For example, I want to turn MyClass a into Dynamic MyClass, and the above function will be used to create instances of Dynamic MyClass that store a representation of the type parameter a.
Well, how about using scoped type variables to select the inner component:
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Dynamic
import Data.Typeable
getTypeRep :: forall t a . Typeable a => t a -> TypeRep
getTypeRep _ = typeOf (undefined :: a)
Works for me:
*Main> getTypeRep (Just ())
()
*Main> getTypeRep (Just 7)
Integer
*Main> getTypeRep ([True])
Bool
Interesting design.
On a tangential note to Don's solution, notice that code rarely require ScopedTypeVariables. It just makes the solution cleaner (but less portable). The solution without scoped types is:
{-# LANGUAGE ExplicitForAll #-}
import Data.Typeable
helper :: t a -> a
helper _ = undefined
getTypeRep :: forall t a. Typeable a => t a -> TypeRep
getTypeRep = typeOf . helper
This function (now) exists in Data.Typeable typeRep

How to make specialized type classes for certain types, default implementation for the rest of types

I would like to have a type class of types that can possibly casted to other types when possible.
class Castable a b where
cast :: a -> Maybe b
cast _ = Nothing -- default implementation
Now the class would be implemented for some types and for all the others I would like to have default implementation.
How one can do that?
It's not necessarily a safe or Haskell-y thing to do, but it is certainly possible, using OverlappingInstances
First, enable them:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
Write your casting class:
class Castable a b where
cast :: a -> Maybe b
cast _ = Nothing -- default implementation
An "optimized" instance:
instance Castable Int Bool where
cast 0 = Just False
cast _ = Just True
and finally, a general instance for all types:
instance Castable a b where
Example use:
main = do
print $ (cast (7 :: Int) :: Maybe Bool)
print $ (cast (7 :: Int) :: Maybe Integer)
Running this, the default is chosen when the types aren't specialized:
*Main> main
Just True
Nothing

Resources