placeholder-0: placeholder definitions for TODO and unimplemented
Copyright(c) Edward Kmett 2024
LicenseBSD-2-Clause OR Apache-2.0
MaintainerEdward Kmett <ekmett@gmail.com>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellTrustworthy
LanguageHaskell2010

Control.Placeholder

Description

Various functions to indicate unfinished or generally unimplemented code

Synopsis

Combinators

todo :: forall {r :: RuntimeRep} (a :: TYPE r). HasCallStack => a Source #

Warning: todo left in code

todo indicates unfinished code.

It is to be used whenever you want to indicate that you are missing a part of the implementation and want to fill that in later.

The main difference to other alternatives like typed holes and undefined or error is, this does not throw an error but only emits a warning.

Similarly to undefined, error and typed holes, this will throw an error if it is evaluated at runtime which can only be caught in IO.

This is intended to *never* stay in code but exists purely for signifying "work in progress" code.

To make the emitted warning error instead (e.g. for the use in CI), add the -Werror=x-todo flag to your OPTIONS_GHC.

Examples

Expand
superComplexFunction :: Maybe a -> IO Int
-- we already know how to implement this in the Nothing case
superComplexFunction Nothing = pure 42
-- but the Just case is super complicated, so we leave it as todo for now
superComplexFunction (Just a) = todo

Representation Polymorphism

Expand

todo, in contrast to TODO, is fully representation polymorphic

unimplemented :: forall {r :: RuntimeRep} (a :: TYPE r). HasCallStack => a Source #

unimplemented indicates that the relevant code is unimplemented. Unlike todo, it is expected that this _may_ remain in code long term, and so no warning is supplied. Use cases might include places where a typeclass would theoretically require a member to be implemented, but where the resulting violation is actually intended.

Patterns

pattern TODO :: HasCallStack => a Source #

Warning: TODO left in code

TODO indicates unfinished code or an unfinished pattern match

You can use this in most positions where you could pass todo, but it also can be used in pattern position to indicate that there are cases you haven't considered.

There remain some circumstances where you can only use todo, however, they arise when using this in a PolyKinded situation.

This pattern synonym is marked COMPLETE, implying that every match after matching on TODO will emit a redundant pattern match warning. Adding new options to your datatype, similarly to how wildcard patterns (patterns starting with an underscore) work, will not cause any warnings or errors.

Examples

Expand

Since the pattern match is strict, even if the branch itself does not evaluate to bottom, matching on TODO will.

>>> x = []
>>> case x of
...   (x : _) -> x
...   TODO -> 42
*** Exception: Control.Placeholder.todo: not yet implemented

As usual, this behaviour can be reversed by using a ~ in front of TODO in pattern position.

>>> x = []
>>> case x of
...   (x : _) -> x
...   ~TODO -> 42
42

In most situations, TODO can be used just like todo, where the above is equivalent to the below

>>> y :: Int = todo
>>> x :: Int = TODO

Representation Polymorphism

Expand

Mind that pattern synonyms may not be representation polymorphic, hence, if you need something that can be used with some kind other than Type, you have to use todo. For example, TODO cannot stand instead of a pattern match on an Int# :: TYPE IntRep or as a placeholder for a ByteArray# :: UnliftedType

pattern Unimplemented :: HasCallStack => a Source #

Unimplemented can be used in most circumstances unimplemented can, but it can also be used in pattern position to indicate cases haven't been considered yet. Unlike TODO it does not provide a compile-time warning, as it is expected that this _may_ remain in code long term.

IO

todoIO :: HasCallStack => IO a Source #

Warning: todoIO left in code

todoIO indicates unfinished code that lives in the IO monad.

It should be used similarly to how throwIO should be used rather than throw in IO to throw at the time the IO action is run rather than at the time it is created.

unimplementedIO :: HasCallStack => IO a Source #

unimplementedIO indicates that the method is unimplemented, but it lives in IO, and so only throws when actually run, rather than when it is constructed. Unlike todoIO it does not provide a compile-time warning, as it is expected that this _may_ remain in code long term.

Exceptions

newtype TodoException Source #

This is the Exception thrown by todo, TODO and todoIO.

Bundled Patterns

pattern TodoException :: TodoException

This lets us discard the location information in a TodoException