Undefined at the type level - haskell

Often when I'm playing with Haskell code, I stub things out with a type annotation and undefined.
foo :: String -> Int
foo = undefined
Is there a type-level "undefined" that I could use in a similar way?
(Ideally, in conjunction with a kind annotation)
type Foo :: * -> *
type Foo = Undefined
Further thought on the same thread: is there a way for me to stub out typeclass instances for types created this way? An even easier way than the following theoretical way?
instance Monad Foo where
return = undefined
(>>=) = undefined

You can use EmptyDataDecls to stub out a type, and with KindSignatures you can give it a kind:
{-# LANGUAGE EmptyDataDecls, KindSignatures #-}
data Foo :: * -> *
You can also stub out the Monad instance without warnings with this option to GHC.
{-# OPTIONS_GHC -fno-warn-missing-methods #-}
instance Monad Foo
And then you don't need to leave any implementation for return and >>=.

This question was asked and answered a long time ago; best practices have evolved since.
These days, instead of undefined, for stubbing out code you should be using typed holes, and their type-level analogue, partial type signatures.

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

How to export type constructors when using DataKinds extension?

Playing with advanced type-system stuff. I want to have named kind and a
couple of type constructors that produce types of that kind:
{-# LANGUAGE DataKinds #-}
data Subject = New | Existing
Here, as I understand, we have named kind Subject and type constructors
New and Existing that are :: Subject. These type constructors do not
take arguments (I plan to use them as phantom types), it should be roughly
equivalent to:
{-# LANGUAGE EmptyDataDecls #-}
data New
data Existing
With the difference that now I can write:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
-- …
data MyConfig :: Subject -> * -> * where
MyConfig
{ mcOneThing :: Path t File
} :: MyConfig k t
This even compiles. What is confusing is that declaration of data kinds is
indistinguishable from data type declarations, so this code seems to produce
data type Subject as well as named kind Subject (?) It would be clearer
for me it we could specify on which level do we declare things (kinds, and
then New and Existing are type constructors; or types, and then New
and Existing are value constructors for things of Subject type). I don't
get this design decision with “promote everything that seems to work”.
Now, my problem is that I cannot export New and Existing as
type-constructors to use in other module, e.g. to declare things like:
foo :: MyConfig New Dir -> …
where at the same time
foo :: MyConfig Int Dir -> …
should be ill-kinded and it should not compile.
Here is how I'm trying to export them:
module MyModule
( New
, Existing
-- …
)
where
What I get:
Not in scope type constructor or class ‘New’
Not in scope type constructor or class ‘Existing’
GHC manual in
section 7.9.3
says that to distinguish between “types and constructors” one can use single quote ', so I tried:
module MyModule
( 'New
, 'Existing
-- …
)
where
…but now it's a parse error.
How do I export New and Existing type constructors, and most
importantly, is there anything wrong with my current understanding?
Use the usual syntax for exporting constructors:
module MyModule (Subject(..)) where
data Subject = New | Existing
Currently, lifted and unlifted constructors are tied together, so we can only export/import them together.
Also, you don't need to have DataKinds in MyModule, only in the module where you intend to use lifted constructors.

When using MultiParamTypeClasses, do you need to use every type in every class function

When I use MultiParamTypeClasses, I can create class functions that ignore one of the type parameters (ie- like "identity" below).
{-# LANGUAGE MultiParamTypeClasses #-}
data Add = Add
data Mul = Mul
class Test a b where
identity::a
instance Test Int Add where
identity = 0
instance Test Int Mul where
identity = 1
(this is a stripped down version, of course in the full program there would be other functions that would use "b").
The example compiles, but I can never access identity!
main = do
putStrLn (show (identity::Int))
leads to "No instance for (Test Int b0) arising from a use of 'identity'.
Is there a way to access identity? If not, shouldn't the compiler forbid me from ever creating a class function that doesn't use all type parameters?
If not, shouldn't the compiler forbid me from ever creating a class function that doesn't use all type parameters?
Perhaps. Indeed you'll never be able to use such a class method. But as the error occurs always at compile-time, it's not really dangerous.
Fixes that work in some similar cases (not in yours, though):
Make the undetermined type variable functionally dependent on one of the others.
{-# LANGUAGE FunctionalDependencies #-}
class Group_FD g p | g->p where
identity :: g
This could be used perhaps like
data Nat = One | Succ Nat
instance Group_FD Nat Mult where
identity = One
instance Group_FD Int Add where
identity = 0
But it's obviously not possible to make multiple instances with the same g element this way.
Define a seperate class with only one parameter for the methods that depend only on that. Then make this class a constraint ("superclass") on the other one, to "import" methods:
class Identity i where
identity :: i
class (Identity i) => Test i y
that's no use at all for your application though, since you want the behaviour of identity to depend on the Phantom type variable.
To achieve your goal, you must somehow pass the information of which instance you want. One way to achieve this is phantom arguments:
class Group_PA g p where
identity :: p -> g
instance Group_PA Int Add where
identity _ = 0
instance Group_PA Int Mult where
identity _ = 1
You could then use that like
GHCi> identity Add :: Int0
GHCi> identity Mult :: Int1
Perhaps more idiomatic would actually be to make the flag types empty
{-# LANGUAGE EmptyDataDecls #-}
data Add
data Mult
GHCi> identity (undefined :: Add) :: Int0
GHCi> identity (undefined :: Mult) :: Int1
This makes it clearer that the phantom argument actually carries no runtime information, just controls what instance the compiler chooses.
Admittedly, this is pretty ugly.
The right™ solution is to make newtype wrappers to contain the phantom information. In fact, such wrappers are already in the standard libraries: Sum and Product.
If you use FlexibleInstances, it's possible to change the instance definition so that identity may be used:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data Add = Add
data Mul = Mul
class Test a b where
identity::a
instance Test Int b where
identity = 0
main :: IO ()
main = do
print $ (identity :: Int)
Because instances could be defined in an other file and then only that file would require the use of FlexibleInstances, GHC cannot disallow class declarations that don't use all their type variables in general.
If you want instances for different b's, then you have to use FunctionalDependencies.

Existential quantifier silently disrupts Template Haskell (makeLenses). Why?

I have this file:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ExistentialQuantification #-}
module Toy where
import Control.Lens
data Bar = Bar { _barish :: String }
data Foo = forall a. Show a => Foo { _fooish :: a }
$(makeLenses ''Bar)
$(makeLenses ''Foo)
x = barish
y = fooish
and I get the following error message:
Toy.hs:15:5:
Not in scope: `fooish'
Perhaps you meant `_fooish' (line 9)
This is my first time attempting to use existential quantifiers; I have no idea why this combination of features breaks. Even more worryingly, why do I get no error message about makeLenses failing? I ran runhaskell Toy.hs
You can't actually use your function _fooish. If you try to do that, you get the error:
Cannot use record selector `_fooish' as a function due to escaped type variables
Probable fix: use pattern-matching syntax instead
In the expression: _fooish
So lens can't generate a lens for you. Why doesn't it give an error? Well, sometimes you have additional fields for which it's possible to generate lenses. It seems this not the case here, but I think in general makeLenses just skips everything that is impossible to do and tries to generate the rest.

Is a scoped type statement possible?

Is it possible to do the following:
foo = bar
where
type A = (Some, Huge, Type, Sig)
meh :: A -> (A, A) -> A
I only need to use this custom type inside the where clause, so it does not make sense to define it globally.
This isn't possible. Why not just define it above the function? You don't have to export it from the module (just use an explicit export list).
By the way, if you really do have a type that big, it's probably a sign that you should factor it into smaller parts, especially if you have a lot of tuples as your example suggests; data-types would be more appropriate.
Actually, there's one, slightly ridiculous, way to approximate this:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
foo :: forall abbrv. (abbrv ~ (Some, Huge, Type, Sig))
=> abbrv -> abbrv
foo x = meh x (x, x)
where meh :: abbrv -> (abbrv, abbrv) -> abbrv
meh x y = {- ... -}
I can't really recommend enabling two language extensions just for the sake of abbreviating types in signatures, though if you're already using them (or GADTs instead of type families) I suppose it doesn't really hurt anything.
Silliness aside, you should consider refactoring your types in cases like this, as ehird suggests.

Resources