Monday, November 10, 2014

Two new "validation" applicatives

There exists an Either-like Applicative (usually called "Validation") that either collects all the errors, or returns a success. This is different from the Monad instance of Either, that stops at the first error encountered.

The type can be found at the validation package. However, that package incurs on a heavy lens dependency.

Recently, the type has cropped up without the lens dependency in both transformers (as the Errors type synonym) and either (as Validation).

The version in the either package has a more precise type, as it only requires the error values to form a Semigroup, but not necessarily a Monoid. So you can use a NonEmpty to accumulate errors.

Thursday, October 23, 2014

conceit 0.2.1.0

I have released a new version of the conceit package with the following changes:

The Applicative instance now doesn't require those ugly (Show e, Applicative e) constraints on the error type.

There's a Monad instance for Conceit. I initially made the >> operator concurrent, like *>, but that was a bad idea. In the end, the Monad instance has sequential operations and the Applicative concurrent ones, like it happens in Haxl.

There are also MonadThrow, MonadCatch and MonadError instances. The first two work throwing and catching exceptions from IO, the last one works more like ExceptT.

A special run function was added for when the error is "impossible":  Conceit Void a -> IO a. This makes easier to use Conceit in place of Concurrently.

The internals of this new version of conceit have been copied from those of Concurrently in Simon Marlow's async package, with modifications to support the new behaviour.

Sunday, October 19, 2014

Colchis, yet another JSON-RPC 2.0 client

There's no shortage of JSON-RPC 2.0 libraries on Hackage, as any cursory search will show. I have just added my own, called Colchis.

It is a pipes-based client that makes use of bidirectional pipes. It doesn't have a lot of features, in particular the only supported transport is raw TCP. I think HTTP transport support would be easy to add, but I don't have the need right now. No notifications or batched requests, either.

My aim is to be able to communicate with jsonrpc4j servers in "streaming" mode.

Check the examples folder in the repo for some examples of usage.

Monday, October 6, 2014

conceit 0.1.0.0

I have updloaded to Hackage a tiny package called conceit. It contains a slight variation on the Concurrently type from the async package.

Concurrently is hugely useful. A instance of Applicative, its <*> executes two IO actions concurrently (duh!) and, if one of the threads throws an exception, the other one is killed before re-throwing the exception. Very handy to ensure proper cleanup.

Conceit is similar to Concurrently, but the IO actions return an Either value. If both actions return with Right, the return values are combined. But if one of the actions returns with Left, the other action is immediately terminated and the Left value is returned. One could say that Conceit behaves like race for errors and like Concurrently for successful return values.

A Bifunctor instance is provided to help "massage" the errors.

Thursday, October 2, 2014

process-streaming 0.6.0.0

I have released (a few days ago already) version 0.6.0.0 of process-streaming, my library of pipes-based helpers built on top of the process package.

The API of version 0.3.0.0 proved to be too convoluted, with bloated and obscure function signatures. Hopefully the API for the new version is more intuitive.

The central abstraction if that of a Siphon. A Siphon represents a computation that either drains a Producer completely, or fails early aborting the consumption of the Producer. stdout and stderr can only be consumed through Siphons. Siphons can be created out of regular Consumers, pipes folds, or Parsers from pipes-parse.

Why do we need Siphons? When consuming both stdin and stderr of an external process, it is important that the two are drained to completion, because otherwise the process may block due to an output buffer that is not being read and fills up.

Siphons have an Applicative instance that "forks" a producer and feeds it to two computations. This Applicative instance made the support for branching pipelines of processes easy to implement.

The test suite contains several examples of usage.

Monday, June 30, 2014

The lazy Writer monad

I found an interesting example of the lazy State monad that uses "head recursion".

I tried to adapt the example for the lazy Writer monad but it proved difficult. If you naively consume the head of the infinite accumulator, it will hang, even with the lazy version of the monad:

The trick is to use Dual from Data.Monoid:

Maybe I suffer from a failure of imagination, but I can't think of any practical problem in which the lazy Writer monad offers an advantage over the strict version.

Monday, June 9, 2014

process-streaming 0.3.0.0

I have released version 0.3.0.0 of process-streaming, my library of pipes-based helpers built on top of the process package.

It contains breaking changes. Some functions have new names, and a few newtypes have been introduced in order to hide unnecessarily complex signatures. Hopefully the changes make the library a bit more intuitive.

You might find this library useful if:

  • You want an easy way to consume the standard streams of an external process using the tools provided by the pipes ecosystem.
  • You want concurrent, streaming access to both the stdout and stderr of an external process, without fear of deadlocks caused by full output buffers.
  • You want to consume stdout and stderr combined in a single stream.
  • You want to be relieved of tedious bookkeeping like: automatically killing the external process on the face of errors and exceptions, ensuring the termination of threads spawned for concurrent reads, and so on.