Emitting warnings from Template Haskell splices - haskell

I know that I can cause a compile-time error by calling fail from a splice, but is it possible to only generate a warning? In particular I would like it to be possible to turn this warning into an error when compiling with -Werror.
Essentially what I'm trying to do is this:
todo :: Q Exp
todo = do
-- emit warning somehow
loc <- location
let message = ... -- generate message based on loc
[| error $(litE (stringL message)) |]
The idea is to use this instead of undefined while coding, but make sure it doesn't sneak its way into production code by compiling with -Werror.
myFunc x | isSimpleCase x = 42
| otherwise = $todo

Turns out the function I was after was the Template Haskell function report. Its type signature was in the documentation, but I had to read the source code to figure out what it did. The TH documentation sure could use some improvements.
Anyway, my todo placeholder is now working perfectly, and I'll put something up on Hackage soon if anyone is interested.

I don't believe this is possible naively from TH, but it is a really cool idea.
One way to implement it would be via bindings to the GHC-API warning and debug output or error functions.
E.g. to pretend to be GHC,
import Panic
main = sorry "help!"
produces
$ ./A
A: A: sorry! (unimplemented feature or known bug)
(GHC version 7.0.2 for x86_64-unknown-linux):
help!
Constructing GHC warnings should work similarly, checking if -Werror is set, and you could clean up the API to be quite useful.

To emit warnings from Template Haskell splices,
you can use reportWarning :: String -> Q ().
It already includes the location (line and column).
You can implement your todo function simply by:
todo :: Q Exp
todo = do
reportWarning "TODO"
[| undefined |]
Further information
#hammar's answer indicates the function report. It has been deprecated since GHC 7.6 (2012) and will possibly be removed from the API in the near future.
(However, report is still available
on GHC 7.10
and
on GHC master branch
as of 2015.)
Use reportError to report an error and carry on with the Q computation
(ultimately failing compilation anyway).
Use fail to stop with an error (GHC ≤ 7.10). That might
not apply on GHC 8.0.

Related

Require that a specific Haskell type defined in code is invalid

Is it possible to instruct GHC compiler to require that a specific value in code has invalid type, without ever using this value?
A contrived example is:
data Box a = Num a => Box a
goodBoxSample :: Box Int
goodBoxSample = Box 1
-- below definition and binding are expected to fail compilation
badBoxSample :: Box String
badBoxSample = Box "foo"
Is there a way to inform the compiler that badBoxSample is expected to fail (e.g. with some pragma, rather than commenting it out as a known bad sample), so that the code compiles only if badBoxSample fails to type-check?
The motivation here is the same as for writing a test (in some other language) with the code that is required to throw exception for the test case to pass.
Not possible. You're basically asking for a way to prove that there's no instance Num String, but Haskell operates under the open-world assumption, which means that someone could always declare such an instance.
Somebody posted a very helpful answer here, but before I managed to accept it was removed... Thank you anyway, and here it is for the reference:
https://hackage.haskell.org/package/generic-lens-2.0.0.0/docs/Data-Generics-Product-Fields.html
In short, the goal of testing failing types can be achieved with doctest, in the way the linked library does it.

How to document type-class constraints using Haddock?

I'm trying to document some very scary type-class constraints and explaining why they're required, but I can't seem to get the following working in Haddock:
{-|
This will show-up at the top of the module
-}
module Try where
-- | This shows up immediately after the class "header"
class (
-- | PROBLEM: This doesn't work...
Show a -- ^ PROBLEM: Also, this doesn't work
) => Something a where
-- | This shows up as the method's documentation
something :: a -> Int
There isn't any way to make this work with the latest version of Haddock.
This idea has been brought up before in passing: https://github.com/haskell/haddock/issues/472#issuecomment-257136046. I wouldn't hold my breath though - this would require some really core changes to how Haddock stores doc strings.

Haskell: Parse error: module header, import declaration or top-level declaration expected

I am saving some commands in a Haskell script in a .hs file while working thru a Haskell textbook. Here's a small example.
fst (1,2)
snd (1,2)
When I run these commands from the prelude in GHCi, they work fine. When I try to compile the .hs file with these two lines, I get the following:
ch4_test.hs:2:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
2 | fst (1,2)
| ^^^^^^^^^
Failed, no modules loaded.
I've googled this error and can't find any explanation what I'm doing wrong.
From a newbie to future newbies: The interactive environment ghci would lead you to believe that you can punch some expressions into an .hs file and run the thing (in a similar fashion to languages like swift and ruby). This is not the case.
Haskell needs an entrypoint called main. Quoting:
Here is a simple program to read and then print a character:
main :: IO ()
main = do c <- getChar
putChar c
The use of the name main is important: main is defined to be the entry point of a Haskell program (similar to the main function in C), and must have an IO type, usually IO ()
Source: https://www.haskell.org/tutorial/io.html
You can't just put any expression in a hs file.
As the error message says, you need a declaration here. For example:
main =
print (fst (1,2)) >>
print (snd (1,2))
I am getting this error but the cause appears to be completely different from anything posted here. And the error message is not at all helpful.
Using Cabal version 3.6.2.0 with GHCI 8.10.7 on MacOS High Sierra (10.13)
I'm working from this page: https://www.tutorialspoint.com/haskell/haskell_modules.htm
specifically the "custom modules" section. There you can see the code I copied and pasted.
Besides the tutorial not mentioning I needed to add "other-modules: Custom" to myfirstapp.cabal, and besides the fact that the sample Custom.hs file includes "if x 'rem' 2 == 0" rather than "if x rem 2 == 0", here is the problem:
Indentation matters!
This line (inside the quotes) does NOT work "if x rem 2 == 0".
This line DOES work " if x rem 2 == 0"!
Indenting by one space is the difference between success and failure.
I'm totally new to Haskell. I've programmed extensively in PHP, Javascript, and Applescript, and dabbled in a dozen others, and this is the first time I've seen white space matter. I assume this is commonly known amongst Haskell veterans, but it would certainly be nice if that was included prominently in the documentation.

Adapting Error to Except

Now that Control.Monad.Error is deprecated, and Control.Monad.Except reigns supreme, a lot of sources online haven't caught up, and still show examples of how to use Error.
So how would I go about turning
instance Error MyError where
noMsg = ...
strMsg = ...
into something using Except. Just replacing Error with Except didn't work as Except expects additional type parameters
I understand that those exact methods don't exist in Except, so what's the alternative?
Short answer is: Replace Error by nothing at all, replace ErrorT by ExceptT, and things should continue to work as long as you don't use Errors methods, fail (which now has a different definition), or failing pattern matches in do notation.
The essential difference between the old Control.Monad.Error system and the new Control.Monad.Except system is that the new system imposes no class restriction on the error/exception type.
It was found that the ability to use any error/exception type at all, polymorphically, was more useful than the somewhat hacky ability to customize conversion of string error messages.
So the class Error has simply disappeared.
As a side effect, fail for ExceptT now is lifted from the underlying monad. This also changes the effect of failing patterns in do notation.
The old definition was:
fail msg = ErrorT $ return (Left (strMsg msg))
which I think is equivalent to
fail msg = throwError (strMsg msg)
If you still need this behavior, you can instead use
throwError yourIntendedErrorValue
(throwE works instead if you're using transformers (i.e. Control.Monad.Trans.Except) rather than mtl.)
The old do pattern matching failure would apply to things like
do
Just x <- myErrorTAction
...
when the action actually returns Nothing. This is more awkward, but you could e.g. replace it with an explicit case match (essentially desugaring it):
do
y <- myErrorTAction
case y of
Nothing -> throwE ...
Just x -> do
...
#DanielWagner suggests the following to avoid extra indentation:
do
x <- myErrorTAction >>= maybe (throwError ...) return
...
The removal of Error also eliminates the need for an inconsistency in naming that Control.Monad.Error had: Most transformers follow the rule that SomethingT is the name of the transformer, and Something is a type alias for SomethingT ... Identity. The old ErrorT broke that because the Error class was used for something entirely different.
In the new system, Except e = ExceptT e Identity, like for other transformers.

Why does Haskell insist on removing the last argument of a function?

This is the relevant code :
removeCard :: Card -> Tracker -> Tracker
removeCard card tracker = filter (\cTracker -> ctCard cTracker /= card) tracker
Haskell is giving me a warning here, saying it should be written without the tracker on each side. I find it easier to read my functions when all the arguments are there, as the argument names help clarify what the function does. I could reverse the order of the parameters, but it makes intuitive sense to me that if you're calling a removeCard function, the card to remove is the first parameter, so I don't want to do that either. Is there a strong argument in favor of removing the last parameter?
EDIT : The question originally said that Haskell was giving me an error, but that was a bug with Syntastic, it's just a warning.
If you don't want this HLint warning, you can disable it. This module will not show it for any functions defined:
module Foo where
{-# ANN module "HLint: ignore Eta reduce" #-}
foo bar = show bar

Resources