opened 03:58PM - 07 Mar 24 UTC
Dear Haskell core library committee.
Currently there are multiple ways of des…cribing something as unimplemented
- undefined
- error "not implemented yet"
- various other, similar functions from external libraries, such as the ones in alternative preludes like `Relude` [placeholders](https://hackage.haskell.org/package/placeholders-0.1/docs/Development-Placeholders.html#v:todo) or [the todo package](https://hackage.haskell.org/package/todo-0.2.0.3/docs/Debug-Todo.html)
- typed holes
All of these have problems:
1. Problems of the functions currently in `base`:
- `undefined`:
- doesn't give you a warning if it remains in code
- doesn't read as "this is open, I will definitely implement it soon"
- a lot to type for "please compiler, be quiet for the second, I will come back to this"
- `error`:
- also doesn't give you a warning if it remains in code
- may read as "this is open, I will definitely implement it soon" *but* this is a lot to type
- even more to type for "please compiler, be quiet for the second, I will come back to this", sometimes even needs paranthesis
2. external dependencies:
- just for doing a quick debugging `todo`, it doesn't seem worth adding an alternative `Prelude` or even add a dependency just for the sake of this
3. typed holes
- they are, by default, errors, not warnings
- they are very noisy (by default they produce a lot of output)
- they are slow (by default)
That's why propose a function `todo` that has the following properties:
- has a warning annotation `"todo remains in code"` in group `x-todo` so that it can be used with `WError` for e.g. CI
- has the same type as `undefined`
- gets (re)exported by `base:Prelude`
- is to be used whenever there is a place in the code where we want to temporary fill holes
- the warning message is not fixed as shown in the example implementation and may be adjusted, similar things hold for the documentation
The implementation would be as follows:
```haskell
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE MagicHash #-}
{-# OPTIONS_GHC -Wall #-}
module Todo (todo) where
import GHC.Base (raise#, TYPE, RuntimeRep)
import GHC.Exception (errorCallWithCallStackException)
import GHC.Stack (HasCallStack)
{- | '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.
==== __Examples__
@
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'
@
-}
todo :: forall {r :: RuntimeRep} (a :: TYPE r). (HasCallStack) => a
todo = raise# (errorCallWithCallStackException "Prelude.todo" ?callStack)
{-# WARNING in "x-todo" todo "todo remains in code" #-}
```
try it out in a separate module, as such:
```haskell
module TodoExample where
import Todo
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
```
This implementation will work from `>= ghc981`
Impact:
on [hoogle](https://hoogle.mangoiv.com/?q=todo) I currently find 4 functions which this would break, two of which have similar semantics to this one, making it improbable that they will be found in code out there.
I will obviously run a proper impact assessment though.
Also look at:
[rust std's `todo!` and `unimplemented!` macros](https://doc.rust-lang.org/std/macro.todo.html)
Rendered docs:
![rendered docs without expanded Examples](https://github.com/haskell/core-libraries-committee/assets/40720523/eea71f3b-97a1-4dd5-b687-a1fc4eeb0779)
![rendered docs with expanded Examples](https://github.com/haskell/core-libraries-committee/assets/40720523/ff4e4ccb-4fba-4fc1-a2b1-1bacd389d3f4)
How it looks, loading a module using `todo` into `GHCi`:
![screenshot of terminal showing how it looks to load a module using the `todo` function](https://github.com/haskell/core-libraries-committee/assets/40720523/83ee9fdb-19e3-41f1-8aea-4fa495365ec7)