With -hints
option on, the compiler emits a hint message against the following program:
module Main where
main :: IO ()
main = do
let magic :: Int -- (A)
magic = 123
println magic
.
$ fregec -hints Main.fr
H Main.fr:5: let definition is a constant: magic
calling: javac -cp /home/yohashi/lib/java/fregec.jar:. -d . -sourcepath . -encoding UTF-8 ./Main.java
What does this hint try to "hint" against?
If I omit the type annotation (sorry for incorrect terminology) on the line (A)
, the hint goes away:
main = do
let magic = 123
...
Type ascription doesn't bring a hint, either:
main = do
let magic = 123 :: Int
The same thing happens to where
declarations:
main = println magic
where
magic :: Int
magic = 123 -- let definition is a constant: magic
magica = 123 -- no hint
magicb = 123 :: Int -- no hint
magicfun :: Int -> Int
magicfun = succ -- let definition is a constant: magicfun
magicfuna = succ -- no hint
magicfunb = succ :: Int -> Int -- no hint
magicfunc :: Int -> Int
magicfunc i = succ i -- no hint
A hint on magicfun
is particularly annoying because it discourages the point-free notation (compare to magicfunc
).
So my question is: what is the motivation behind this hint?
I think giving an alias for expressions simple or complex is a valid use for let
/where
. Is the hint suggesting otherwise?
You are right that abbreviating a constant or aliasing a function is perfectly fine. But then, hints are not warnings, but merely comments about your program that may or may not tell you something you didn't know yet.
Hence the notion of "hint against" is mistaken. Nor should you strive to make your code "hints free".
Ironically, it looks like the hint in question would need another hint to explain it. It should read:
I, the compiler, use to move type annotated constants like your 'name' to the top level, because it is safe to do so and may eliminate some or all nested levels of let. This will also speed up things later in type checking, code generation and run time. In addition, you might consider to do the same yourself, lest you end up defining the same constant over and over in different let expressions or where clauses.
Please note that, in
foo :: Int
foo = 42
we are annotating foo
, while in
foo = 42 :: Int
we are annotating the right hand side only, so that technically, foo
is not annotated and must undergo type inference. So that's where the seemingly unjustified and confusing difference comes from.