Different default behaviors between the prompt and loaded files in GHCi - haskell

So my questions are:
1) (This is more specific and related to the problem I had) How can I know the default types for numbers, i.e., the Ts in default (T1, ...) being used at the moment in GHCi?
2) Is there a way to make typed code and loaded code behave the same always in GHCi? (excluding the differences related to the fact that typed code is run inside the IO Monad) For example, I should not have to include some kind of extension (e.g., ExtendedDefaultRules) so that the code in a file runs exactly as run in the prompt.
3) How can I invoke GHC and GHCi so that the same code shows the same behavior whether run via GHC or GHCi? (imagine I load the main file of an app and type run main in GHCi)
Thanks

Regarding point 3:
You can make code run exactly in the same way in both ghc and ghci:
use only pure and safe functions. By doing this you know that optimizations or side-effects will not show any different behaviour due to the implementation (as in the question you linked).
No special flag is required. If you do not follow this advice then there is no flag that allows to obtain what you want.
Regarding point 2:
You can make ghci recompile every file and use the interpreter version instead of loading the binary compiled by ghc so you can be sure the code will act as if typed by ghci instead of compiled by ghc. Use the :reload command to force recompilation.
Regarding the types and defaulting (point 1):
GHCi by default uses the extended defaulting rules, which are described here.
Standard defaulting rules basically default only "numbers" (i.e. Num, Fractional etc.). Extended rules are able to default types for things like Eq, Ord and Show.
Note that the default declaration implicit when using ExtendedDefaultRules is:
default ((), Integer, Double)
So, basically, any "free" Eq or Ord constraint is simply defaulted to ().
So you can simply specify ExtendedDefaultRules or NoExtendedDefaultRules to specify exactly which kind of defaulting you want.
This can be done putting the pragmas in the source files {-# LANGUAGE <extension-name> #-} or by specifying -X<extension-name> when compiling with ghc or by using the GHCi directive :set -X<extension-name>.
As noted by dfeur there is a fundamental difference between ghci and ghc: ghci must be able to completely infer the type of the input text when it is inserted. So, obviously, you have to arrange the declarations so that a function doesn't reference an undefined name.
Moreover type defaulting will be applied to each statement which means that, together with the monomorphism restriction (see: What is the monomorphism restriction? and https://wiki.haskell.org/Monomorphism_restriction) ghci may infer more monomorphic types than the ones inferred by ghc when compiling the same code.
You probably want to use NoMonomorphismRestriction when using GHCi (though recent versions of ghci have it disabled by default) and probably in your files too.

Related

Module Frames - TableTypes does not work

I am a data scientist familiar with languages such as R and python.
I have been trying to learn haskell for two months.
There is a module people employ to deal with frames in haskell similarly to common packages in those other languages (tidyverse in R and pandas in python).
The problem is: the common function for extracting data type for a csv is simply returning a message error:
tableTypes "base" "base.csv"
<interactive>:2:1: error:
• No instance for (Show Language.Haskell.TH.Lib.DecsQ)
arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
I cannot understand what this message means and I could not find any answer on Google. Could someone help me solve it?
Link to the module: http://hackage.haskell.org/package/Frames
You've stumbled into a case that's involves some advanced features of Haskell. The problem is that tableTypes "base" "base.csv" is a template haskell splice. For some reason, a few years back ghc was modified to allow bare expressions at the top level as splices, instead of requiring the standard splice syntax of $(expression generating code to splice).
But the bare expression syntax is incompatible with ghci. If you enter a bare expression in ghci, it tries to evaluate and print it (with some special rules for expressions that result in IO values).
When ghci evaluates tableTypes "base" "base.csv" it gets a result back that's not an instance of Show, because the template haskell Q environment is not printable. It contains a bunch of functions.
You have a few options here, depending on what you actually are trying to do. You could use runQ in ghci to dump the AST generated by the splice. That's probably not what you want. That's more likely to be a tool that's useful when you're developing a splice than for testing a library that uses them.
You could enable the TemplateHaskell extension within ghci and actually have it perform the splice interactively, but that's somewhat fiddly to get to work and you don't end up seeing much anyway.
I think the most practical solution is to move your code into a file. You can load said file from ghci if you desire - the important part is that in the context of a file, there's no longer any syntactic ambiguity - that's definitely a splice to evaluate while compiling, not an expression to evaluate interactively.

Ghc: partially compile Haskell code?

When I compile a Haskell file with ghci, typically with :load, and if there is no type error, all the expressions are loaded in the ghc interpreter. It's very nice: I can play around with :t to figure out the type of various expressions.
My problem is: if there is a tiny error somewhere, ghci is not able to load anything (not even the imported modules!!), which makes finding the right types even more difficult. I always do the same: comment out all the bits that do not typecheck, find the relevant types wiht :t in ghci, and de-comment.
But this is so tedious! Is there a better workflow for "partially compiling" a Haskell source code?
As #MikhailGlushenkov pointed out in the comments, the solution is to use the -fdefer-type-errors flag to GHCi.

Why did my mistake annotating this type signature not break things?

I had defined an alias for the function execState:
myCleverName = execState
GHC warned about a top-level binding with no annotated type signature, so I'd written:
myCleverName :: State s a => s -> s
Immediately obvious to most of you is that "fat arrow" => should have just been a regular skinny one ->. But I only just noticed that today, yet both the module containing the alias and the code using the alias have been compiling fine for weeks, with not so much as a warning that I used the wrong syntax. Why is that?
Thanks!
GHC 7.6.3 had a bug that allowed things like this but it's fixed (or should be) in GHC 7.8. Internally, type class constraints are represented as implicit function arguments and I think that's why 7.6.3 was confused. They still are represented that way, but the sanity checking has been improved.

How do you control type defaulting in doctests

How does doctest decide what type defaulting rules to use?
I have written several doctests that I would like to default to Double (because of RealFrac or Floating contexts) that are instead failing because they are defaulting to Integer and the relevant instances are (for good reason) missing.
I tried adding default (Integer, Double) to my $setup named chunk, to no apparent effect.
I tried adding the -XExtendedDefaultRules option to my invocation of doctest, also to no apparent effect. I did this even though I don't think my particular example actually requires the extended default rules.

Can I get warnings about overly-restrictive type signatures?

Can GHC or some lint tool tell me when I've provided a type signature for a function that could be more polymorphic?
GHC doesn't do this, and a quick search of Hackage turns up nothing.
A simple, but possibly quite effective way to implement such a thing would be to load the module in GHCi, use :browse to get all the type signatures, then load a copy without any type signatures, use :browse again, and compare the two outputs; then just print all the lines that differ beyond parentheses, whitespace and alpha-renaming. However, this wouldn't work perfectly, especially if you have definitions whose types can't be inferred.
I have a feeling such a tool would turn up a lot of false positives in practice.

Resources