How can I run multiple statements in GHCi? - haskell

I'm doing some very simple performance testing of a simple function that I believe has O(n)(squared) performance (or worse).
Currently I'm running multiple statements which is tedious to repeat:
ghci> myfunction 0 100
true
ghci> myfunciton 0 200
true
ghci> myfunction 0 300
true
ghci> :r
Is there a way I can run all four GHCi statements? I can't just combine them using "native" Haskell as I'd like to include the :r (which is a GHCi statement - not exactly Haskell) that gets run at the end.

One way I've found is creating a separate file:
myfunction 0 100
myfunction 0 200
myfunction 0 300
:r
and then using:
:script path/to/file

You can define a custom GHCi command using :def in this way:
> :def foo (\_ -> return "print 100\nprint 200\n:t length")
> :foo
100
200
length :: Foldable t => t a -> Int
In the returned string, :-commands can be included as well, like :t above.

One way of doing it is to create a testing suite in your Cabal file in which you place your function calls as tests, then use stack test --file-watch. That recompiles and reruns the tests every time you save a file.

Related

Custom QuickCheck failed message

test1 = hspec $ do
describe "blabla" $ do
it "should be equl" $ verbose $
\input-> ...
In the above code, when a test failed, it prints the failed input. But I'm actually interested in another value that can be calculated from input. Can I ask QuickCheck to print the other value?
Somehow I've never seen it advertised, but you can use hspecs expectations inside of QuickCheck properties. Here is an example:
describe "blabla" $ do
it "should be equl" $ verbose $ \input ->
round input `shouldBe` floor (input :: Double)
Above property is clearly not true, so it should fail. Since we are not only interested input, but also want to know the computed values from it, shouldBe will give us just that:
3) blabla should be equl
Falsifiable (after 2 tests and 4 shrinks):
0.6
expected: 0
but got: 1
Naturally, due to verbose, only input will be printed for passing tests, while computed value (eg. round input) will only be printed for a failed test case, which is what you were looking for it seems anyways.

Why doesn't this cause stackoverflow?

In 8.hs I define
digitProduct [] = 1
digitProduct (c:rest) = (read [c] :: Int) * digitProduct rest
Then inside ghci, I run
digitProduct $ take 10000 $ repeat '9'
And it produces a result:
-3633723290617080191
I would've imagined that a recursion of 10000 would've caused a stackoverflow. Also, my recursion isn't a tail call. What's going on here?
Nothing special is going on. 10,000 is just not enough to fill the stack. I get a stack overflow in ghci when I replace take 10000 with take 100000000.

unreadable quickcheck log file after a test routine

I made a test routine for a Haskell program with quickcheck. I declared it in my cabal file with :
Test-Suite routine_de_test
Type: exitcode-stdio-1.0
Hs-Source-Dirs: test
Main-is: Tests.hs
and launched it with :
cabal configure --enable-tests
cabal buil
cabal test
The tests are processed correctly and I was expecting to see details about the random value used for each test in the log file dist/test/ but when I open it, the file looks like this :
I tried to open the file with several encoding (UTF8, ISO-8859-15, ...) but nothing is changed.
Is it normal? Or is there something wrong?
Is it possible when performing quickcheck test from cabal to get the complete list of random values used for each tests?
It looks like the funny characters are simply backspaces, and quickcheck is simply reporting the number of tests it has performed so far by overwriting (0 tests) with (1 test) and then (2 tests) and then with (3 tests), etc.
Visually it will look fine when displayed to a terminal.
Update:
To report the random values used for a test the only way I know of is to write your test to explicitly display (or save to a file) the values used.
If your test is a pure function you can use the trace function from Debug.Trace. For instance, if you have this property:
prop_commutes :: Int -> Int -> Bool
prop_commutes a b = a + b == b + a
You can trace each invocation of prop_commutes by modifying like this:
import Debug.Trace
prop_commutes :: Int -> Int -> Bool
prop_commutes x y = a + b == b + a
where (a,b) = trace ("(a,b) = " ++ show (x,y)) (x,y)
and then quickCheck prop_commutes will emit lines like:
(x,y) = (20,-73)
(x,y) = (71,-36)
(x,y) = (2,-11)
...
in addition to its normal output.

I taught ghci to compile my StackOverflow posts. Can I make it slicker?

Haskell Stack Overflow layout preprocessor
module StackOverflow where -- yes, the source of this post compiles as is
Skip down to What to do to get it working if you want to play with this first (1/2 way down).
Skip down to What I would like if I witter on a bit and you just want to find out what help I'm seeking.
TLDR Question summary:
Can I get ghci to add filename completion to the :so command I defined in my ghci.conf?
Could I somehow define a ghci command that returns code for compilation instead of returning a ghci command, or
does ghci instead have a better way for me to plug in Haskell code as a
file-extension-specific pre-processor, so :l would work for .hs and .lhs files as usual, but use my handwritten preprocessor for .so files?
Background:
Haskell supports literate programming in .lhs source files, two ways:
LaTeX style \begin{code} and \end{code}.
Bird tracks: Code starts with > , anything else is a comment.
There must be a blank line between code and comments (to stop trivial accidental misuse of >).
Don't Bird tracks rules sound similar to StackOverflow's code blocks?
References: 1. The .ghci manual
2. GHCi haskellwiki
3. Neil Mitchell blogs about :{ and :} in .ghci
The preprocessor
I like writing SO answers in a text editor, and I like to make a post that consists of code that works,
but end up with comment blocks or >s that I have to edit out before posting, which is less fun.
So, I wrote myself a pre-processor.
If I've pasted some ghci stuff in as a code block, it usually starts with * or :.
If the line is completely blank, I don't want it treated as code, because otherwise
I get accidental code-next-to-comment-line errors because I can't see the 4 spaces I accidentally
left on an otherwise blank line.
If the preceeding line was not code, this line shouldn't be either, so we can cope with StackOverflow's
use of indentation for text layout purposes outside code blocks.
At first we don't know (I don't know) whether this line is code or text:
dunnoNow :: [String] -> [String]
dunnoNow [] = []
dunnoNow (line:lines)
| all (==' ') line = line:dunnoNow lines -- next line could be either
| otherwise = let (first4,therest) = splitAt 4 line in
if first4 /=" " --
|| null therest -- so the next line won't ever crash
|| head therest `elem` "*:" -- special chars that don't start lines of code.
then line:knowNow False lines -- this isn't code, so the next line isn't either
else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too
but if we know, we should keep in the same mode until we hit a blank line:
knowNow :: Bool -> [String] -> [String]
knowNow _ [] = []
knowNow itsCode (line:lines)
| all (==' ') line = line:dunnoNow lines
| otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
Getting ghci to use the preprocessor
Now we can take a module name, preprocess that file, and tell ghci to load it:
loadso :: String -> IO String
loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- so2bird each line
>>= writeFile (fn++"_so.lhs") -- write to a new file
>> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")
I've used silently redefining the :rso command becuase my previous attemts to use
let currentStackOverflowFile = .... or currentStackOverflowFile <- return ...
didn't get me anywhere.
What to do to get it working
Now I need to put it in my ghci.conf file, i.e. in appdata/ghc/ghci.conf
as per the instructions
:{
let dunnoNow [] = []
dunnoNow (line:lines)
| all (==' ') line = line:dunnoNow lines -- next line could be either
| otherwise = let (first4,therest) = splitAt 4 line in
if first4 /=" " --
|| null therest -- so the next line won't ever crash
|| head therest `elem` "*:" -- special chars that don't start lines of code.
then line:knowNow False lines -- this isn't code, so the next line isn't either
else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too
knowNow _ [] = []
knowNow itsCode (line:lines)
| all (==' ') line = line:dunnoNow lines
| otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- convert each line
>>= writeFile (fn++"_so.lhs") -- write to a new file
>> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")
:}
:def so loadso
Usage
Now I can save this entire post in LiterateSo.so and do lovely things in ghci like
*Prelude> :so StackOverflow
[1 of 1] Compiling StackOverflow ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.
*StackOverflow> :rso
[1 of 1] Compiling StackOverflow ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.
*StackOverflow>
Hooray!
What I would like:
I would prefer to enable ghci to support this more directly. It would be nice to get rid of the intermediate .lhs file.
Also, it seems ghci does filename completion starting at the shortest substring of :load that determines
you're actually doing load, so using :lso instead of :so doesn't fool it.
(I would not like to rewrite my code in C. I also would not like to recompile ghci from source.)
TLDR Question reminder:
Can I get ghci to add filename completion to the :so command I defined in my ghci.conf?
Could I somehow define a ghci command that returns code for compilation instead of returning a ghci command, or
does ghci instead have a better way for me to plug in Haskell code as a
file-extension-specific pre-processor, so :l would work for .hs and .lhs files as usual, but use my handwritten preprocessor for .so files?
I would try to make a standalone preprocessor that runs SO preprocessing code or the standard literary preprocessor, depending on file extension. Then just use :set -pgmL SO-preprocessor in ghci.conf.
For the standard literary preprocessor, run the unlit program, or use Distribution.Simple.PreProcess.Unlit.
This way, :load and filename completion just work normally.
GHCI passes 4 arguments to the preprocessor, in order: -h, the label, the source file name, and the destination file name. The preprocessor should read the source and write to the destination. The label is used to output #line pragmas. You can ignore it if you don't alter the line count of the source (i.e. replace "comment" lines with -- comments or blank lines).

How to test my haskell functions

I just started with Haskell and tried to do write some tests first. Basically, I want to define some function and than call this function to check the behavior.
add :: Integer -> Integer -> Integer
add a b = a+b
-- Test my function
add 2 3
If I load that little script in Hugs98, I get the following error:
Syntax error in declaration (unexpected `}', possibly due to bad layout)
If I remove the last line, load the script and then type in "add 2 3" in the hugs interpreter, it works just fine.
So the question is: How can I put calls of my functions in the same script as the function definition? I just want to load the script and be able to check if it does what I expect it to...I don't want to type them in manually all the time.
Others have said how to solve your immediate problem, but for testing you should be using QuickCheck or some other automated testing library.
import Test.QuickCheck
prop_5 = add 2 3 == 5
prop_leftIdentity n = add 0 n == n
Then run quickCheck prop_5 and quickCheck prop_leftIdentity in your Hugs session. QuickCheck can do a lot more than this, but that will get you started.
(Here's a QuickCheck tutorial but it's out of date. Anyone know of one that covers QuickCheck 2?)
the most beginner friendly way is probably the doctest module.
Download it with "cabal install doctest", then put your code into a file "Add.hs" and run "doctest Add.hs" from the command line.
Your code should look like this, the formatting is important:
module Add where
-- | add adds two numbers
--
-- >>> add 2 3
-- 5
-- >>> add 5 0
-- 5
-- >>> add 0 0
-- 0
add :: Integer -> Integer -> Integer
add a b = a+b
HTH Chris
Make a top level definition:
add :: Integer -> Integer -> Integer
add a b = a + b
test1 = add 2 3
Then call test1 in your Hugs session.
How can I put calls of my functions in the same script as the function definition? I just want to load the script and be able to check if it does what I expect it to...I don't want to type them in manually all the time.
In short, you can't. Wrap it in a function and call it instead. Your file serves as a valid Haskell module, and having "flying" expression is not a valid way to write it.
You seem to come from a scripting language background, but don't try treating Haskell as one of them.
If you have ghc installed, then the runhaskell command will interpret and run the main function in your file.
add x y = x + y
main = print $ add 2 3
Then on the command line
> runhaskell Add.hs
5
Not sure, but hugs probably has a similar feature to the runhaskell command. Or, if you load the file into the hugs interpreter, you can simply run it by calling main.
I was trying to do the same thing and I just made a function that ran through all my test cases (using guards) and returned 1 if they all passed and threw an error if any failed.
test :: Num b => a->b
test x
| sumALL [1] /= 1 = error "test failed"
| sumALL [0,1,2] /= 3 = error "test failed"
...
| otherwise = 1

Resources