Unit-testing the undefined evaluated in lazy expression in Haskell - unit-testing

Writing a unit test in Haskell where an expression should fail when undefined is encountered is a bit tricky. I tried the following with HSpec:
module Main where
import Test.Hspec
import Control.Exception (evaluate)
main :: IO ()
main = hspec $ do
describe "Test" $ do
it "test case" $ do
evaluate (take 1 $ map (+1) [undefined, 2, 3]) `shouldThrow` anyException
to no avail. It reports me did not get expected exception: SomeException
If I evaluate the same expression in REPL, I'd get:
[*** Exception: Prelude.undefined
CallStack (from HasCallStack):
error, called at libraries\base\GHC\Err.hs:79:14 in base:GHC.Err
undefined, called at <interactive>:2:20 in interactive:Ghci1

The problem is that evaluate doesn't force your expression to NH or even WHNF1. Try x <- evaluate (take 1 $ map (+1) [undefined, 2, 3]) in GHCi - it doesn't give you any error! The only reason it does when you paste in evaluate (take 1 $ map (+1) [undefined, 2, 3]) is that GHCi also tries to print the result of what it got and, to do that, it ends up trying to evaluate the expression.
If you want to see how much of a thunk has been evaluated, you can always use :sprint in GHCi:
ghci> x <- evaluate (take 1 $ map (+1) [undefined, 2, 3])
ghci> :sprint x
x = [_]
As you can see, evaluate hasn't forced the expression far enough to realize x contains an undefined. A quick fix is to evaluate the thing you are examining to normal form using force.
import Test.Hspec
import Control.Exception (evaluate)
import Control.DeepSeq (force)
main :: IO ()
main = hspec $ do
describe "Test" $ do
it "test case" $ do
evaluate (force (take 1 $ map (+1) [undefined, 2, 3] :: [Int]))
`shouldThrow` anyException
force lets you trigger the evaluation of thunks until the argument is full evaluated. Note that it has an NFData (stands for "normal form data") constraint on it, so you may find yourself deriving Generic and NFData for your data structures.
1 Thanks for #AlexisKing for pointing out that evaluate does push its argument into WNHF, which is why head $ map (+1) [undefined, 2, 3] does trigger the error. In the case of take, it isn't enough though.

Related

How to get rid of sub lists of a list in a list in Haskell?

I'm kinda new to Haskell and would like to know how to do the following:
L = [[1,2],[1,2,3],[1,2,3,4]]
How do I get rid of all the sub list ([1,2], [1,2,3]) and get a result of [[1,2,3,4]] only?
If I understood problem right, the solution can be like below:
import Data.List
-- Get only if element is not subsequence of any other x element
filterOutSublists x = filter (not . (isSub)) x
where
-- Check if given element is subsequence of any of x element
isSub y = foldl (\acc y' -> acc || (y `elem` (init $ subsequences y'))) False x
But this solution has very bad O(n) complexity, so it is useless for long lists.
You can use concat to flatten the sublists, then, since you want to get rid of the duplicates, you can use Data.Set to convert it to a set and back again to a list-
import qualified Data.Set as Set
f = (:[]) . Set.toList . Set.fromList . concat
Output
λ> f [[1,2],[1,2,3],[1,2,3,4]]
[[1,2,3,4]]
λ> f [[1, 2], [3, 4]]
[[1,2,3,4]]
Note that the final (:[]) is just there to put the final result inside a surrounding list, which is what you have shown in your example - though I don't quite know what even is the point of that.
If you want the results to be just one list instead of a list surrounded by another list, remove the (:[]) composition.

Why does feeding init to last not work in Haskell?

So I'm writing a line to get the second to last element of a list. Initially my code was
mySLast x = last.take ((length x) - 1) x
Which worked up until the last function. Realized the my take business is already included in Haskell as init so I rewrote as
mySLast = last.init
This still doesn't work. I find this puzzling because init::[a]->[a] and last::[a]->a so they definitely should be composable morphisms in the Hask Category.
I tried asking Haskell what it thinks the type is and it said
ghci> :t last.init
last.init :: [c] -> c
ghci> last.init [3,2,4,1]
<interactive>:45:6:
Couldn't match expected type ‘a -> [c]’
with actual type ‘[Integer]’
Relevant bindings include
it :: a -> c (bound at <interactive>:45:1)
Possible cause: ‘init’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘init [3, 2, 4, 1]’
In the expression: last . init [3, 2, 4, 1]
Even though
ghci> init [3,2,4,1]
[3,2,4]
ghci> last [3,2,4]
4
So I must be misunderstanding something about composing functions in Haskell. Any insight would be greatly appreciated!
Function application binds more tightly than (.) so
last.init [3,2,4,1]
is being parsed as
last . (init [3,2,4,1])
you can use
(last . init) [3,2,4,1]
or
last . init $ [3,2,4,1]
You forgot the $ between init and your list, e.g.
last . init $ [3,2,4,1]
↑ See here
An alternative solution to this problem that only evaluates the (spine of the) list up to the needed element, rather than using length (which will evaluate the entire spine before walking back to the needed element):
takeTail n xs = go (drop n xs) xs
where
go (_:ys) (_:xs) = go ys xs
go [] xs = xs -- Stop and return xs when ys runs out
> head . takeTail 2 $ [1,2,3,4]
3

Few questions about sml zip function

I am new to sml, now I am trying to define a zip function which takes two lists as a tuple.
here are the code.
I got it working, but I have a few questions
exception Mismatch;
fun zip ([],[]) = []
| zip ((x::xs),(y::ys)) = (x, y)::zip (xs, ys)
| zip (_, _) = raise Mismatch;
Can I define the exception inside zip function, like let in end, I tried, but always get error.
Another question is for the second pattern matching, I wrote
zip ([x::xs],[y::ys]) = (x, y)::zip (xs, ys)
also gave me error.
Zip take a tuple, but each of the element is list, why can't I use [x::xs] just like other list?
last question, in pattern matching, does the order matter? I think it is, I change the order and got error, just want to make sure
Thanks
You should never define an exception inside of a let ... in ... end*. It makes it impossible to catch it by name outside of the let-expression.
*: It's okay if you don't plan on letting it escape from the let-expression, but you do plan on doing that here.
As for your other question:
When you write [...], the SML compiler understands it as "The list containing ...."
E.g, [1] is the list containing 1, [4, 6, 2] is the list containing 4, 6 and 2, and so on.
When you write x :: xs, the SML compiler understands it as "The list starting with x, followed by the list xs."
E.g. 1 :: [] is the list starting with a 1, followed by the empty list, and 4 :: [6, 2] is the list starting with a 4, followed by 6 and 2, and so on.
Now, when you write [x :: xs], you're doing a combination of the two, and SML understands it as: "The list containing the list starting with x, followed by xs."
So, by writing [...] rather than (...), you're asking for a list within another list. This is not what you want.
For your final question: Yes, order matters. Patterns are checked in top-down order. Therefore,
fun foo _ = 4
| foo 4 = 5
will always return 4, whereas
fun foo 4 = 5
| foo _ = 4
will return 5 when given a 4.

quickCheckAll always return "True"

I'm trying to use QuickCheck following another answer.
I test like this:
{-# LANGUAGE TemplateHaskell #-}
import Test.QuickCheck
import Test.QuickCheck.All
last' :: [a] -> a
last' [x] = x
last' (_:xs) = last' xs
prop_test x = last' x == last x
check = do
putStrLn "quickCheck"
quickCheck (prop_test :: [Char]-> Bool)
check2 = do
putStrLn "quickCheckAll"
$quickCheckAll
Then I load it in winGHCI and call check and check2. I get
quickCheck
*** Failed! (after 1 test):
Exception:
list.hs:(7,1)-(8,23): Non-exhaustive patterns in function last'
""
which I think it's reasonable. However, I get this from check2
quickCheckAll
True
I'm confused because no matter how I change the last' function, even wrong, quickCheckAll always return True.
What's wrong with my code? How can I fix this?
From the Test.QuickCheck.All docs:
To use quickCheckAll, add a definition to your module along the lines of
return []
runTests = $quickCheckAll
and then execute runTests.
Note: the bizarre return [] in the example above is needed on GHC 7.8; without it, quickCheckAll will not be able to find any of the properties.
Adding return [] before your check makes it work for me.
To use quickCheckAll, you need a function which reads:
return []
runTests = $quickCheckAll
The other comment mentions this, but doesn't point out that it will still always return true unless the function is located below all of your quickCheck functions!

Adding a Show instance to RWH's RandomState example

I have just typed in the RandomState example from real world haskell. It looks like this:
import System.Random
import Control.Monad.State
type RandomState a = State StdGen a
getRandom :: Random a => RandomState a
getRandom =
get >>= \gen ->
let (val, gen') = random gen in
put gen' >>
return val
getTwoRandoms :: Random a => RandomState (a, a)
getTwoRandoms = liftM2 (,) getRandom getRandom
It works, but the result doesn't get displayed. I get the error message:
No instance for (Show (RandomState (Int, Int)))
arising from a use of `print' at <interactive>:1:0-38
Possible fix:
add an instance declaration for (Show (RandomState (Int, Int)))
In a stmt of a 'do' expression: print it
I am having some trouble adding an instance for Show RandomState. Can anyone show me how this is done?
Thanks.
For the sake of being explicit, as jberryman and the comments on the question imply: Something of type RandomState (a, a) is a function, not a value. To do anything with it, you want to run it with an initial state.
I'm guessing you want something like this:
> fmap (runState getTwoRandoms) getStdGen
((809219598,1361755735),767966517 1872071452)
This is essentially what the runTwoRandoms function a bit further in RWH is doing.
Since RandomState is a synonym for State and there isn't an instance of show defined for State, you won't be able to show it.
You would also not be able to derive show because State is just a wrapper for a function and Haskell has no way to define a show for functions that would be useful:
Prelude> show (+)
<interactive>:1:0:
No instance for (Show (a -> a -> a))
arising from a use of `show' at <interactive>:1:0-7
Possible fix: add an instance declaration for (Show (a -> a -> a))
In the expression: show (+)
In the definition of `it': it = show (+)
EDIT: Forgot to add the other piece: GHCi is giving you that error because it uses show behind the scenes on the expressions you enter... REPL and all that.