Testing a function that takes an empty list - unit-testing

I'm trying to write a unit test for the simple function that takes a list and just returns it,
func :: [a] -> [a]
func x = x
using the test code to test that it works as expected when given an empty list
emptyListTest :: Test
emptyListTest = TestCase $ assertEqual "for (func [])," [] $ func []
main :: IO Counts
main = runTestTT $ TestList [emptyListTest]
However, I get the error
No instance for (Show a0) arising from a use of `assertEqual'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Show Double -- Defined in `GHC.Float'
instance Show Float -- Defined in `GHC.Float'
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus 28 others
In the expression: assertEqual "for (func [])," []
In the second argument of `($)', namely
`assertEqual "for (func [])," [] $ func []'
In the expression:
TestCase $ assertEqual "for (func [])," [] $ func []
Other tests with non-empty lists work fine, and the function works fine when testing manually by calling func [] in ghci.
I've also noticed that if I create a dummy type, and make a list taking elements of that type (if that's the correct way of saying it), then passing that to the test seems to work, and the test passes
data Dummy = Dummy
deriving(Eq, Show)
emptyList :: [Dummy]
emptyList = []
emptyListTest :: Test
emptyListTest = TestCase $ assertEqual "for (func [])," [] $ func emptyList
Why is this? Is there a way to test functions with an empty list without going down the dummy type route?

Well, the error tells you exactly what is wrong. Read it.
The type variable `a0' is ambiguous
So, type your variable! GHC can't possibly know what type to use to test unless you do.
emptyListTest = TestCase $ assertEqual "for (func [])," [] $ func ([] :: [Int])
You may have to enable an extension to do it inline.

You need to provide a type for the empty list - otherwise GHC doesn't know what kind of list you are using.
One possible fix:
.... assertEqual "for (func [])," [] $ func ([] :: [Int])

Related

Haskell ambiguous type variable compiler error when foldMap on empty List

I'm trying to write a function that flattens nested Lists.
The code:
data NestedList a = Elem a | List [NestedList a]
flatten :: NestedList a -> [a]
flatten (Elem e) = [e]
flatten (List l) = foldMap flatten l
main = do
let c0 = List []
print $ flatten c0
When I try and provide an empty List from main I get a compiler error:
Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
I am wondering what causes this error and how to fix it.
Any help is much appreciated!
When you call print :: (Show a) => a -> IO (), the constraint on Show a needs to be solved somehow. In your case, the type of c0 is inferred to be NestedList a, which is of course not enough information to solve the Show [a] constraint from print $ flatten c0.
You solve this problem by adding a type signature to the binding of c0 to make it monomorphic.

Passing a randomly generated list as a parameter in Haskell

I am new to Haskell and really having trouble with the whole IO thing.
I am trying to find out how long it takes to traverse a list in haskell. I wanted to generate a list of random numbers and pass it as a parameter to a function so that I can print each element of the list. I am using CRITERION package for the benchmark. Here is the code:
{-# LANGUAGE OverloadedStrings #-}
import System.Random
import Control.Exception
import Criterion.Main
printElements [] = return ()
printElements (x:xs) = do print(x)
printElements xs
randomList 0 = return []
randomList n = do
x <- randomRIO (1,100)
xs <- randomList (n-1)
return (x:xs)
main = defaultMain [
bgroup "printElements" [ bench "[1,2,3]" $ whnf printElements (randomList 10)
, bench "[4,5,6]" $ whnf printElements [4,5,6,4,2,5]
, bench "[7,8,9]" $ whnf printElements [7,8,9,2,3,4]
, bench "[10,11,12]" $ whnf printElements [10,11, 12,4,5]
]
]
Error when I run the code:
listtraversal.hs:18:67:
Couldn't match expected type ‘[a0]’ with actual type ‘IO [t0]’
In the second argument of ‘whnf’, namely ‘(randomList 10)’
In the second argument of ‘($)’, namely
‘whnf printElements (randomList 10)’
Put briefly, you need to bind your function to the IO value, instead of trying to apply it to the value wrapped inside the IO value.
-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements
randomList does not return a list of values; it returns an IO action that, when executed, can produce a list of values. Ignoring the various constraints induced by the implementation, the type is
randomList :: (...) => t1 -> IO [t] -- not t1 -> [t]
As such, you can't directly work with the list of values that the IO action can produce; you need to use the monad instance to bind the value to an appropriate function. whnf printElements is one such function; it takes a list and returns an IO action.
whnf printElements :: Show a => [a] -> IO ()
Instead of pulling the list out and passing it to whnf printElements, we "push" the function into an IO value using >>=. That operator's type, specialized to the IO monad, is
(>>=) :: IO a -> (a -> IO b) -> IO b
In this case, the first IO a value is the IO [t] value returned by randomList. whnf printElements is the a -> IO b function we bind to.
The result is a new IO value that take the first IO value, pulls out the wrapped value, applies the given function, and returns the result.
In other words, the IO monad itself takes care of pulling apart the result from randomList and applying your function to it, rather than you doing it explicitly.
(You might have noticed that I've said that >>= binds a value to a function and vice versa. It is perhaps more accurate to say that >>= binds them together into a single IO action.)

Not typed empty list : Haskell

I just tried to write the simplest maybe function I could imagine in Haskell, and got this error message. And magically it only appears, when I try to evaluate myHead for an empty list. What did I do wrong?
module Main
where
myHead :: [a] -> Maybe a
myHead [] = Nothing
myHead (x:_) = Just x
main = do
print (myHead [])
When I run it from a file, I get this output :
main.hs:15:1: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
... plus 22 others
...plus 12 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of a 'do' block: print (myHead [])
In the expression: do { print (myHead []) }
In an equation for ‘main’: main = do { print (myHead []) }
<interactive>:3:1: error:
• Variable not in scope: main
• Perhaps you meant ‘min’ (imported from Prelude)
There's nothing wrong with myHead, you would have the same issue if you used:
main = do
print Nothing
The issue here is that Nothing and myHead [] have a polymorphic type Maybe a, for any a. Then, print is called to write that value. For that, print has to require that Maybe a is convertible to string: it does that by requiring Show (Maybe a), which in turn it requires Show a.
However, there is no universal instance of Show a: the compiler now needs to know what a is before it can convert that to string.
Note this
print (Just 3 :: Maybe Int) -- OK
print (Just id :: Maybe (Int->Int)) -- Not OK! Functions can not be printed
The solution is to use a concrete type for your code
main = do
print (myHead [] :: Maybe Int) -- or any other showable type

Writing test cases in Haskell for differing types

I've made a library that creates "list like" sequences, and of which many Prelude style functions are implemented. I want to write some test cases for this, to ensure my library is producing correct output, and I thought the easiest way to do this is write some functions, convert the results to lists and compare them to the Prelude results. Lets say we've got this:
import qualified MyLibrary as ML
import qualified Prelude as P
For example I may want the following testcase:
P.take 5 (P.enumFrom 1) == toList (ML.take 5 (ML.enumFrom 1))
Note that ML.enumFrom does not output a list, it outputs it's own datatype.
The above works fine, but notice how I'm "repeating myself" (TM). I have to ensure the left and right side are the same otherwise my test case is erroneous.
Is there a nice way to write test cases like this so I don't have to repeat myself?
The first problem that P.take and ML.take, etc., only look similar – in fact they are totally unrelated functions and the compiler doesn't know anything about their common behaviour. So, as #jd823592 proposed, we need to group them with a typeclass (I used a simple newtype wrapper so the example would be compilable):
import Prelude hiding (take, enumFrom)
import qualified Prelude as P (take, enumFrom)
newtype MySeq a = MySeq [a]
class Sequence s where
take :: Int -> s a -> s a
enumFrom :: Enum a => a -> s a
toList :: s a -> [a]
instance Sequence MySeq where
take n (MySeq xs) = MySeq (P.take n xs)
enumFrom n = MySeq (P.enumFrom n)
toList (MySeq xs) = xs
instance Sequence [] where
take = P.take
enumFrom = P.enumFrom
toList = id
Then we'll try to define some tests using now-unified functions from the class definition. They may just generate a Sequence of any type, and we'll then force them to produce explicit types.
test1 = doTest (take 5 $ enumFrom 1) -- the part in brackets is polymorphic
doTest :: (Eq a, Sequence s) => s a -> Bool
doTest test = ???
Now the second problem is that we pass a polymorphic function as a parameter and then need to instantiate it with different type parameters ([a] and MySeq a in this case). In standard Haskell 2010 it is impossible, but we can exploit the Rank2 (or RankN) extension:
{-# LANGUAGE Rank2Types #-}
<...>
doTest :: forall a . Eq a => (forall s . Sequence s => s a) -> Bool
doTest test = (test `asTypeOf` dummy1) == toList (test `asTypeOf` dummy2) where
dummy1 :: Eq a => [a]
dummy1 = undefined
dummy2 :: Eq a => MySeq a
dummy2 = undefined
This solution is a bit clumsy, but still works. Please feel free to improve.

Propagating errors to cause HUnit tests to fail

I am writing an HUnit test for a function eval :: Wff -> Assignment -> Maybe Bool. Wff is a custom data type which is an abstract parse tree for a simplified subset of boolean expressions:
data Wff = Var Name
| Not Wff
| Or Wff Wff
deriving (Eq)
and Assignment is a type alias for an associative list which gives a boolean value for each variable in a Wff:
type Assignment = [(Name, Bool)]
My current test looks like this:
testEval :: Test
testEval = "Test eval"
~: TestList $ zipWith (\e (Just a) -> e ~=? a) expected (eval wff <$> assignments)
where expected = [True, False]
assignments = [[('p', True)], [('p', False)]]
Right wff = parse wffStr
wffStr = "p"
Both of the tests constructed pass. However, the test is not very robust. If I modify it with a more complicated value for wffStr but make a typo, the pattern Right wff will fail because parse will return a Left String instead of a Rigth Wff. This causes the test run to abort and I'd rather get a failure for the few bad tests and the actual results for the rest. How can I modify my current structure so that the error propagates to cause the test to fail instead of aborting all together?
I don't know anything about HUnit, but: can you just tell it what to do when the parse fails?
testEval = case parse wffStr of
Left _ -> {- use HUnit's functions to make a failing test case -}
Right wff -> "Test eval" ~: TestList $ {- ... -}
where expected = [True, False]
{- ... -}