Re: [Haskell-cafe] Testing Implementation vs Model - Records or Type Classes?

2011-04-09 Thread Heinrich Apfelmus

Twan van Laarhoven wrote:

For reference, here the full signature of the core combinators:

data Event a
data Behavior a

instance Functor Behavior
instance Applicative Behavior
instance Functor Event
instance Monoid (Event a)

filter :: (a - Bool) - Event a - Event a
apply :: Behavior (a - b) - Event a - Event b
accumB :: a - Event (a - a) - Behavior a


The apply and accumB functions are harder. Is the Behavior 
implementation for the model really different from the one of the 
implementation, which seems to be {initial::a, changes::Event a}? If 
not, you could just generalize that type by making the event type a 
parameter


data GenBehavior e a = GB a (E a)

If this is not the case,


I have changed the both implementations completely, so this no longer an 
option.


then instead of MPTCs you could also try type 
families,


class ... = FRP event where
data Behavior event
apply :: Behavior event (a - b) - event a - event b
accumB :: a - event (a - a) - Behavior event a

I don't know whether this is any better than the MPTC approach, though.


Data type families have the advantage that I don't run into problems 
with ambiguity. The following seems sensible to me:


class (Functor (Event f), Functor (Behavior f),
   Applicative (Behavior f)) = FRP f where
apply :: Behavior f (a - b) - Event f a - Event f b
...

where  f  is simply a dummy variable to index different FRP implementations.

The problem with this is that I need the  FlexibleContexts  extension to 
do that. There goes Haskell2010 compatibility.



Best regards,
Heinrich Apfelmus

--
http://apfelmus.nfshost.com


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Testing Implementation vs Model - Records or Type Classes?

2011-04-08 Thread Heinrich Apfelmus

Hello,

I'm writing a small Haskell library for functional reactive programming. 
The core of the library consists of two data types and several 
primitives. However, I have programmed this core *twice*: once as a 
*model* that displays the intended semantics, and once as the actual 
*implementation* to be used in production code.


Of course, I would like to use QuickCheck to test that the 
implementation gives the same results as the model. My problem is: how 
to organize this with the minimum amount of boilerplate?


It appears that I can use *multiparameter type classes* to solve this, 
but I'm not sure I'm happy with this, in particular because it makes the 
generated Haddock less readable (see 3) below). On the other hand, I 
could also use *record wildcards* to conveniently reify a module into a 
record data structure. But that will give me problems with combinators 
that are derived from the core combinators (see 2) below).


Haskell Café, what are your suggestions and ideas?


In particular, I wish to:

1) Write examples to be QuickChecked only once.
I imagine that my main function for testing looks like this

test_equal example =
  forAll $ \input - example model input
  == example implementation input

where  example  an expression involving the combinators from my library. 
The point is that I don't want to write  example  twice, once for each 
version.


2) Use derived combinators.
For reference, here the full signature of the core combinators:

   data Event a
   data Behavior a

   instance Functor Behavior
   instance Applicative Behavior
   instance Functor Event
   instance Monoid  (Event a)

   filter :: (a - Bool) - Event a - Event a
   apply  :: Behavior (a - b) - Event a - Event b
   accumB :: a - Event (a - a) - Behavior a

When writing tests, I also want to use common derived combinators, like, say

   filterJust :: Event (Maybe a) - Event a
   filterJust = fmap fromJust . filter isJust

without implementing them twice.

3) Obtain readable Haddock.
I like the simplicity and readability of an ordinary module signature. 
In contrast, libraries with many type class scare me. Or is there a way 
to make this less scary?


I'm not sure about the last one:
4) Make both model and implementation available to the user,
so that he can QuickCheck his own programs as well. Since the 
implementation makes heavy use of IO, it is a bit harder to test 
automatically, so the model might be useful to have.



Best regards,
Heinrich Apfelmus

--
http://apfelmus.nfshost.com


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Testing Implementation vs Model - Records or Type Classes?

2011-04-08 Thread Twan van Laarhoven

On 08/04/11 11:54, Heinrich Apfelmus wrote:

Hello,

I'm writing a small Haskell library for functional reactive programming.
The core of the library consists of two data types and several
primitives. However, I have programmed this core *twice*: once as a
*model* that displays the intended semantics, and once as the actual
*implementation* to be used in production code.

...
Haskell Café, what are your suggestions and ideas?

...
For reference, here the full signature of the core combinators:

data Event a
data Behavior a

instance Functor Behavior
instance Applicative Behavior
instance Functor Event
instance Monoid (Event a)

filter :: (a - Bool) - Event a - Event a
apply :: Behavior (a - b) - Event a - Event b
accumB :: a - Event (a - a) - Behavior a


You don't need MPTCs to generalize the filter function:

-- this class is useful beyond this FRP library,
--  you might already be able to find it on hackage somewhere
class Functor f = Filterable f where
filter :: (a - Bool) - f a - f a
-- filter p . fmap f == fmap f . filter (p . f)
-- filter (const True) == id
-- filter p . filter q == filter (\x - p x  q x)

The apply and accumB functions are harder. Is the Behavior 
implementation for the model really different from the one of the 
implementation, which seems to be {initial::a, changes::Event a}? If 
not, you could just generalize that type by making the event type a 
parameter


data GenBehavior e a = GB a (E a)

If this is not the case, then instead of MPTCs you could also try type 
families,


class ... = FRP event where
data Behavior event
apply :: Behavior event (a - b) - event a - event b
accumB :: a - event (a - a) - Behavior event a

I don't know whether this is any better than the MPTC approach, though.


Twan

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Testing Implementation vs Model - Records or Type Classes?

2011-04-08 Thread wren ng thornton

On 4/8/11 8:55 AM, Twan van Laarhoven wrote:

-- this class is useful beyond this FRP library,
-- you might already be able to find it on hackage somewhere
class Functor f = Filterable f where
filter :: (a - Bool) - f a - f a
-- filter p . fmap f == fmap f . filter (p . f)
-- filter (const True) == id
-- filter p . filter q == filter (\x - p x  q x)


There are a few other methods that should be added to this typeclass. In 
particular,


filterMap :: (a - Maybe b) - f a - f b

which fuses the first rule and saves the redundant passes and evaluations.

In a similar vein you may want a class for versions that allow 
applicative/monadic functions along with the sequenceA/sequence 
capabilities of Traversable.


--
Live well,
~wren

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe