Why are preconditions failing to work in this FsCheck example? - testing

I am trying to use the FsCheck library. I can do some tests but preconditions do not seem to work. The code below provides an example:
let sortEven (xs: int list) =
xs
|> List.filter (fun x -> x % 2 = 0)
|> List.sort
let lengthGT0 (xs: int list) = (List.length xs) > 0
[<Property>]
let checkSortEven (xs: int list) =
lengthGT0 xs ==>
((xs |> sortEven |> List.sum) = (xs |> List.rev |> sortEven |> List.max))
Calling the function checkSortEven with an empty list as its argument generates an exception because List.rev does the same. So, in the code above, I tried to use a precondition, using the ==> operator, to prevent the FsCheck from trying empty lists. However, whether the first list tested is empty or a shrunk list is empty checkSortEven is called an exception is generated:
Falsifiable, after 1 test (0 shrinks) (StdGen (843297067,296354622)):
Original:
[]
with exception:
System.ArgumentException: The input sequence was empty.
Falsifiable, after 1 test (1 shrink) (StdGen (1296284131,296354622)):
Original:
[-1]
Shrunk:
[]
with exception:
System.ArgumentException: The input sequence was empty.
Falsifiable, after 1 test (2 shrinks) (StdGen (1865393009,296354622)):
Original:
[-1; 1]
Shrunk:
[]
with exception:
System.ArgumentException: The input sequence was empty.
There is a related question on SO at Why is my precondition being ignored on my Property-based test? but it seems to be a different case (nested functions).
I also tried Check.QuickThrowOnFailure instead of Check.Quick with basically the same results.
Any ideas on why preconditions are not working in this example?

Related

Implementing map & min that takes the tables.keys iterator as argument in Nim

I would like to define overloads of map and min/max (as originally defined in sequtils) that works for tables.keys. Specifically, I want to be able to write something like the following:
import sequtils, sugar, tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
# Get the minimum X coordinate.
let minX = locations.keys.map(xy => xy[0]).min
echo minX
Now this fails with:
/usercode/in.nim(12, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
Below are my three attempts at writing a map that works (code on Nim playground: https://play.nim-lang.org/#ix=3Heq). Attempts 1 & 2 failed and attempt 3 succeeded. Similarly, I implemented min using both attempt 1 & attempt 2, and attempt 1 failed while attempt 2 succeeded.
However, I'm confused as to why the previous attempts fail, and what the best practice is:
Why does attempt 1 fail when the actual return type of the iterators is iterable[T]?
Why does attempt 2 fail for tables.keys? Is tables.keys implemented differently?
Is attempt 2 the canonical way of taking iterators / iterables as function arguments? Are there alternatives to this?
Attempt 1: Function that takes an iterable[T].
Since the Nim manual seems to imply that the result type of calling an iterator is iterable[T], I tried defining map for iterable[T] like this:
iterator map[A, B](iter: iterable[A], fn: A -> B): B =
for x in iter:
yield fn(x)
But it failed with a pretty long and confusing message:
/usercode/in.nim(16, 24) template/generic instantiation of `map` from here
/usercode/in.nim(11, 12) Error: type mismatch: got <iterable[(int, int)]>
but expected one of:
iterator items(a: cstring): char
first type mismatch at position: 1
required type for a: cstring
but expression 'iter' is of type: iterable[(int, int)]
... (more output like this)
From my understanding it seems to say that items is not defined for iterable[T], which seems weird to me because I think items is exactly what's need for an object to be iterable?
Attempt 2: Function that returns an iterator.
I basically copied the implementation in def-/nim-itertools and defined a map function that takes an iterator and returns a new closure iterator:
type Iterable[T] = (iterator: T)
func map[A, B](iter: Iterable[A], fn: A -> B): iterator: B =
(iterator: B =
for x in iter():
yield fn(x))
but this failed with:
/usercode/in.nim(25, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
func map[A, B](iter: Iterable[A]; fn: A -> B): B
first type mismatch at position: 1
required type for iter: Iterable[map.A]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
which hints that maybe tables.keys doesn't return an iterator?
Attempt 3: Rewrite keys using attempt 2.
This replaces tables.keys using a custom myKeys that's implemented in a similar fashion to the version of map in attempt 2. Combined with map in attempt 2, this works:
func myKeys[K, V](table: Table[K, V]): iterator: K =
(iterator: K =
for x in table.keys:
yield x)
Explanation of errors in first attempts
which hints that maybe tables.keys doesn't return an iterator
You are right. It does not return an iterator, it is an iterator that returns elements of the type of your Table keys. Unlike in python3, there seems to be no difference between type(locations.keys) and type(locations.keys()). They both return (int, int).
Here is keys prototype:
iterator keys[A, B](t: Table[A, B]): lent A
The lent keyword avoids copies from the Table elements.
Hence you get a type mismatch for your first and second attempt:
locations.keys.map(xy => xy[0]) has an incorrect first parameter, since you get a (int, int) element where you expect a iterable[A].
Proposals
As for a solution, you can either first convert your keys to a sequence (which is heavy), like hola suggested.
You can directly rewrite a procedure for your specific application, mixing both the copy in the sequence and your operation, gaining a bit in performance.
import tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
func firstCoordinate[X, Y, V](table: Table[(X, Y), V]): seq[X] =
result = #[]
for x in table.keys:
result.add(x[0])
let minX = locations.firstCoordinate.min
echo minX
This is not strictly adhering your API, but should be more efficient.

Elm specify number to me Int

I am trying to see if length of a given list equals some number. However == expects two numbers not Int, so even when I type (==) 1 type is still number -> Bool so finally when I pipe in result of lenght I get compilation error:
-- TYPE MISMATCH ---------------------------------------------------------- REPL
This function cannot handle the argument sent through the (|>) pipe:
4| List.length |> ((==) 1)
^^^^^^
The argument is:
List a -> Int
But (|>) is piping it to a function that expects:
number
Hint: Only Int and Float values work as numbers.
So how can I specify that my constant is an Int as opposed to number variable?
I think you might be overthinking this, checking for equality is as straight forward in Elm as in other languages.
myList = [1, 2, 3]
List.length myList == 3 // True
If you do want to use the (==) function, in case you're doing currying or for other reasons
List.length myList |> (==)
And then you could either store that as a variable or invoke it right away
List.length myList |> (==) 3 // True
OR
lengthChecker = List.length myList |> (==)
lengthChecker 3 // True
But I would say it's better to stick to the simple version of just doing the check with ==.
Just to expand on why your attempt wasn't compiling, the signature for (==) is (==) : a -> a -> Bool meaning it's a function that takes one argument, a, and returns a function that takes one argument, a and returns a Bool. So in your case ((==) 1) is a function that wants a number. When you do List.length |> ((==) 1) you're trying to call that function that expects a number with the List.length function itself.
Use >> to compose functions.
isLengthOne = List.length >> ((==) 1) is a function that checks that the length of a list is 1.
|> pipes the output of one statement to the input of the next.
So aList |> List.length |> ((==) 1) would check aList.

Using FsCheck I get different results on tests, once 100% passed and the other time error

I created a generator to generate lists of int with the same lenght and to test the property of zip and unzip.
Running the test I get once in a while the error
Error: System.ArgumentException: list2 is 1 element shorter than list1
but it shouldn't happen because of my generator.
I got three times the test 100% passed and then the error above. Why?
It seems my generator is not working properly.
let samelength (x, y) =
List.length x = List.length y
let arbMyGen2 = Arb.filter samelength Arb.from<int list * int list>
type MyGenZ =
static member genZip() =
{
new Arbitrary<int list * int list>() with
override x.Generator = arbMyGen2 |> Arb.toGen
override x.Shrinker t = Seq.empty
}
let _ = Arb.register<MyGenZ>()
let pro_zip (xs: int list, ys: int list) =
(xs, ys) = List.unzip(List.zip xs ys)
|> Prop.collect (List.length xs = List.length ys)
do Check.Quick pro_zip
Your code, as written, works for me. So I'm not sure what exactly is wrong, but I can give you a few helpful (hopefully!) hints.
In the first instance, try not using the registrating mechanism, but instead using Prop.forAll, as follows:
let pro_zip =
Prop.forAll arbMyGen2 (fun (xs,ys) ->
(xs, ys) = List.unzip(List.zip xs ys)
|> Prop.collect (List.length xs))
do Check.Quick pro_zip
Note I've also changed your Prop.collect call to collect the length of the list(s), which gives somewhat more interesting output. In fact your property already checks that the lists are the same length (albeit implicitly) so the test will fail with a counterexample if they are not.
Arb.filter transforms an existing Arbitrary (i.e. generator and filter) to a new Arbitrary. In other words, arbMyGen2 has a shrinking function that'll work (i.e. only returns smaller pairs of lists that are of equal length), while in genZip() you throw the shrinker away. It would be fine to simply write
type MyGenZ =
static member genZip() = arbMyGen2
instead.

Standard ML Syntax

I'm new to Standard ML and trying to write the following code
fun whilestat test stmt1 =
(fn x => if (test x) then (stmt1 x;whilestat test stmt1 ) else (x) );
The issue is that it gives me the following error
w.sml:21.6-22.82 Error: right-hand-side of clause doesn't agree with function result type [circularity]
expression: ('Z -> 'Y) -> 'Z -> 'Z
result type: ('Z -> 'Y) -> 'Z
in declaration:
whilestat2 = (fn arg => (fn <pat> => <exp>))
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:292.17-292.20
Im just trying to emaulate a while condition where if the staement is true then it recurses, else returns the value.
The issue lies in the return type of whilestat. In the then branch, you return a function, whereas in the else branch, you return return an arbitrary piece of data. I think you simply forgot to pass all of the arguments when you recurse in the then branch.
Here's how I would write it (notice also that there's no need to use fn x => ..., which I think contributed to your confusion).
fun whilestat test stmt1 x =
if test x
then (stmt1 x; whilestat test stmt1 x)
else x
In the future, you might find it helpful to explicitly annotate types in your source code, to double check your reasoning. I found your bug by trying to fill in the ??? below:
fun whilestat (test : 'a -> bool) (stmt1 : 'a -> unit) : ??? =
...

Make Test.QuickCheck.Batch use a default type for testing list functions

I am testing a function called extractions that operates over any list.
extractions :: [a] -> [(a,[a])]
extractions [] = []
extractions l = extract l []
where extract [] _ = []
extract (x:xs) prev = (x, prev++xs) : extract xs (x : prev)
I want to test it, for example, with
import Test.QuickCheck.Batch
prop_len l = length l == length (extractions l)
main = runTests "extractions" defOpt [run prop_len]
But this won't compile; I have to supply a type either for run or prop_len, because QuickCheck can't generate [a], it has to generate something concrete. So I chose Int:
main = runTests "extractions" defOpt [r prop_len]
where r = run :: ([Int] -> Bool) -> TestOptions -> IO TestResult
Is there any way to get QuickCheck to choose a for me instead of having it specified in the type of run?
The quickcheck manual says "no":
Properties must have monomorphic types. `Polymorphic' properties, such as the one above, must be restricted to a particular type to be used for testing. It is convenient to do so by stating the types of one or more arguments in a
where types = (x1 :: t1, x2 :: t2, ...)
clause...