News aggregator

Checking all interleavings of concurrent program - my first semi-serious Haskell project

Haskell on Reddit - Thu, 07/10/2014 - 1:30am

Link first: concurrency-simulator

Long-time lurker here. I've put together knowledge from several blog posts (especially from here, here and here) and made my first semi-serious Haskell project: concurrency simulator. You can define concurrent program using special monad and then you can run it in several ways: normally in IO, in IO with some additional logging, using predefined interleaving and then inspecting all possible interleavings. All interleavings mode is especially interesting, because it allows to exhaustively test program for bugs.

Generic comments and criticism are welcome, but I have also some specific questions, if you don't mind.

1) allRuns function uses list monad as base of monad transformer stack (I've abstracted away which exactly stack with ListAtBottom class). This is convenient, but also very slow. It allows easy enumeration of all possible interleavings, but doesn't allow any navigation in the tree of possible outcomes in search for goal (i. e deadlock). Better way would be inspecting tree of possible outcomes (at least one level ahead, using singleStep function, but possibly more), to prioritize search, but I honestly don't know how to do it, at least not without losing generality of allRuns type.

2) Another nice thing would be paralelizing allRuns function. There is some really stupid attempt to do it at the bottom of the file. Does anybody know about parallel implementations of list monad? Or should I give up list monad and use explicit sequence manipulation?

submitted by zarazek
[link] [2 comments]
Categories: Incoming News

Yesod Web Framework: RFC: New Data.Conduit.Process

Planet Haskell - Thu, 07/10/2014 - 1:15am

I've been working on a new iteration of the Data.Conduit.Process API over the past few days. The current API (provided by the process-conduit package), has some issues. So I'm starting over with a new API, and will be including this in conduit-extra's next release.

Before releasing, I'd like to get some feedback on the new API. I've put together a School of Haskell tutorial, which will ultimately become the real documentation for this module. It describes usage of the library, as well as why the library looks the way it does. You can view the source on the process branch of conduit.

In case anyone's wondering, the "well known bug" in waitForProcess may actually not be very well known yet. There's a race condition documented in the source code, but it's not nearly as narrow a window as implied there. For example, the following code will reliably throw an exception:

import System.Process import Control.Concurrent.Async main :: IO () main = do (_, _, _, ph) <- createProcess $ shell "sleep 1" let helper i = do ec <- waitForProcess ph print (i :: Int, ec) ((), ()) <- concurrently (helper 1) (helper 2) return ()

Thus the motivation for fixing the problem in Data.Conduit.Process. Thanks go to Michael Sloan for discovering the severity of this race condition. In fact, the bug he ran into, combined with a separate process-conduit bug I ran up against, were the impetus for me getting this library written now.

For the lazy, here's a copy of the content from School of Haskell:

NOTE: This tutorial documents a not-yet-released version of conduit-extra's Data.Conduit.Process module. Currently, that module name is provided by process-conduit, which provides a completely different API. This tutorial is present now for early feedback. If you'd like to experiment, this code is available on the process branch of the conduit repo.

Introduction

Whenever you run an external process, there are four ways to interact with it post-creation:

  • Write to its standard input
  • Read from its standard output
  • Read from its standard error
  • Check its exit code

The standard System.Process module provides means for all of these interactions. However, there are some downsides with using them:

  • Many of the function in System.Process rely on lazy I/O.
  • There is a subtle race condition when checking for exit codes.
  • Dealing with Handles directly is relatively low-level.

Data.Conduit.Process provides a higher-level interface for these four interactions, based on conduit. It additionally leverages type classes to provide more static type safety than dealing directly with System.Process, as will be described below. The library is also designed to work with the wonderful async library, providing for easy, high-quality concurrency.

Note that providing general parameters for creating a process, such as its working directory or modified environment variables, are not addressed by this module; you should instead use the standard facilities from System.Process.

Synopsis{-# LANGUAGE OverloadedStrings #-} import Control.Applicative ((*>)) import Control.Concurrent.Async (Concurrently (..)) import Control.Concurrent.Async (Concurrently (..)) import Data.Conduit (await, yield, ($$), (=$)) import qualified Data.Conduit.Binary as CB import qualified Data.Conduit.List as CL import Data.Conduit.Process (ClosedStream (..), conduitProcess, proc, waitForConduitProcess) import System.IO (stdin) main :: IO () main = do putStrLn "Enter lines of data. I'll base64-encode it." putStrLn "Enter \"quit\" to exit." ((toProcess, close), fromProcess, ClosedStream, cph) <- conduitProcess (proc "base64" []) let input = CB.sourceHandle stdin $$ CB.lines =$ inputLoop =$ toProcess inputLoop = do mbs <- await case mbs of Nothing -> close Just "quit" -> close Just bs -> do yield bs inputLoop output = fromProcess $$ CL.mapM_ (\bs -> putStrLn $ "from process: " ++ show bs) ec <- runConcurrently $ Concurrently input *> Concurrently output *> Concurrently (waitForConduitProcess cph) putStrLn $ "Process exit code: " ++ show ecExit codes

There's a well documented corner case in waitForProcess whereby multiple calls can end up in a race condition, and therefore a deadlock. Data.Conduit.Process works around this issue by not providing direct access to a ProcessHandle. Instead, it wraps this with a ConduitProcessHandle, which uses an STM TMVar under the surface. This allows you to either poll to check if a process has exited, or block and wait for the process to exit. As a minimal example (ignore the streaming bits for now, they'll be explained shortly).

import Data.Conduit.Process main :: IO () main = do (Inherited, Inherited, Inherited, cph) <- conduitProcess (shell "sleep 2") -- non-blocking getConduitProcessExitCode cph >>= print -- blocking waitForConduitProcess cph >>= print

If you need direct access to the ProcessHandle (e.g., to terminate a process), you can use conduitProcessHandleRaw.

Streaming

Now to the main event: streaming data. There are multiple ways you can interact with streams with an external process:

  • Let the child process inherit the stream from the parent process
  • Provide a pre-existing Handle.
  • Create a new Handle to allow more control of the interaction.

One downside of the System.Process API is that there is no static type safety to ensure that the std_out parameter in fact matches up with the value produced by createProcess for the standard output handle. To overcome this, Data.Conduit.Process makes use of type classes to represent the different ways to create a stream. This isn't entirely intuitive from the Haddocks, but once you see the concept used, it's easy to use yourself.

Inherited and ClosedStream

Let's start with an example of using the simplest instances of our typeclasses. Inherited says to inherit the Handle from the parent process, while ClosedStream says to close the stream to the child process. For example, the next snippet will inherit stdin and stdout from the parent process and close standard error.

import Data.Conduit.Process main :: IO () main = do putStrLn "Just wrapping cat. Use Ctrl-D to exit." (Inherited, Inherited, ClosedStream, cph) <- conduitProcess (shell "cat") waitForConduitProcess cph >>= print

Note that there's no way to send an EOF in School of Haskell, so the above active code will never terminate.

Conduit

It would be pretty strange to have a library in conduit-extra that didn't provide some conduit capabilities. You can additionally get a Sink to be used to feed data into the process via standard input, and Sources for consuming standard output and error.

This next example reads standard input from the console, process standard output with a conduit, and closes standard error.

import Data.Conduit (($$)) import qualified Data.Conduit.List as CL import Data.Conduit.Process main :: IO () main = do putStrLn "Just wrapping cat. Use Ctrl-D to exit." (Inherited, src, ClosedStream, cph) <- conduitProcess (shell "cat") src $$ CL.mapM_ print waitForConduitProcess cph >>= print

Note that these Sources and Sinks will never close their Handles. This is done on purpose, to allow them to be used multiple times without accidentally closing their streams. In many cases, you'll need to close the streams manually, which brings us to our next section.

Conduit + close

Let's say we'd like to close our input stream whenever the user types in "quit". To do that, we need to get an action to close the standard input Handle. This is simple: instead of just returning a Source or Sink, we ask for a tuple of a Source/Sink together with an IO () action to close the handle.

{-# LANGUAGE OverloadedStrings #-} import Data.ByteString (ByteString) import Data.Conduit (Source, await, yield, ($$), ($=)) import qualified Data.Conduit.Binary as CB import Data.Conduit.Process import System.IO (stdin) userInput :: Source IO ByteString userInput = CB.sourceHandle stdin $= CB.lines $= loop where loop = do mbs <- await case mbs of Nothing -> return () Just "quit" -> return () Just bs -> do yield bs yield "\n" loop main :: IO () main = do putStrLn "Just wrapping cat. Type \"quit\" to exit." ((sink, close), Inherited, ClosedStream, cph) <- conduitProcess (shell "cat") userInput $$ sink close waitForConduitProcess cph >>= printUseProvidedHandle

Let's take a quick detour from our running example to talk about the last special type: UseProvidedHandle. This says to conduitProcess: use the example value of UseHandle provided in std_in/std_out/std_err. We can use this to redirect output directly to a file:

import Data.Conduit.Process import System.IO (withFile, IOMode (..)) main :: IO () main = do let fp = "date.txt" withFile fp WriteMode $ \h -> do (ClosedStream, UseProvidedHandle, ClosedStream, cph) <- conduitProcess (shell "date") { std_out = UseHandle h } waitForConduitProcess cph >>= print readFile fp >>= printUse with async

In our examples above, we only ever used a single Source or Sink at a time. There's a good reason for this: we can easily run into deadlocks if we don't properly handle concurrency. There are multiple ways to do this, but I'm going to strongly recommend using the async package, which handles many corner cases automatically. In particular, the Concurrently data type and its Applicative instance make it easy and safe to handle multiple streams at once.

Instead of duplicating it here, I'll ask the reader to please refer back to the synopsis example, which ties this all together with two threads for handling streams, and another thread which blocks waiting for the process to exit. That style of concurrency is very idiomatic usage of this library.

Categories: Offsite Blogs

extensible-transformers

haskell-cafe - Thu, 07/10/2014 - 12:52am
Hi cafe, I whipped up extensible-transformers ( https://github.com/RobotGymnast/extensible-transformers) this afternoon. The idea is to make Monad transformer code more like extensible-effects code (http://hackage.haskell.org/package/extensible-effects). Here's a sample: {-# LANGUAGE FlexibleContexts #-} module Main(main) where import Control.Monad.Trans.Flexible import Control.Monad.Trans.List import Control.Monad.Trans.State.Strict
Categories: Offsite Discussion

Taking over setlocale

haskell-cafe - Wed, 07/09/2014 - 10:33pm
Greetings, I would like to take over the setlocale package. Following the steps described on http://www.haskell.org/haskellwiki/Taking_over_a_package I need to state my intention on a public forum. The original author (Lukas Mai) published his package in the Public Domain. This would be fine, but the Author seems to be living in Germany. The problem with that is that in Germany an author is not allowed to give up his copyright in this way. This means the licensing of the package defaults to "All rights reserved", making the package undistributable. I already tried to contact the author about this problem, but he didn't respond in a week. This isn't a very long time, but I didn't get an answer on past attempts to contact him (this was at least a month, but probably more, ago). To solve this problem, I rewrote the setlocale binding with the same API under the BSD3-clause. PS: Please keep the CC to Lukas Mai and the debian-haskell list intact. Regards Sven _____________________________________________
Categories: Offsite Discussion

Looking for architecture/infrastructure advice on coping with thousands of concurrent clients

haskell-cafe - Wed, 07/09/2014 - 6:40pm
Let's just imagine there aren't enough poker sites out there already and that it makes sense to build another one. Basically, there will be players connecting to one or more tables, most likely talking some kind of JSON based protocol with the server(s). #1 - What's a good way to set up and maintain compressed and encrypted connections from the clients to my cluster? I've been wanting to try out websockets, think that'll do? #2 - I'm new to Haskell and would appreciate thoughts on how to store and process game state. Imagine a plain application managing 1000 tables of poker, responding to player input (that magically appears) and timer events (e.g. folding players that fail to take action). What data structures and libraries should I be looking at here? Thoughts on concurrency and how I organize program flow? #3 - I'm thinking of ZMQ to wire components together. Would I be better off basing my cluster on Cloud Haskell or some other library for distributed work? Would love some quick pointers and feedbac
Categories: Offsite Discussion

Danny Gratzer: Examining Hackage: logict

Planet Haskell - Wed, 07/09/2014 - 6:00pm
Posted on July 10, 2014

One of my oldest habits with programming is reading other people’s code. I’ve been doing it almost since I started programming. For the last two years that habit has been focused on Hackage. Today I was reading the source code to the “logic programming monad” provided by logict and wanted to blog about how I go about reading new Haskell code.

This time the code was pretty tiny, find . -name *.hs | xargs wc -l reveals two files with just under 400 lines of code! logict also only has two dependencies, base and the mtl, so there’s not a big worry of unfamiliar libraries.

Setting Up

It’s a lot easier to read this post if you have the source for logict on hand. To grab it, use cabal get. My setup is something like

~ $ cabal get logict ~ $ cd logict-0.6.0.2 ~/logict-0.6.0.2 $ cabal sandbox init ~/logict-0.6.0.2 $ cabal install --only-dependencies Poking Around

I’m somewhat ashamed to admit that I use pretty primitive tooling for exploring a new codebase, it’s grep and find all the way! If you use a fancy IDE, perhaps you can just skip this section and take a moment to sit back and feel high-tech.

First things first is to figure out what Haskell files are here. It can be different than what’s listed on Hackage since often libraries don’t export external files.

~/logict-0.6.0.2 $ find . -name *.hs ./dist/build/autogen/Paths_logict.hs ./Control/Monad/Logic.hs ./Control/Monad/Logic/Class.hs

Alright, there’s two source file and one sitting in dist. The dist one is almost certainly just cabal auto-gened stuff that we don’t care about.

It also appears that there’s no src directory and every module is publicly exported! This means that we only have two modules to worry about.

The next thing to figure out is which to read first. In this case the choice is simple: greping for imports with

grep "import" -r Control

reveals that Control.Monad.Logic imports Control.Monad.Logic.Class so we start with *.Class.

Reading Control.Monad.Logic.Class

Alright! Now it’s actually time to start reading code.

The first thing that jumps out is the export list

module Control.Monad.Logic.Class (MonadLogic(..), reflect, lnot) where

Alright, so we’re exporting everything from a class MonadLogic, as well as two functions reflect and lnot. Let’s go figure out what MonadLogic is.

class (MonadPlus m) => MonadLogic m where msplit :: m a -> m (Maybe (a, m a)) interleave :: m a -> m a -> m a (>>-) :: m a -> (a -> m b) -> m b ifte :: m a -> (a -> m b) -> m b -> m b once :: m a -> m a

The fact that this depends on MonadPlus is pretty significant. Since most classes don’t require this I’m going to assume that it’s fairly key to either the implementation of some of these methods or to using them. Similar to how Monoid is critical to Writer.

The docs make it pretty clear what each member of this class does

  • msplit

    Take a local computation and split it into it’s first result and another computation that computes the rest.

  • interleave

    This is the key difference between MonadLogic and []. interleave gives fair choice between two computation. This means that every result that appears in finitely many applications of msplit for some a and b, will appear in finitely many applications of msplit to interleave a b.

  • >>-

    >>- is similar to interleave. Consider some code like

    (a >>= k) `mplus` (b >>= k)

    This is equivalent to mplus a b >>= k, but has different characteristics since >>= might never terminate. >>- is described as “considering both sides of the disjunction”.

    I have absolutely no idea what that means.. hopefully it’ll be clearer once we look at some implementations.

  • ifte

    This is the equivalent of Prolog’s soft cut. We poke a logical computation and if it can succeed at all, then we feed it into the success computation, otherwise we’ll feed return the failure case.

  • once

    once is clever combinator to prevent backtracking. It will grab the first result from a computation, wrap it up and return it. This prevents backtracking further on the original computation.

Now the docs also state that everything is derivable from msplit. These implementations look like

interleave m1 m2 = msplit m1 >>= maybe m2 (\(a, m1') -> return a `mplus` interleave m2 m1') m >>- f = do (a, m') <- maybe mzero return =<< msplit m interleave (f a) (m' >>- f) ifte t th el = msplit t >>= maybe el (\(a,m) -> th a `mplus` (m >>= th)) once m = do (a, _) <- maybe mzero return =<< msplit m return a

The first thing I notice looking at interleave is that it kinda looks like

interleave' :: [a] -> [a] -> [a] interleave' (x:xs) ys = x : interleave' ys xs interleave _ ys = ys

This makes sense, since this will fairly split between xs and ys just like interleave is supposed to. Here msplit is like pattern matching, mplus is :, and we have to sprinkle some return in there for kicks and giggles.

Now about this mysterious >>-, the biggest difference is that each f a is interleaved, rather than mplus-ed. This should mean that it can be fairly split between our first result, f a and the rest of them m' >>- f. Now if we can do something like

(m >>- f) `interleave` (m' >>- f)

Should have nice and fair behavior.

The next two are fairly clear, ifte splits it’s computation, and if it can it feeds the whole stinking thing return amplusm' to the success computation, otherwise it just returns the failure computation. Nothing stunning.

once is my favorite function. To prevent backtracking all we do is grab the first result and return it.

So that takes care of MonadTrans. The next thing to worry about are these two functions reflect and lnot.

reflect confirms my suspicion that the dual of msplit is mplus (return a) m'.

reflect :: MonadLogic m => Maybe (a, m a) -> m a reflect Nothing = mzero reflect (Just (a, m)) = return a `mplus` m

The next function lnot negates a logical computation. Now, this is a little misleading because the negated computation either produces one value, (), or is mzero and produces nothing. This is easily accomplished with ifte and once

lnot :: MonadLogic m => m a -> m () lnot m = ifte (once m) (const mzero) (return ())

That takes care of most of this file. What’s left is a bunch of instances for monad transformers for MonadTrans. There’s nothing to interesting in them so I won’t talk about them here. It might be worth glancing at the code if you’re interested.

One slightly odd thing I’m noticing is that each class implements all the methods, rather than just msplit. This seems a bit odd.. I guess the default implementations are significantly slower? Perhaps some benchmarking is in order.

Control.Monad.Logic

Now that we’ve finished with Control.Monad.Logic.Class, let’s move on to the main file.

Now we finally see the definition of LogicT

newtype LogicT m a = LogicT { unLogicT :: forall r. (a -> m r -> m r) -> m r -> m r }

I have no idea how this works, but I’m guessing that this is a church version of [a] specialized to some m. Remember that the church version of [a] is

type CList a = forall r. (a -> r -> r) -> r -> r

Now what’s interesting here is that the church version is strongly connected to how CPSed code works. We could than imagine that mplus works like cons for church lists and yields more and more results. But again, this is just speculation.

This suspicion is confirmed by the functions to extract values out of a LogicT computation

observeT :: Monad m => LogicT m a -> m a observeT lt = unLogicT lt (const . return) (fail "No answer.") observeAllT :: Monad m => LogicT m a -> m [a] observeAllT m = unLogicT m (liftM . (:)) (return []) observeManyT :: Monad m => Int -> LogicT m a -> m [a] observeManyT n m | n <= 0 = return [] | n == 1 = unLogicT m (\a _ -> return [a]) (return []) | otherwise = unLogicT (msplit m) sk (return []) where sk Nothing _ = return [] sk (Just (a, m')) _ = (a:) `liftM` observeManyT (n-1) m'

observeT grabs the a from the success continuation and if no result is returned than it will evaluate fail "No Answer which looks like the failure continuation! Looks like out suspicion is confirmed, we’re dealing with monadic church lists or some other permutation of those buzzwords.

Somehow in a package partially designed by Oleg I’m not surprised to find continuations :)

observeAllT is quite similar, notice that we take advantage of the fact that r is universally quantified to instantiate it to a. This quantification is also used in observeManyT. This quantification also prevents any LogicT from taking advantage of the return type to do evil things with returning random values that happen to match the return type. This is what’s possible with ContT for example.

Now we have the standard specialization and smart constructor for the non-transformer version.

type Logic = LogicT Identity logic :: (forall r. (a -> r -> r) -> r -> r) -> Logic a logic f = LogicT $ \k -> Identity . f (\a -> runIdentity . k a . Identity) . runIdentity

Look familiar? Now we can inject real church lists into a Logic computation. I suppose this shouldn’t be surprising since [a] functions like a slightly broken Logic a, without any sharing or soft cut.

Now we repeat all the observe* functions for Logic, I’ll omit these since they’re implementations are exactly as you’d expect and not interesting.

Next we have a few type class instances

instance Functor (LogicT f) where fmap f lt = LogicT $ \sk fk -> unLogicT lt (sk . f) fk instance Applicative (LogicT f) where pure a = LogicT $ \sk fk -> sk a fk f <*> a = LogicT $ \sk fk -> unLogicT f (\g fk' -> unLogicT a (sk . g) fk') fk instance Alternative (LogicT f) where empty = LogicT $ \_ fk -> fk f1 <|> f2 = LogicT $ \sk fk -> unLogicT f1 sk (unLogicT f2 sk fk) instance Monad (LogicT m) where return a = LogicT $ \sk fk -> sk a fk m >>= f = LogicT $ \sk fk -> unLogicT m (\a fk' -> unLogicT (f a) sk fk') fk fail _ = LogicT $ \_ fk -> fk

It helps for reading this if you expand sk to “success continuation” and fk to “fail computation”. Since we’re dealing with church lists I suppose you could also use cons and nil.

What’s particularly interesting to me here is that there are no constraints on m for these type class declarations! Let’s go through them one at a time.

Functor is usually pretty mechanical, and this is no exception. Here we just have to change a -> m r -> m r to b -> m r -> m r. This is trivial just by composing the success computation with f.

Applicative is similar. pure just lifts a value into the church equivalent of a singleton list, [a]. <*> is a little bit more meaty, we first unwrap f to it’s underlying function g, and composes it with out successes computation for a. Notice that this is very similar to how Cont works, continuation passing style is necessary with church representations.

Now return and fail are pretty straightforward. Though this is interesting because since pattern matching calls fail, we can just do something like

do Just a <- m Just b < n return $ a + b

And we’ll run n and m until we get a Just value.

As for >>=, it’s implementation is very similar to <*>. We unwrap m and then feed the unwrapped a into f and run that with our success computations.

We’re only going to talk about one more instance for LogicT, MonadLogic, there are a few others but they’re mostly for MTL use and not too interesting.

instance (Monad m) => MonadLogic (LogicT m) where msplit m = lift $ unLogicT m ssk (return Nothing) where ssk a fk = return $ Just (a, (lift fk >>= reflect))

We’re only implementing msplit here, which strikes me as a bit odd since we implemented everything before. We also actually need Monad m here so that we can use LogicT’s MonadTrans instance.

To split a LogicT, we run a special success computation and return Nothing if failure is ever called. Now there’s one more clever trick here, since we can choose what the r is in m r, we choose it to be Maybe (a, LogicT m a)! That way we can take the failure case, which essentially is just the tail of the list, and push it into reflect.

This confused me a bit so I wrote the equivalent version for church lists, where msplit is just uncons.

{-# LANGUAGE RankNTypes #-} newtype CList a = CList {runCList :: forall r. (a -> r -> r) -> r -> r} cons :: a -> CList a -> CList a cons a (CList list) = CList $ \cs nil -> cs a (list cs nil) nil :: CList a nil = CList $ \cons nil -> nil head :: CList a -> Maybe a head list = runCList list (const . Just) Nothing uncons :: CList a -> Maybe (a, CList a) uncons (CList list) = list skk Nothing where skk a rest = Just (a, maybe nil (uncurry cons) rest)

Now it’s a bit clearer what’s going on, skk just pairs up the head of the list with the rest. However, since the tail of the list has the type m (Maybe (a, LogicT m a)), we lift it back into the LogicT monad and use reflect to smush it back into a good church list.

That about covers Control.Monad.Logic

Wrap Up

I’ve never tried sharing these readings before so I hope you enjoyed it. If this receives some positive feedback I’ll do something similar with another package, I’m leaning towards extensible-effects.

If you’re interested in doing this yourself, I highly recommend it! I’ve learned a lot about practical engineering with Haskell, as well as really clever and elegant Haskell code.

One thing I’ve always enjoyed about the Haskell ecosystem is that some of the most interesting code is often quite easy to read given some time.

<script type="text/javascript"> /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ var disqus_shortname = 'codeco'; // required: replace example with your forum shortname /* * * DON'T EDIT BELOW THIS LINE * * */ (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <noscript>Please enable JavaScript to view the comments powered by Disqus.</noscript> comments powered by Disqus
Categories: Offsite Blogs

Why is package management so awful?

Haskell on Reddit - Wed, 07/09/2014 - 1:48pm

Upgrading ghc is extremely difficult. Upgrading cabal is extremely difficult. Cabal installing new packages almost always fails due to dependency version conflicts. I spent hours trying to download and compile yesod and hours with ghcjs. I'm still working on the latter. Are these issues being taken seriously in the haskell community? I'm quite surprised and honestly sad at how poorly haskell's dependency management was implemented given that everything else is architected so impressively. Is there hope? Because I would love to continue my path toward haskell enlightenment but a lot of my time is being wasted on installation issues.

submitted by p01ym47h
[link] [97 comments]
Categories: Incoming News

Storing functions with data-acid

Haskell on Reddit - Wed, 07/09/2014 - 8:16am

Can acid-state be safely used with structures that cannot be checkpointed? In particular I was thinking of storing functions which can be updated. Then as long as I don't call createCheckpoint, things will continue to work?

So for example, something like -

data Func a b = Func { run :: a -> (b, (Func a b)) }

I can then define a dummy safecopy instance -

instance SafeCopy (Func a b) where putCopy = undefined getCopy = undefined

Declare a transaction -

apply :: a -> Update (Func a b) b apply a = do (b,f) <- gets (($ a) . run) put f return b $(makeAcidic ''Func ['apply])

A sample function -

sample :: Func Int Int sample = sample' 0 sample' n = Func $ \a -> (a+n, sample' $ n+1)

And then I can do this (I have tried this and it seems to work) -

main = do acid <- openLocalState sample putStrLn "Please enter an integer:" s <- getLine let n = read s n' <- update acid (Apply n) putStrLn $ "The answer is: " ++ (show n') submitted by haskman
[link] [12 comments]
Categories: Incoming News

Turning a message parser into a protocol handler

haskell-cafe - Wed, 07/09/2014 - 7:10am
The last few days I've been playing around with the combination of attoparsec/blaze/conduit to build a parser and a generator of messages in a small proprietary protocol used at work. The goal is to easily build small clients of the protocol, and possibly, if time permits, build a server in Haskell which mimics the C implementation of the server. I've come so far that the message parsing and generating is working. I've also put together a couple of tiny clients to verify that my Haskell code can communicate with the production implementation of the server. I've done this by manually tying the toy example behaviour into my conduit process. However, I recognise that as the required behaviour becomes more and more complex my thinking about the behaviour more and more resembles a finite automaton (or FSM). This led me to look around for an FSM generator tool or library for Haskell, but found none. Did I miss something in my search? Or maybe Haskell already IS the FSM generator tool I need. /M
Categories: Offsite Discussion

ANNOUNCE: sai-shape-syb Generic mapping tohomogeneous types (etc.)

haskell-cafe - Wed, 07/09/2014 - 4:31am
This package provides some support for dealing with polytypic data. It lets you escape from the generics world and work with a homogeneous rose tree, which can sometimes be convenient. I realise a more experienced programmer would probably do this differently, but anyhow it was useful to me and I've uploaded it. http://hackage.haskell.org/package/sai-shape-syb There are some examples at http://fremissant.net/shape-syb In particular, it supports GHC staged traversals, so for those trying to work with the GHC AST this might be a helpful tool for filtering, debugging, and suchlike. Kind Regards, Andrew Seniuk rasfar on #haskell _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe< at >haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Categories: Offsite Discussion

security update practice?

haskell-cafe - Wed, 07/09/2014 - 2:47am
Hi all, there was a security update to the underlying library to one of my bindings last night (lz4) and it got me thinking - how do we handle security updates as a community? I typically find out from IRC or twitter now, which isn't particularly reliable. Might it be possible to mark an update on Hackage as a security update rather than feature update? cheers Mark
Categories: Offsite Discussion

Travis CI

haskell-cafe - Wed, 07/09/2014 - 2:10am
Hi, This is just FYI. As you may know, Travis CI itself provides multiple versions of GHC now: http://docs.travis-ci.com/user/languages/haskell/ But I was suffering from test failures indicated by: ghc_find: command not found I heard that this problem is fixed today. https://github.com/travis-ci/travis-ci/issues/2364 --Kazu
Categories: Offsite Discussion

Webdriver: Couldn't match type `Element' with `WDElement'

haskell-cafe - Tue, 07/08/2014 - 11:52pm
I received some help/guidance in #haskell, but I still can't get this to work. I'm basically trying to find all the text elemnts in a webpage with the webdriver package. Here is my code and errors: {-# LANGUAGE OverloadedStrings #-} import Control.Monad import Control.Monad.IO.Class import Test.WebDriver import Test.WebDriver.Classes (WebDriver (..)) import Test.WebDriver.Commands import Test.WebDriver.Commands.Wait main = do runSession defaultSession capabilities $ do openPage "http://www.appnitro.com/demo/view.php?id=1" inputs <- findElems $ ByTag "input" textElems <- filterM (liftM $ ((==) "text" . (`attr` "type"))) inputs -- wait 20 seconds waitUntil 20 (getText <=< findElem $ ByCSS ".doesnotexist") `onTimeout` return "" liftIO $ putStrLn "done" where capabilities = allCaps { browser=firefox }
Categories: Offsite Discussion