help needed to improve my library (quickcheck)

39 views
Skip to first unread message

ebmtra...@gmail.com

unread,
May 1, 2013, 9:18:21 PM5/1/13
to pure...@googlegroups.com
Hi all,
I know Haskell rather well and I always find its QuickCheck tool very pleasant so I decided to try to implement it in pure.
So here it is (there is a download link at the beginning of the post):

http://purelibs.blogspot.fr/2013/05/quickcheck-tutorial-000.html

Its development is at a very early stage but I already like the way the arguments of a function can be manipulated out of the function, thanks to the get_fundef function.
As a matter of fact, this is that same function that make me wonder.
If I understand well, a function defined as

> f x y = somecomputation x y

implies that get_fundef f will output something useful whereas if

> g = \ x y -> process x y

then g is a closure and get_fundef can't evaluate it. Is it correct ?

My question is about manipulating the arguments of g the same way get_fundef permits the manipulation of the f arguments. Is it possible ? For a concrete application, I need to enable a quickcheck user to define properties the f way as well as the g way, then, whatever way is chosen, the quickcheck function parses the property (see get_types), chooses the right arguments (see arbitrary in the source), and applies the property to the arguments.  At the moment, only the f way is coded:

get_types f = go ((\[a-->_]->a) $ get_fundef f) [] with
  go g ts = if ~(applp g) then ts else go (next g) (get_type g : ts);
  get_type = (\ (_ __type__ t) -> t) . (\ (_@_ x) -> x);
  next = (\ (x@_ _) -> x);
end;

quickcheck prop = catch falsified (go 0) with
  go 100 = puts "OK, passed 100 tests." $$ ();
  go i   = if apply prop args
             then go (i+1)
             else throw (args,i) when args = map arbitrary (get_types prop) end;
  falsified (args,i) = puts ("Falsifiable, after " + str i + " tests:\n" + str args) $$ ();
  apply f []     = f;
  apply f (a:as) = apply (f a) as
end; 

(please, see the post and the source for the context and all details).

By the way, any advice on the code or anything else is welcome!


Albert Graef

unread,
May 3, 2013, 2:09:44 AM5/3/13
to pure...@googlegroups.com
On Thu, May 2, 2013 at 3:18 AM, <ebmtra...@gmail.com> wrote:
> I know Haskell rather well and I always find its QuickCheck tool very
> pleasant so I decided to try to implement it in pure.

That's wonderful, I can't wait to try it out! (Unfortunately, I still
have some stuff to prepare for the upcoming LAC conference, so this
will have to wait a bit. But this is one of the sorely missing pieces
in the Pure ecosystem, so I'll surely get back to you on it.)

Albert

--
Dr. Albert Gr"af
Dept. of Music-Informatics, University of Mainz, Germany
Email: agg...@gmail.com
WWW: http://www.musikinformatik.uni-mainz.de/ag

Alastair Pharo

unread,
May 3, 2013, 2:42:09 AM5/3/13
to pure...@googlegroups.com
Hi there,

A bit late perhaps, but I too had a shot at a quickcheck-type function.
The code a bit raw but I've put it up on bitbucket so you can take a
look:

https://bitbucket.org/asppsa/pure-ptest/overview

testtest.pure shows the kinds of tests that can be done. I stopped
working on the quickcheck part a little while ago in favour of a more
Rspec-like assertion system (the "a should b" expressions), and
apparently the quickcheck part doesn't entirely work anymore. Anyway,
you're welcome to make use of it in your own code (in accordance with
the BSD license) if you see anythin of value there. Perhaps we can pool
efforts on this somehow?

I've made a comment below about get_fundef too:

ebmtra...@gmail.com writes:

> If I understand well, a function defined as
>
>> f x y = somecomputation x y
>
> implies that get_fundef f will output something useful whereas if
>
>> g = \ x y -> process x y
>
> then g is a closure and get_fundef can't evaluate it. Is it correct ?

The manual says that get_fundef takes a symbol, and returns the
definition of the function associated with that symbol in the global
scope. This means that you can't use it for closures, like you say, but
it also means that you can't use it for a local function either, so the
following won't work:

quickcheck f with
<definiton of f here>
end;

You could add to quickcheck a rule that lets the user specify
the type signature of the function they are checking. Something like:

quickcheck (f,[int,int]);

If I understand your code correctly, this would allow you to pass any
arbitrary function into quickcheck. My "check" function does something
like this (though in a bloated way)...

Cheers,

Alastair

ebmtra...@gmail.com

unread,
May 4, 2013, 7:28:21 PM5/4/13
to pure...@googlegroups.com
@ag Thank you for your interest but I have to warn you that this is only an amateur work for the moment, only to prove that working with types is possible! If this proves useful to anyone else, well... I should study the other libraries (like Alastair's) to see how you, dev people,  make use of namespaces to be respectful of the existing pure environment. Any advice on that would be appreciated, by the way.
For the moment, I'm only focusing on the basic functionalities, independantly from any other library (so, please tell me if you see some conflicting symbols, I had to namespace a 'chars' of mine because I didn't know that this name was already in the prelude, for example). My next step may be heading to dynamic distribution, that is to say that the starting tests should use predefine 'minimal' values (0,[],...), the last ones totally random values and, in between, a slow transition from definite to random during the 100 tests. I think this is how Haskell's QuickCheck works.

@ Alastair Thank you for your link. I'm on it and I'll give you feedback as soon as I understand more!





Albert Graef

unread,
May 5, 2013, 4:15:12 AM5/5/13
to pure...@googlegroups.com
On Sun, May 5, 2013 at 1:28 AM, <ebmtra...@gmail.com> wrote:
> @ag Thank you for your interest but I have to warn you that this is only an
> amateur work for the moment, only to prove that working with types is
> possible!

Well, if you're a proficient Haskell programmer then you're not really
an amateur, are you? ;-) And aren't we all "amateurs" in all but a
handful programming languages that we know best?

> I had to namespace a 'chars' of mine because I didn't
> know that this name was already in the prelude, for example).

A quick way to see what's there is to look in the index of the online
manual, or to just ask the interpreter itself:

> show chars
chars s::string = __C::string_chars s if ~funp (:);
chars s::string = list (__C::string_chars s);

You can also use glob style patterns with `show`:

> show -g ch*
type char x::string = intp (ord x);
charp x = typep ('char) x;
chars s::string = __C::string_chars s if ~funp (:);
chars s::string = list (__C::string_chars s);
extern bool pure_check_tag(int, expr*) = check_ptrtag;
chr n::int = c if stringp c when c = __C::string_chr n end;

Tab completion also works great for this. E.g., to see which routines
starting with 'c' are predefined in the default namespace, start
typing `::c` at the interpreter prompt and then hit the Tab key.

ebmtra...@gmail.com

unread,
May 5, 2013, 6:21:01 AM5/5/13
to pure...@googlegroups.com
 Yes, for prelude functions, it is easy to find out a conflict. But, if everyone uses an hypothetical pure-data-maybe library, it will be awkward to name a function 'fromJust' in the quickcheck library, for example. It is hard to know until I know that everyone uses the pure-data-maybe library ;) I'm not aware enough of pure users' habits but I'm learning... Good luck and have fun at LAC!
Reply all
Reply to author
Forward
0 new messages