Haskell: Property Based Testing for Higher Order Function - haskell

I have two properties that a function foo must satisfy:
prop_1 :: [Int] -> Bool
prop_1 xs = foo xs id == xs
prop_2 :: [Int] -> (Int -> Int) -> (Int -> Int) -> Bool
prop_2 xs f g = foo (foo xs f) g == foo xs (g . f)
I am trying to check whether the above properties satisfy the following function using quickCheck:
foo :: [a] -> (a -> b) -> [b]
foo xs f = []
When I tried running quickCheck with prop_2 I get the following error:
quickCheck(prop_2)
<interactive>:18:1: error:
No instance for (Show (Int -> Int))
arising from a use of 'quickCheck'
(maybe you haven't applied a function to enough arguments?)
In the expression: quickCheck (prop_2)
In an equation for 'it': it = quickCheck (prop_2)
I am not sure why I am getting this error and how I can resolve it. Any insights are appreciated.

You can use QuickCheck's support for generation of random shrinkable, showable functions by changing the property to
prop_2 :: [Int] -> Fun Int Int -> Fun Int Int -> Bool
prop_2 xs (Fn f) (Fn g) = foo (foo xs f) g == foo xs (g . f)
and then you'll see something more useful than <function> for counterexamples.

As the documentation on QuickCheck says:
However, before we can test such a property, we must see to it that function values can be printed (in case a counter-example is found). That is, function types must be instances of class Show. To arrange this, you must import module ShowFunctions into every module containing higher-order properties of this kind. If a counter-example is found, function values will be displayed as "<function>"
So you can fix this by importing a module like:
import Text.Show.Functions
prop_1 :: [Int] -> Bool
prop_1 xs = foo xs id == xs
prop_2 :: [Int] -> (Int -> Int) -> (Int -> Int) -> Bool
prop_2 xs f g = foo (foo xs f) g == foo xs (g . f)

Related

Trying to understand types in haskell library fused-effects

I am trying to understand hmap.
module Main where
import Control.Effect.Fresh
import Control.Effect.Carrier
a :: Fresh Maybe Int
a = Fresh (\n -> Just 5)
b :: Fresh Maybe [Int]
b = fmap (\n -> [7::Int]) a
f :: Maybe Int -> [] Int
f mi = [1]
c :: Fresh Maybe Int -> Fresh [] Int
c = hmap f
main :: IO ()
main = do
putStrLn "Just testing types"
ghc error:
• Couldn't match type ‘x’ with ‘Int’
‘x’ is a rigid type variable bound by
a type expected by the context:
forall x. Maybe x -> [x]
at src/Main.hs:16:5-10
Expected type: Maybe x -> [x]
Actual type: Maybe Int -> [Int]
• In the first argument of ‘hmap’, namely ‘f’
In the expression: hmap f
In an equation for ‘c’: c = hmap f
|
16 | c = hmap f
| ^
Why is there no match of x with Int?
The type signature of hmap is:
hmap :: Functor m => (forall x . m x -> n x) -> (h m a -> h n a)
My f function is declared in my code as:
f :: Maybe Int -> [] Int
f mi = [1]
Why is there no match between m x -> n x and Maybe Int -> [] Int
As you can see from the signature of hmap, it expects a function of type forall x. m x -> n x. The forall x in there means that it needs to work for all possible x, but your function only works for Int. It has the type m Int -> n Int (where m=Maybe and n=[]), but hmap requires m x -> n x for all possible x.
In order to use f with hmap, you need to define it in a generic way, such that it works for any argument type, for example
f :: forall x. Maybe x -> [] x
f (Just x) = [x]
f Nothing = []
(NOTE: forall x. is not necessary in this signature, but I included it to illustrate how f needs to match the first argument of hmap)
hmap has NOT this type
hmap :: Functor m => (m x -> n x) -> (h m a -> h n a)
but has this type instead:
hmap :: Functor m => (forall x . m x -> n x) -> (h m a -> h n a)
The difference is that, in the first (fake) type, you can choose the value of x. In the latter type, instead x is chosen by hmap (and not by you).
In your code, you pass f to hmap, which amounts to choosing x = Int, but you are not allowed to do that. You need to define an f which is able to work with any x, e.g.
f :: Maybe x -> [] x
f mi = []

How To Properly Choose Which USB Device To Connect To?

I am new to both USB drivers and Haskell. I am trying to connect to Tomu (an ARM micocontroller that fits in a USB port) using System.USB. I tried this example: https://github.com/basvandijk/usb-example/blob/master/example.hs, but it is several years out of date. I am trying to do hello world on USB, but getting type errors.
The following code works:
module Lib where
import System.USB
import System.USB.IO
import Data.Vector
import Data.Maybe
getOneDesc :: Int -> IO (VendorId, ProductId)
getOneDesc n = do
usbConn <- newCtx
devList <- getDevices usbConn
f <- getDeviceDesc $ devList ! n
let f0 = deviceVendorId f
let f1 = deviceProductId f
return (f0, f1)
At the repl, I can type getOneDesc 0 and I get something like this:
(300, 42)
I figured I ought to be able to do something like this:
isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> Bool
isThisDeviceTheOneIWant n a b = do
(x, y) <- getOneDesc n
return (x == a) && (y == b)
But I encounter type errors.
Can anybody see what's wrong with this?
Your getOneDesc is an IO (VendorId, ProductId), so that means that the result type of your return (x == a) && (y == b) has type IO Bool. So you should change the type of your function. You must also add parentheses around the argument you pass to return (because in Haskell, return is not a keyword, just a plain function).
isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = do
(x, y) <- getOneDesc n
return ((x == a) && (y == b))
You can not make the isThisDeviceTheOneIWant return a Bool, since the getOneDesc returns an IO (VendorId, ProductId), and you can not get an a out of an IO a.
We can, like #DanielWagner says, use fmap :: Functor f => (a -> b) -> f a -> f b to process the result of the getOneDesc n, like:
isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = fmap ((a, b) ==) (getOneDesc n)
or use (<$>) :: Functor f => (a -> b) -> f a -> f b which is the same as fmap:
isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = ((a, b) ==) <$> getOneDesc n

How to generate arbitrary two argument function with QuickCheck?

I am trying to test my implementation of zipWith using QuickCheck. My implementation, myZipWith, I would like to QuickCheck test by comparing to the standard function. Something like:
main = do
quickCheck (prop_myZipWith :: (Int -> Int -> Int) -> [Int] -> [Int] -> Bool)
prop_myZipWith :: (a -> b -> c) -> [a] -> [b] -> Bool
prop_myZipWith f x y = (myZipWith x y) == (zipWith f x y)
This does not work because (Int -> Int -> Int) is not an instance of Arbitrary.
With single-argument functions one can get around this using Test.QuickCheck.Function's Fun (which instantiates Arbitrary). For example:
main = do
quickCheck (prop_myMap :: Fun Int Int -> [Int] -> Bool)
prop_myMap :: Fun a b -> [a] -> Bool
prop_myMap (Fun _ f) l = (myMap f l) == (map f l)
I am trying to do something similar except generating two-argument arbitrary functions.
How can I generate arbitrary instances of two argument functions for QuickCheck testing of higher-order functions such as zipWith?
QuickCheck 2.9.2
With QuickCheck 2.9.2, you can use the Fun type, and the Fn pattern. You'll have to
import Test.QuickCheck.Function
You can then write the property using a tuple as input, and then curry the function:
prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn f) x y = myZipWith (curry f) x y == zipWith (curry f) x y
main looks like this:
main =
quickCheck (prop_myZipWith :: Fun (Int, Int) Int -> [Int] -> [Int] -> Bool)
This compiles, and the test passes, in my repro.
QuickCheck 2.10.0.1
With QuickCheck 2.10.0.1, you can instead use the Fn2 pattern, like this:
prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn2 f) x y = myZipWith f x y == zipWith f x y
The main method remains the same, because the type of prop_myZipWith hasn't changed, but import Test.QuickCheck.Function is no longer required.

Generalize function to fold both elements with one higher-kinded type and with two nested types?

I have next two elements:
x :: Maybe t
y :: [(String, t)]
And I have a function:
foo :: t -> a
How can I implement polymorphic function that can work both on x and y with foo to collect results in list? More specifically, I need to put something instead of ??? here:
mapToList :: ??? => (t -> a) -> ??? t -> [a]
And I want to call with less boilerplate possible, most closest option to this is preferable:
mapToList foo x
mapToList foo y
Something naive like this doesn't work :(
mapToList :: Foldable f => (t -> a) -> f t -> [a]
mapToList extractor = map extractor . toList
mapToList #Maybe foo x
mapToList #([] ((,) String)) foo y
I was looking at Compose but didn't manage to figure out how to apply it to my problem in nice simple way. I can use Compose to generalize somehow but my solution is not satisfactory. I can always use map for lists and just maybe [] foo on Maybe's. But I wonder, is there nice way to generalize both use cases?
Not sure this helps at all since it's just shifting the boilerplate away from the call site, but:
{-# LANGUAGE FlexibleInstances,FunctionalDependencies,RankNTypes #-}
import Data.Functor.Compose (Compose(Compose))
import Data.Foldable
class AsFoldable x a | x -> a where
withFoldable :: (forall f. (Foldable f) => f a -> b) -> x -> b
instance AsFoldable [(String,a)] a where
withFoldable f = f . Compose
instance AsFoldable (Maybe a) a where
withFoldable = id
x :: Maybe Int
x = Just 3
y :: [(String,Int)]
y = [("A",5),("B",6)]
mapToList :: (AsFoldable x t) => (t -> a) -> x -> [a]
mapToList f = withFoldable (map f . toList)
main = do
print $ mapToList (+1) x
print $ mapToList (+1) y

Function Definition in Haskell (GHCİ)

I am a beginner of Haskell. What is wrong with this expression?:
Prelude> let { f op [] = [] ; f op (h:t) = op h : f op t }
Prelude> f (+) []
<interactive>:337:1:
No instance for (Show (t0 -> t0))
arising from a use of `print'
Possible fix: add an instance declaration for (Show (t0 -> t0))
In a stmt of an interactive GHCi command: print it
Many thanks for support.
Function (+) has type (+) :: Num a => a -> a -> a and function f has type f :: (t -> a) -> [t] -> [a].
f expects a function of one argument.
f (+1) [] will be correct
Your function is inferred to have this type: (x -> y) -> [x] -> [y].
(+) has type Num a => a -> a -> a. This can be an instance of the type (x -> y) if we take x to be a and y to be a -> a, so all is fine. So the empty list in f (+) [] must be of type [a], and the return type must be [a -> a] (all of this with the same Num a constraint, of course). So f (+) [] correctly computes an empty list of type Num a => [a -> a].
This is all fine, but then GHCi wants to print the result of your expression. There is no way of printing values of type Num a => [a -> a], because there is no way to print functions. This is basically the error GHCi is giving you: No instance for (Show (t0 -> t0)).
There's nothing actually wrong with your function, or with your invocation of that function. It's just that it results in an (empty) list of functions, which you can't print. If you'd let bound it instead, you wouldn't get an error, and you could go on to do with it anything you would normally expect to be able to do with a Num a => [a -> a].
The type of the function f is:
Prelude> :t f
f :: (t -> a) -> [t] -> [a]
If you call the function like this:
Prelude> f (+) []
... you get the types (Let's pretend that (+) only works for Ints in this example):
(+) :: Int -> Int -> Int
(t -> a) = (Int -> (Int -> Int))
t = Int
a = (Int -> Int)
This means that the second argument to f is of type [t] = [Int] and the return type is [a] = [Int -> Int]. Because the return type is a list of functions, and functions cannot be shown, ghci will refuse to "compile" the expression because of the type errors, and you get the error that you see.
The f (+) [] function returns a list of functions:
Prelude> :t f (+) []
f (+) [] :: Num t => [t -> t]
And prelude trying to call show function on each element of the resulting list, however functions are not instances of the Show type class.

Resources