Re: [Haskell-cafe] Lifting IO actions into Applicatives

2013-10-01 Thread Oliver Charles
On 10/01/2013 07:58 AM, Michael Snoyman wrote:
 I'm wondering if anyone's run into this problem before, and if there's a
 common solution.
 
 In Yesod, we have applicative forms (based originally on formlets).
 These forms are instances of Applicative, but not of Monad. Let's
 consider a situation where we want to get some user input to fill out a
 blog post datatype, which includes the current time:
 
 data Blog = Blog Title UTCTime Contents
 
 myBlogForm :: Form Blog
 myBlogForm = Blog $ titleForm * something * contentsForm
 
 The question is: what goes in something? Its type has to be:
 
 something :: Form UTCTime
 
 Ideally, I'd call getCurrentTime. The question is: how do I lift that
 into a Form? Since Form is only an Applicative, not a Monad, I can't
 create a MonadIO instance. However, Form is in fact built on top of
 IO[1]. And it's possible to create a MonadTrans instance for Form, since
 it's entirely possible to lift actions from the underlying functor/monad
 into Form. So something can be written as:
 
 something = lift $ liftIO getCurrentTime

Is it really necessary to have a type class to do this? You can always
just introduce 'io :: IO a - Form a' to lift IO actions into a form.
Then you just have:

myBlogForm = Blog $ titleForm * io getCurrentTime * contentsForm

In digestive-functors, we have the base monad in the type of the form
itself, so we provide 'monadic' which goes from
m (Form m a) - Form m a (hand-waving as there are actually other type
constraints). You might get more power by following in those steps, and
having the aforementioned 'io' function actually be:

io :: IO (Form a) - Form a

- ocharles




signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Poll plea: State of GUI graphics libraries in Haskell

2013-09-27 Thread Oliver Charles
On 09/27/2013 04:32 AM, Conal Elliott wrote:
 I'm polling to see whether there are will and expertise to reboot
 graphics and GUIs work in Haskell. I miss working on functional graphics
 and GUIs in Haskell, as I've been blocked for several years (eight?) due
 to the absence of low-level foundation libraries having the following
 properties:
 
 * cross-platform,
 * easily buildable,
 * GHCi-friendly, and
 * OpenGL-compatible.
 
 The last several times I tried Gtk2hs, I was unable to compile it on my
 Mac. Years ago when I was able to compile, the GUIs looked and
 interacted like a Linux app, which made them awkward and upleasant to
 use. wxHaskell (whose API and visual appearance I prefered) has for
 years been incompatible with GHCi, in that the second time I open a
 top-level window, the host process (GHCi) dies abruptly. Since my GUI 
 graphics programs are often one-liners, and I tend to experiment a lot,
 using a full compilation greatly thwarts my flow. For many years, I've
 thought that the situation would eventually improve, since I'm far from
 the only person who wants GUIs or graphics from Haskell.

We are working on bindings to SDL 2 at the moment -
https://github.com/Lemmih/hsSDL2. They are currently usable for most
'stock' work - drawing things, doing interaction, window management,
etc. However, I'm afraid SDL bindings don't really solve what you want
in terms of a GUI programming.

SDL2 at least gives you a sane cross platform way to create a window
with an OpenGL context, and to draw things using hardware acceleration.
If you actually need widgets, then SDL probably won't help here.

- ocharles



signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Readable GHC 7.6.3 docs (Bootstrapped)

2013-09-11 Thread Oliver Charles
On 09/11/2013 03:45 PM, Twan van Laarhoven wrote:
 Why does every section have a title=1.2.3 foo on the outer div? In
 Firefox this shows up as a useless tooltip when moving the mouse over
 the text.

That's the same with the official document. I think it's a feature of
whatever tool is used to generate this documentation. The NixOS
documentation has the same annoying behavior -
http://nixos.org/nix/manual/#idp125008

- ocharles



signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Lenses: Should I declare Getters?

2013-09-10 Thread Oliver Charles
On 09/10/2013 06:31 AM, Charlie Paul wrote:
 I've been looking through Edward Kmett's lens library, and I'm a bit
 befuddled about Getters. In my own code, why would I want to have
 something be a Getter instead of a plain function? As far as I can see,
 a plain function is simpler to use, and can be converted to a Getter
 with to if we want to use it as a Fold. Is there a situation where
 writing a Getter is superior than writing a function, then lifting it as
 needed?

Generally, you don't provide 'Getter's because people can always lift a
function with to - as you said. This is mentioned in the lens FAQ at:

https://github.com/ekmett/lens/wiki/FAQ#wiki-using-getters

- ocharles




signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Identity of indiscernibles

2013-08-08 Thread Oliver Charles
On 08/08/2013 05:05 PM, Tom Ellis wrote:
 On Thu, Aug 08, 2013 at 03:38:41PM +0200, Jerzy Karczmarczuk wrote:
 One could simply implement IO as a free monad
 Interesting. I wonder how.
 
 See [1] for an explanation of free monads in general

You're lacking a matching definition of [1] :)




signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Wrapping all fields of a data type in e.g. Maybe

2013-07-16 Thread Oliver Charles
On 07/16/2013 09:57 PM, Michael Orlitzky wrote:
 I have a common pattern in my command-line programs; I start out with a
 configuration data type, which over-simplified looks like:
 
   data Cfg = Cfg { verbose :: Bool }
 
 Now, there's usually a default configuration,
 
   default :: Cfg
   default = Cfg False
 
 The user can override the defaults one of two ways, either via a config
 file, or from the command-line. If both are specified, the command-line
 takes precedence. The way I do this is with,
 
   data OptionalCfg = OptionalCfg { verbose :: Maybe Bool }
 
 And then I define I Monoid instance for OptionalCfg which lets me merge
 two ofthem. Once the two OptionalCfgs are merged, I merge *that* with
 the default Cfg.
 
 This all works great, except that when there's 20 or so options, I
 duplicate a ton of code in the definition of OptionalCfg. Is there some
 pre-existing solution that will let me take a Cfg and create a new type
 with Cfg's fields wrapped in Maybe?

One option is to combine OptionalCfg with Cfg, by parameterizing Cfg. If
you make

  data Cfg a = Cfg { cfgVerbose :: a Bool }

Then you can choose between Cfg Identity and Cfg Maybe. Furthermore,
these are different types, so you can still have a monoid over Cfg Maybe.

There might be some lens magic that makes working with this easier too.
For example,

  verbose :: Lens' (Cfg a) Bool
  verbose = cfgVerbose.traverse

Or something to that effect (that actually compiles).

- ollie



signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Netwire bouncing ball

2013-07-11 Thread Oliver Charles
On 07/11/2013 05:52 PM, Just wrote:
 On 07/10/2013 11:44 PM, Ertugrul Söylemez wrote:
 A very simple way to do this is to use integralLim_ instead of
 integral_.  It allows the ball itself to handle the bouncing.  A less
 invasive way (i.e. you can add it to your example) is to use the (--)
 combinator:

  ball = integral_ 0 . integral_ 40 . (-9.8)

  aboveGround = require (= 0)

  bouncingBall = aboveGround . ball -- bouncingBall

 While this gives you a bouncing ball, the ball will not follow real
 physics.  Once the ball hits the ground, it will just start over with
 its original velocity.  integralLim_ is the correct solution.
 
 Thank you very much, this works as expected and is easy to understand.
 However a complete example of a bouncing ball would be super awesome
 since I have trouble to get it work with integralLim_.
 
 My first try was to use object_ from Control.Wire.Prefab.Move but got
 stuck very quickly.
 
 I think this would be a good addition to the quickstart tutorial.

It would indeed be a fantastic addition - this is almost exactly what I
was trying to do as my example netwire project. For a bit more support,
I was trying to move a point from x=0 to x=10, and then back to x=0 -
and so on. I got as far as getting to x=10, but then had no idea how to
reverse the direction and make the whole thing cycle. I was told to read
about ArrowLoop, but sadly I never got much further.

- ollie



signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] ANNOUNCE: module-management-0.9.3 - clean import lists, split and merge modules

2013-07-01 Thread Oliver Charles
On 07/01/2013 08:38 PM, David Fox wrote:
 Should I keep posting updates in this thread?

Yes please, I'm interested in following this development! That, or get
yourself a blog and let us all know where to point our RSS readers.

- Ollie




signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] [haskell.org Google Summer of Code] The Summer of Code is officially under way.

2013-06-18 Thread Oliver Charles
On 18 Jun 2013 15:34, Edward Kmett ekm...@gmail.com wrote:
 I'm looking forward to seeing what we can accomplish together this year!

+1 - best of luck, students !

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


Re: [Haskell-cafe] ANN: Angel 0.4.2

2013-06-13 Thread Oliver Charles
On 13 Jun 2013 06:51, Michael Xavier mich...@michaelxavier.net wrote:

 I'm pleased to announce the release of Angel 0.4.2 and that I have
officially taken over maintainership of this project. Thanks to Jamie
Turner for starting such a great project and allowing me to take over this
project.

Hi Michael, great to hear Angel is still active! Its a great project, so I
wish you good luck as the new maintainer. Thanks for your work!

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


Re: [Haskell-cafe] What symbol / atom/ interned-string package is currently preferred?

2013-05-09 Thread Oliver Charles

On 05/09/2013 12:56 PM, Johannes Waldmann wrote:

http://hackage.haskell.org/package/intern

what does this package do? OK, I can read efficient hash consing
but what does it mean exactly? and how would I actually use it?
I can't tell you what it does, but there is an example - 
https://github.com/ekmett/intern/blob/master/examples/Term.hs


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


Re: [Haskell-cafe] ANN: rematch, an library for composable assertions with human readable failure messages

2013-04-16 Thread Oliver Charles

On 04/16/2013 11:24 AM, Tom Ellis wrote:

On Tue, Apr 16, 2013 at 10:17:48AM +0100, Tom Crayford wrote:

I kept on running into this thing where I was calling error in quickcheck
to get good error messages about the things I was comparing. In Java land,
this stuff is handled by Hamcrest: a library for composable assertions with
good error messages. This library is basically a port of hamcrest's core
api, but I've been very pleased with how it turned out.

[...]

Let me know if you have any feedback/thoughts

I've been feeling the need for something like this for some time.  I'll
check it out.  Thanks!

Tom
This is beyond sorely needed. I can't wait to plug this into some of my 
own projects!


Thanks!
- Ollie

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


Re: [Haskell-cafe] Monad fold

2013-04-16 Thread Oliver Charles

On 04/16/2013 01:47 PM, Lyndon Maydwell wrote:

You could do:

runKleisli . mconcat . map Kleisli :: Monoid (Kleisli m a b) = [a - 
m b] - a - m b


Would that work for you?
I can't find an instance for Monoid (Kleisli m a b) in `base`, so 
presumably the author would also have to write this instance? If so - 
would that really be any different to using that fold?


- Ollie

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


Re: [Haskell-cafe] Vector Fabrics is hiring!

2013-04-08 Thread Oliver Charles

On 04/08/2013 06:30 AM, Stefan Holdermans wrote:


* Your friends and colleagues describe you as a rockstar programmer;
   your programming ability is way above average;

Good luck hiring smart people.

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


Re: [Haskell-cafe] Fwd: Now Accepting Applications for Mentoring Organizations for GSoC 2013

2013-03-19 Thread Oliver Charles

On 03/18/2013 08:49 PM, Johan Tibell wrote:

[bcc: hask...@haskell.org mailto:hask...@haskell.org]

We should make sure that we apply for Google Summer of Code this year 
as well. It's been very successful in the previous year, where we have 
gotten several projects funded every year.
Definitely - plus it means I get to meet other Haskell'ers at the mentor 
summit ;)


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


Re: [Haskell-cafe] ANN: lazy-csv - the fastest and most space-efficient parser for CSV

2013-02-25 Thread Oliver Charles

On 02/25/2013 10:47 AM, Malcolm Wallace wrote:

There are lots of Haskell CSV parsers out there.  Most have poor 
error-reporting, and do not scale to large inputs.  I am pleased to announce an 
industrial-strength library that is robust, fast, space-efficient, lazy, and 
scales to gigantic inputs with no loss of performance.

 http://code.haskell.org/lazy-csv/

Downloads from Hackage:

 http://hackage.haskell.org/package/lazy-csv

This library has been in industrial use for several years now, but this is the 
first public release.  No doubt the API is not as general as it could be, but 
it already serves many purposes very well.  I'm happy to receive bug reports 
and suggestions for improvements.

Regards,
 Malcolm


Obvious question: How does this compare to cassava? Especially cassava's 
Data.CSV.Incremental module? I specifically ask because you mention that 
it's  It is lazier, faster, more space-efficient, and more flexible in 
its treatment of errors, than any other extant Haskell CSV library on 
Hackage but there is no mention of cassava in the website.


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


Re: [Haskell-cafe] JSON querying

2013-02-17 Thread Oliver Charles

On 02/17/2013 03:01 PM, Sergey Mironov wrote:

Hi folks. Hackage contains several JSON packages but as far as I see,
they all provide 'static' conversion from JSON format to Haskell data
type. Is there a method of converting object containing optional filed
'a' to for example Maybe a.
Assuming you have some sort of 'path' to the key in question, aeson-lens 
might be exactly what you want: 
http://hackage.haskell.org/package/aeson-lens


I use aeson-lens to turn a list of strings of the form [foo, bar, 
baz] into a query into first the 'foo' object, then the 'bar' object, 
then the 'baz' object, using the following:


pathToLens :: Functor f
   = [T.Text]
   - (Maybe Value - f (Maybe Value))
   - Maybe Value
   - f (Maybe Value)
pathToLens [p] = key p
pathToLens ps = let ps' = filter (not . T.null) ps
in key (head ps') . (foldl (.) id . map pathElem $ tail 
ps')

  where
pathElem p = maybe (key p) nth (readMay $ T.unpack p)

So as you can see - I turn any arbitrary path into a query into JSON, 
with a chance of failure.


Hope this helps!
- Ollie

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


[Haskell-cafe] Optimizing performance problems with Aeson rendering large Text arrays

2013-02-01 Thread Oliver Charles

Hello,

In summary, i'm working on an application that responds to a users query, a
sequence index, with the union of a list of UUIDs that have changed 
since that
same sequence index, split into 6 sections. I wish to respond to these 
queries
via JSON to provide an easy to use web service, and for the most part, 
what I

have works.

The problem I am having is that profiling seems to show that the 
majority of the

time spent in my application is encoding this to JSON, and also that the
application is only 60% productive with 40% allocations happening in
Data.Aeson.encode (and friends).

Here's an overview of what I'm doing, the full code can be found at the 
end of

this email.

I am storing my data in memory as an IntMap, from sequence index to a 
changeset:



IntMap ChangeSet


Where a ChangeSet is essentially a tuple of HashSet's of UUIDs:


data ChangeSet = ChangeSet { artistChanges :: !(HashSet MBID)
   , labelChanges :: !(HashSet MBID)
   , recordingChanges :: !(HashSet MBID)
   , releaseChanges :: !(HashSet MBID)
   , releaseGroupChanges :: !(HashSet MBID)
   , workChanges :: !(HashSet MBID)
   }
  deriving (Generic)


The MBID newtype is just a newtype around Text, but you can only create 
MBIDs by
parsing a UUID fromString - just to enforce a bit more correctness, but 
without

the cost of having to serialize the UUID to JSON.

When I query, I splitLookup on the IntMap to get the requested change set by
sequence index, and all future changesets. I union all of these, and 
then render

the response back to the client:


let (_, !cs, !futureCs) = IntMap.splitLookup csId changeSets
writeLBS $ encode $ mconcat $
  catMaybes $ map Just (IntMap.elems futureCs) ++ [ cs ]


None of this shows up in profiling however, and here's what I see:


Thu Jan 31 17:03 2013 Time and Allocation Profiling Report  (Final)

   Main +RTS -p -RTS

total time  =4.75 secs   (4748 ticks @ 1000 us, 1 processor)
total alloc = 4,329,582,160 bytes  (excludes profiling overheads)

COST CENTRE MODULE %time %alloc

encode  Data.Aeson.Encode   23.5 17.4
string  Data.Aeson.Encode   18.5 35.1
break   Data.Aeson.Encode   17.5 2.3
mconcat Main15.1 9.7
fromValue/Array Data.Aeson.Encode9.2 14.8
toJSON  Main 5.7 9.0
send.loop   Snap.Internal.Http.Server.HttpPort   3.0 0.0
mapIter Snap.Iteratee2.1 2.3
parseJSON   Main 1.7 3.0
writeLBSSnap.Internal.Types  1.1 4.9

COST CENTRE MODULEno. entries  %time 
%alloc   %time %alloc


MAINMAIN 21600.00.0   100.0  100.0
 main   Main 43300.00.0   100.0  100.0
  main.sinceMain 106310.00.075.3   78.7
   encode   Data.Aeson.Encode 13910   23.5   
17.475.3   78.7
fromValue/ObjectData.Aeson.Encode1395 2540.0
0.046.0   52.2
 fromValue/ArrayData.Aeson.Encode1420 7577.9   
12.036.4   25.7
  fromValue/String  Data.Aeson.Encode1422 30890950.7
0.028.5   13.7
   string   Data.Aeson.Encode1423 3089095   10.2   
11.427.8   13.7
break   Data.Aeson.Encode1425 3089095   17.5
2.317.52.3
 string Data.Aeson.Encode1396 8848.3   
23.7 9.6   26.6
  fromValue/Array   Data.Aeson.Encode 142101.3
2.9 1.32.9
   fromValue/String Data.Aeson.Encode 142400.0
0.0 0.00.0
  break Data.Aeson.Encode1397 8840.0
0.0 0.00.0
toJSON  Main 1393 1275.7
9.0 5.79.0



Unless I'm reading this incorrectly, this shows that 75% of the time is 
spent in

encode, along with almost 80% of my allocations. While the performance of my
application is actually satisfactory (I respond in around 0.04s), I'd 
still like
to do better - if only for the practical experience of learning how to 
optimize.


Any ideas what I can do about this? I feel like I might get better 
performance
if fromValue/Array new that I had a vector of Text values, and they 
could just
be intercalated with ,  - but I have no idea how the internals of Text 
works

so this might really perform the same as the fold that is currently used.

I am compiling for benchmarking purposes with:


ghc -Wall -fno-warn-orphans -Werror -O2 -rtsopts \
  -hide-package hashable-1.2.0.5 Main.hs


And I 

Re: [Haskell-cafe] Optimizing performance problems with Aeson rendering large Text arrays

2013-02-01 Thread Oliver Charles
Urgh, the formatting got totally destroyed in sending, I think. If so, 
here's a paste of my email as I intended it to be sent:


http://hpaste.org/81648

Sorry about that!
- Ocharles

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


Re: [Haskell-cafe] Optimizing performance problems with Aeson rendering large Text arrays

2013-02-01 Thread Oliver Charles

On 02/01/2013 01:44 PM, Bas van Dijk wrote:


If I make a special case for text based UUIDs in aeson:

data Value = ... | UUID Text | ...

Data.Aeson.Encode.fromValue (UUID s) = singleton ''  fromText s  
singleton ''


Then encoding time improves by 20%.

So a big part of the time is spent encoding the UUID strings.

Bas

This might work, but it doesn't seem to be something I could actually 
distribute, unless I shipped modified Aeson source code... the String 
fromValue pattern seems to do a lot of escaping which won't apply to my 
UUIDs, but I'm not sure what the right solution to that is.


- Ocharles

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


[Haskell-cafe] Looking for advice on modelling a 3-way merge (with varying strategies)

2012-10-31 Thread Oliver Charles
Hello,

I'm currently trying to implement a way 3 way merge, that is dispatched
on type. Essentially, I want to be able to say I have this large data
type which is a product of various other types - here's how to merge
it.

By 3 way merge, I mean that I have a 'new' value, a 'current' value and
a 'common ancestor' value. So far I have:

  import Control.Applicative
  import Data.Monoid

  newtype Merge a = Merge { runMerge :: Either [String] a }

  instance Functor Merge where
fmap f a = Merge $ fmap f $ runMerge a

  instance Applicative Merge where
pure = Merge . Right
(Merge (Right f)) * (Merge (Right a)) = Merge $ Right $ f a
(Merge (Right _)) * (Merge (Left c))  = Merge $ Left $ c
(Merge (Left c)) * (Merge (Left c'))  = Merge $ Left $ c  c'
(Merge (Left c)) * _  = Merge $ Left $ c

  ok :: a - Merge a
  ok = pure

  failMerge :: String - Merge a
  failMerge x = Merge $ Left [x]


So far so good, so I can add my first merge strategy:

  mergeEq :: Eq a = String - a - a - a - Merge a
  mergeEq lbl new current ancestor | current == new  = ok new
   | current == ancestor = ok new
   | new == ancestor = ok current
   | otherwise   = failMerge lbl


And we can make use of this to build more complicated merge strategies:

  data Person = Person { name :: String, surname :: String }
deriving (Show)

  mergeEqOn :: Eq a = (b - a) - String - b - b - b - Merge a
  mergeEqOn l lbl n c a = mergeEq lbl (l n) (l c) (l a)

  mergePerson :: Person - Person - Person - Merge Person
  mergePerson new current ancestor =
Person $ mergeEqOn name name new current ancestor
   * mergeEqOn surname surname new current ancestor


   runMerge $ mergePerson Person { name=Steve, surname=Bobman }
 Person { name=Joe,   surname=Obman }
 Person { name=oe,surname=Obman }
  Left [name]

   runMerge $ mergePerson Person { name=Steve, surname=Bobman }
 Person { name=Joe, surname=Obman }
 Person { name=Joe, surname=Obman }
  Right (Person {name = Steve, surname = Bobman})


Everything does exactly what I want, but it doesn't smell as good as I
expect from Haskell. Firstly, all my primitives or operations take 3
arguments that have to be threaded in a very specific pattern. If I
accidently call mergeEq ancestor current new, I've ran things in the
wrong order and I'm Gonna Have a Bad Time. So that's no good.

Secondly, is there a better way of labelled parts of a merge? I suspect
not, as at some point I need a human readable display, but I did wonder
about using a lens as a label, and then mapping lenses to human readable
names later -- but that will require a bit of newtyping in order to
provide the Eq instance, or maybe i make a HumanLens type which is a
lens and a name?).

Finally, I'm currently a little obsessed with the idea of building
applicatives from the composition or product of other applicatives - can
I use this trick here? I initially used 'Compose ((,) [String]) Maybe a'
but this means it's possible to have
([Conflicts], Just But success!), which is nonsense.

I'd love to hear your thoughts!

- ocharles

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


[Haskell-cafe] Is it possible to create an instance of MonadBaseControl for PropertyM (QuickCheck)/continuations?

2012-01-14 Thread Oliver Charles
Hi

I'm working on a little experiment at the moment: using monadic
QuickCheck to test the integration of my code and the database. I see
some of my functions having properties like - given a database in this
state, selectAll should return all rows, and so on. My initial attempt
has worked nicely, and now I'm trying to test some more complicated
properties, but I'm hitting a problem with overlapping primary keys, and
this is because I'm not correctly cleaning up after each check.

The simplest solution to this is to bracket property itself, and for
that I turned to Control.Monad.Trans.Control in lifted-base, but I am
struggling to actually write an instance for
MonadBaseContol IO (PropertyM IO). It seems that PropertyM is a
continuation monad transformer:

newtype PropertyM m a =
  MkPropertyM { unPropertyM :: (a - Gen (m Property)) - Gen (m Property) }

Given this, is it possible to even write an instance of
MonadBaseControl? From the lifted-base documentation, it explicitly
calls out ConT as *not* having instances, so I wonder if it can't be
done. Sadly, I also lack intuition as to what MonadBaseControl really
means - I think it means 'capture the state of this monad, so later we
can go back to exactly the same state (or sequence of actions?)', but
this is very flakey.

So... is this possible, and if so how can I move forward?

Thanks for any help or advice!
- Ollie

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


Re: [Haskell-cafe] Idiomatic Aeson

2011-12-19 Thread Oliver Charles
Hi, I'm not sure it directly helps, but I had a bit of trouble getting
off the ground with Aeson too. Here's some of my code using Aeson, maybe
there will be something in here that helps you?

https://github.com/ocharles/BookBrainz/blob/master/src/BookBrainz/Search.hs

- Ollie


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


Re: [Haskell-cafe] indentation blues

2011-12-14 Thread Oliver Charles
Paul Koerbitz paul.koerb...@gmail.com writes:

 Hello,
 TL;DR: If you have some time try emacs, the viper / vimpulse plugins are
 pretty good and the editor is awesome in general. Haskell indentation is
 good.

Not to go too off topic, but I'm not sure people are aware there's
another Vim emulation system called Evil:

http://gitorious.org/evil/pages/Home

Started March this year apparently, and should be the successor to
vimpulse.

- Ollie


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


[Haskell-cafe] Using QuickCheck to test against a database

2011-12-01 Thread Oliver Charles
Hi!

I've just spent my evening trying to use QuickCheck properties to test
the database accessing functions in a project I'm working on at the
moment. I've got some stuff that's working, and I wanted to see what the
cafe thought about it, and if anyone had any suggestions or critiscm
that can help me make it even better!

I got here by trying to figure out how I want to test my application. At
first I saw 2 options: use a test database and assume it exists, or have
each test setup the data it needs. I like the latter more, because it
minimises dependence on the outside world. So I got down to writing some
HUnit tests and then had a wave of inspiration... what if I didn't even
define the data, but let QuickCheck do that for me?

Here's what I came up with - note the code here is somewhat paraphrased
for brevity:

  data DBState a = DBState { initDb :: IO ()
   , entity :: a
   }

This type stores an action that initialises the database with enough
data such that it contains whatever 'entity' is. For example,
'DBState Person' knows how to insert a specific person into the
database, and carries along an in-memory log.

Continuing with the Person idea, I then went and made an Arbitrary
instance for DBState Person:

  instance Arbitrary (DBState Person) where
arbitrary = do
  l - Person $ arbitrary `suchThat` (not . null)
  return $ DBState (void $ insertPerson l) p
  where insertPerson p =
  doSql INSERT INTO person (name) VALUES (?)
[ personName p l ]

Then it's just a case of defining some properties:

  prop_allPersons = monadicIO $ do
dbState - pick arbitrary :: Gen [Person]
fetched - run $ initDb `mapM` dbState  findAllPersons
assert $ fetched `eqSet` (entity `map` dbState)
where eqSet a b = all (`elem` a) b  all (`elem` b) a

Voila! For any database, 'findAllPersons' returns all
persons. Now... onto my own critiscisms with this.

Firstly, way too much boiler plate. You have to remember to apply all of
the states of your arbitrary instances, which is a pain, and guaranteed
to be missed. At first I thought DBState looks like it's basically a
writer/IO monad, but then I couldn't actually figure out the monoid to
write to. In this case it's just [Person], but in more complex property
we might need 2 types of entities (for example, to ensure a join worked
correctly) which makes this list heterogenous.

Secondly, the initDb action is sensitive to the order actions are
sequenced. Presumably, I want to test against a database that's as
accurate to production as possible, which means I want foreign keys
enabled. If things are initialized in the wrong order, it violates the
foreign key constraint, and it's a burden if people have to determine
the correct order. One solution here is to make use of deferrable
constraints, but support for these is flakey at best (and it doesn't
work for bracketting tests with BEGIN; ROLLBACK).

These problems just make the properties harder, but they don't seem to
impede the quality or usefulness of the tests. I really want to make
this work, because the idea of it is quite beautiful to me. Though that
might be partly because this is my first time really using QuickCheck,
so I'm getting the oh wow this is swt effect at the same time ;)

Would love to hear peoples thoughts!
- Ollie

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


[Haskell-cafe] Please review my Xapian foreign function interface

2011-02-18 Thread Oliver Charles
Hello!

I've finally came up with some motivation for a project to get my feet
wet using Haskell, and for this little pet project I need an interface
to Xapian. After reading various documents on FFI in general, I've got a
brief working implementation, and I'm now looking for how to better
structure the public API. First, a quick bit of background if you're not
familiar with Xapian.

Xapian is a search engine, and provides a C++ API. You store documents
in a database (handled by Xapian), and index documents by adding terms
to them. Xapian provides stemming algorithms to help generate these
terms from other data. Xapian also has an interface to queries (through
a Xapian::Enquire object), and also a query parser to allow for natural
language queries to be parsed and ran. For more information, you can
check out the API at [1] - it's fairly small.

As Xapian is C++, it seems my best option is to create my own simple C
wrapper, which also lets me tailor my FFI to be easy to use from
Haskell. You can see my C api on Github [2] - for now it's very stripped
down; I've been wrapping stuff on a need-to-use basis.

* * *

Currently what I have is functional (in the sense that it works), but
it's extremely tied to I/O and very little of the code is pure. For
example, to create and index a document, you need to do something along
the lines of:

do document - newDocument
   setDocumentData document Document data
   addPosting document search_term 1
   addDocument database document

(Assuming you already have an open database handle). How horrible
imperative this all looks! :-) A document *feels* like it should be
quite pure, however retrieving properties of a document performs
I/O. For example, I'd like to have something like:

data Document = Document { data :: String, postings :: [String] }
do document - getDocument database 123 -- Get doc #123

and have `document` refer to a pure Document object. I'm still stuck in
the IO monad a bit, but at least I can write pure functions to operate
on `Document` values now. The problem I see with this, is that I believe
I'd have to retrieve all parts of document in my `getDocument` function
(include the data and all postings), and I can't benefit from being lazy
here.

From what I gather, all the methods on Xapian documents are lazy (such
as getting the document data, and getting terms associated with
documents), which would mean that my foreign imports would have to be
`IO String`, for example. This tends to fairly quick cause the IO monad
to propogate everywhere.

* * *

I think that's enough information to explain my current progress, and my
concerns. It could well be that I'm overly worrying about everything
being in the IO monad, but as I said - Haskell is new to me.

All of my work is at [3], and I'd love any advice you have. Haddock
documents have been exported to ocharles.org.uk [4].

Thanks for your time,

Oliver Charles / ocharles

--

[1]: http://xapian.org/docs/apidoc/html/annotated.html
[2]: https://github.com/ocharles/Xapian-Haskell/blob/master/c/cxapian.h
[3]: https://github.com/ocharles/Xapian-Haskell
[4]: http://ocharles.org.uk/tmp/search-xapian/Search-Xapian.html

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