https://wiki.haskell.org/api.php?action=feedcontributions&user=Aninhumer&feedformat=atomHaskellWiki - User contributions [en]2023-03-24T06:59:43ZUser contributionsMediaWiki 1.31.7https://wiki.haskell.org/index.php?title=Monad/ST&diff=43776Monad/ST2011-12-31T12:56:42Z<p>Aninhumer: /* An explanation in Haskell-Cafe */</p>
<hr />
<div>{{Standard class|ST|module=Control.Monad.ST|module-doc=Control-Monad-ST|package=base}}<br />
<br />
The ST monad provides support for ''strict'' state threads.<br />
<br />
<br />
==A discussion on the Haskell irc ==<br />
From #haskell (see 13:05:37 in the [http://tunes.org/~nef/logs/haskell/07.02.07 log] ):<br />
<br />
* TuringTest: ST lets you implement algorithms that are much more efficient with mutable memory used internally. But the whole "thread" of computation cannot exchange mutable state with the outside world, it can only exchange immutable state.<br />
<br />
* TuringTest: chessguy: You pass in normal Haskell values and then use ST to allocate mutable memory, then you initialize and play with it, then you put it away and return a normal Haskell value.<br />
<br />
* sjanssen: a monad that has mutable references and arrays, but has a "run" function that is referentially transparent<br />
<br />
* DapperDan2: it strikes me that ST is like a lexical scope, where all the variables/state disappear when the function returns.<br />
[[Category:Standard classes]] [[Category:Monad]]<br />
<br />
<br />
==An explanation in Haskell-Cafe==<br />
<br />
The ST monad lets you use update-in-place, but is escapable (unlike IO). <br />
ST actions have the form:<br />
<br />
<haskell><br />
ST s α<br />
</haskell><br />
<br />
Meaning that they return a value of type α, and execute in "thread" s.<br />
All reference types are tagged with the thread, so that actions can only<br />
affect references in their own "thread".<br />
<br />
Now, the type of the function used to escape ST is:<br />
<br />
<haskell><br />
runST :: forall α. (forall s. ST s α) -> α<br />
</haskell><br />
<br />
The action you pass must be universal in s, so inside your action you<br />
don't know what thread, thus you cannot access any other threads, thus<br />
<hask>runST</hask> is pure. This is very useful, since it allows you to implement externally pure things like in-place quicksort, and present them as pure functions ∀ e. Ord e ⇒ Array e → Array e; without using any unsafe functions.<br />
<br />
But that type of <hask>runST</hask> is illegal in Haskell-98, because it needs a universal quantifier *inside* the function-arrow! In the jargon, that type has rank 2; haskell 98 types may have rank at most 1.<br />
<br />
See http://www.haskell.org/pipermail/haskell-cafe/2007-July/028233.html<br />
<br />
Could we *please* see an example.<br />
<br />
Sure thing...<br />
<br />
== A few simple examples ==<br />
<br />
In this example, we define a version of the function sum, but do it in a way which more like how it would be done in imperative languages, where a variable is updated, rather than a new value is formed and passed to the next iteration of the function. While in place modifications of the STRef n are occurring, something that would usually be considered a side effect, it is all done in a safe way which is deterministic. The result is that we get the benefits of being able to modify memory in place, while still producing a pure function with the use of runST.<br />
<br />
<haskell><br />
import Control.Monad.ST<br />
import Data.STRef<br />
import Control.Monad<br />
<br />
<br />
sumST :: Num a => [a] -> a<br />
sumST xs = runST $ do -- runST takes out stateful code and makes it pure again.<br />
<br />
n <- newSTRef 0 -- Create an STRef (place in memory to store values)<br />
<br />
forM_ xs $ \x -> do -- For each element of xs ..<br />
modifySTRef n (+x) -- add it to what we have in n.<br />
<br />
readSTRef n -- read the value of n, and return it.<br />
<br />
<br />
</haskell><br />
<br />
An implementation of foldl using the ST monad (a lot like sum, and in fact sum can be defined in terms of foldlST):<br />
<br />
<haskell><br />
foldlST :: (a -> b -> a) -> a -> [b] -> a<br />
foldlST f acc xs = runST $ do<br />
acc' <- newSTRef acc -- Create a variable for the accumulator<br />
<br />
forM_ xs $ \x -> do -- For each x in xs...<br />
<br />
a <- readSTRef acc' -- read the accumulator<br />
writeSTRef acc' (f a x) -- apply f to the accumulator and x<br />
<br />
readSTRef acc' -- and finally read the result<br />
</haskell><br />
<br />
An example of the Fibonacci function running in constant¹ space:<br />
<br />
<haskell><br />
fibST :: Integer -> Integer<br />
fibST n = <br />
if n < 2<br />
then n<br />
else runST $ do<br />
x <- newSTRef 0<br />
y <- newSTRef 1<br />
fibST' n x y<br />
<br />
where fibST' 0 x _ = readSTRef x<br />
fibST' n x y = do<br />
x' <- readSTRef x<br />
y' <- readSTRef y<br />
writeSTRef x y'<br />
writeSTRef y (x'+y')<br />
fibST' (n-1) x y<br />
</haskell><br />
[1] (Since we're using Integers, technically it's not constant space, as they grow in size when they get bigger, but we can ignore this.)</div>Aninhumerhttps://wiki.haskell.org/index.php?title=Monad/ST&diff=43775Monad/ST2011-12-31T12:56:24Z<p>Aninhumer: /* An explanation in Haskell-Cafe */</p>
<hr />
<div>{{Standard class|ST|module=Control.Monad.ST|module-doc=Control-Monad-ST|package=base}}<br />
<br />
The ST monad provides support for ''strict'' state threads.<br />
<br />
<br />
==A discussion on the Haskell irc ==<br />
From #haskell (see 13:05:37 in the [http://tunes.org/~nef/logs/haskell/07.02.07 log] ):<br />
<br />
* TuringTest: ST lets you implement algorithms that are much more efficient with mutable memory used internally. But the whole "thread" of computation cannot exchange mutable state with the outside world, it can only exchange immutable state.<br />
<br />
* TuringTest: chessguy: You pass in normal Haskell values and then use ST to allocate mutable memory, then you initialize and play with it, then you put it away and return a normal Haskell value.<br />
<br />
* sjanssen: a monad that has mutable references and arrays, but has a "run" function that is referentially transparent<br />
<br />
* DapperDan2: it strikes me that ST is like a lexical scope, where all the variables/state disappear when the function returns.<br />
[[Category:Standard classes]] [[Category:Monad]]<br />
<br />
<br />
==An explanation in Haskell-Cafe==<br />
<br />
The ST monad lets you use update-in-place, but is escapable (unlike IO). <br />
ST actions have the form:<br />
<br />
<haskell><br />
ST s α<br />
</haskell><br />
<br />
Meaning that they return a value of type α, and execute in "thread" s.<br />
All reference types are tagged with the thread, so that actions can only<br />
affect references in their own "thread".<br />
<br />
Now, the type of the function used to escape ST is:<br />
<br />
<haskell><br />
runST :: forall α. (forall s. ST s α) -> α<br />
</haskell><br />
<br />
The action you pass must be universal in s, so inside your action you<br />
don't know what thread, thus you cannot access any other threads, thus<br />
<hask>runST</hask> is pure. This is very useful, since it allows you to implement externally pure things like in-place quicksort, and present them as pure functions ∀ e. Ord e ⇒ Array e → Array e; without using any unsafe functions.<br />
<br />
But that type of <hask>runST</hask> is illegal in Haskell-98, because it needs a universal quantifier *inside* the function-arrow! In the jargon, that<br />
type has rank 2; haskell 98 types may have rank at most 1.<br />
<br />
See http://www.haskell.org/pipermail/haskell-cafe/2007-July/028233.html<br />
<br />
Could we *please* see an example.<br />
<br />
Sure thing...<br />
<br />
== A few simple examples ==<br />
<br />
In this example, we define a version of the function sum, but do it in a way which more like how it would be done in imperative languages, where a variable is updated, rather than a new value is formed and passed to the next iteration of the function. While in place modifications of the STRef n are occurring, something that would usually be considered a side effect, it is all done in a safe way which is deterministic. The result is that we get the benefits of being able to modify memory in place, while still producing a pure function with the use of runST.<br />
<br />
<haskell><br />
import Control.Monad.ST<br />
import Data.STRef<br />
import Control.Monad<br />
<br />
<br />
sumST :: Num a => [a] -> a<br />
sumST xs = runST $ do -- runST takes out stateful code and makes it pure again.<br />
<br />
n <- newSTRef 0 -- Create an STRef (place in memory to store values)<br />
<br />
forM_ xs $ \x -> do -- For each element of xs ..<br />
modifySTRef n (+x) -- add it to what we have in n.<br />
<br />
readSTRef n -- read the value of n, and return it.<br />
<br />
<br />
</haskell><br />
<br />
An implementation of foldl using the ST monad (a lot like sum, and in fact sum can be defined in terms of foldlST):<br />
<br />
<haskell><br />
foldlST :: (a -> b -> a) -> a -> [b] -> a<br />
foldlST f acc xs = runST $ do<br />
acc' <- newSTRef acc -- Create a variable for the accumulator<br />
<br />
forM_ xs $ \x -> do -- For each x in xs...<br />
<br />
a <- readSTRef acc' -- read the accumulator<br />
writeSTRef acc' (f a x) -- apply f to the accumulator and x<br />
<br />
readSTRef acc' -- and finally read the result<br />
</haskell><br />
<br />
An example of the Fibonacci function running in constant¹ space:<br />
<br />
<haskell><br />
fibST :: Integer -> Integer<br />
fibST n = <br />
if n < 2<br />
then n<br />
else runST $ do<br />
x <- newSTRef 0<br />
y <- newSTRef 1<br />
fibST' n x y<br />
<br />
where fibST' 0 x _ = readSTRef x<br />
fibST' n x y = do<br />
x' <- readSTRef x<br />
y' <- readSTRef y<br />
writeSTRef x y'<br />
writeSTRef y (x'+y')<br />
fibST' (n-1) x y<br />
</haskell><br />
[1] (Since we're using Integers, technically it's not constant space, as they grow in size when they get bigger, but we can ignore this.)</div>Aninhumerhttps://wiki.haskell.org/index.php?title=Monad/ST&diff=43774Monad/ST2011-12-31T12:55:52Z<p>Aninhumer: </p>
<hr />
<div>{{Standard class|ST|module=Control.Monad.ST|module-doc=Control-Monad-ST|package=base}}<br />
<br />
The ST monad provides support for ''strict'' state threads.<br />
<br />
<br />
==A discussion on the Haskell irc ==<br />
From #haskell (see 13:05:37 in the [http://tunes.org/~nef/logs/haskell/07.02.07 log] ):<br />
<br />
* TuringTest: ST lets you implement algorithms that are much more efficient with mutable memory used internally. But the whole "thread" of computation cannot exchange mutable state with the outside world, it can only exchange immutable state.<br />
<br />
* TuringTest: chessguy: You pass in normal Haskell values and then use ST to allocate mutable memory, then you initialize and play with it, then you put it away and return a normal Haskell value.<br />
<br />
* sjanssen: a monad that has mutable references and arrays, but has a "run" function that is referentially transparent<br />
<br />
* DapperDan2: it strikes me that ST is like a lexical scope, where all the variables/state disappear when the function returns.<br />
[[Category:Standard classes]] [[Category:Monad]]<br />
<br />
<br />
==An explanation in Haskell-Cafe==<br />
<br />
The ST monad lets you use update-in-place, but is escapable (unlike IO). <br />
ST actions have the form:<br />
<br />
<haskell><br />
ST s α<br />
</haskell><br />
<br />
Meaning that they return a value of type α, and execute in "thread" s.<br />
All reference types are tagged with the thread, so that actions can only<br />
affect references in their own "thread".<br />
<br />
Now, the type of the function used to escape ST is:<br />
<br />
<haskell><br />
runST :: forall α. (forall s. ST s α) -> α<br />
</haskell><br />
<br />
The action you pass must be universal in s, so inside your action you<br />
don't know what thread, thus you cannot access any other threads, thus<br />
<hask>runST</hask> is pure. This is very useful, since it allows you to implement externally pure things like in-place quicksort, and present them as pure functions ∀ e. Ord e ⇒ Array e → Array e; without using any unsafe<br />
functions.<br />
<br />
But that type of <hask>runST</hask> is illegal in Haskell-98, because it needs a<br />
universal quantifier *inside* the function-arrow! In the jargon, that<br />
type has rank 2; haskell 98 types may have rank at most 1.<br />
<br />
See http://www.haskell.org/pipermail/haskell-cafe/2007-July/028233.html<br />
<br />
Could we *please* see an example.<br />
<br />
Sure thing...<br />
<br />
== A few simple examples ==<br />
<br />
In this example, we define a version of the function sum, but do it in a way which more like how it would be done in imperative languages, where a variable is updated, rather than a new value is formed and passed to the next iteration of the function. While in place modifications of the STRef n are occurring, something that would usually be considered a side effect, it is all done in a safe way which is deterministic. The result is that we get the benefits of being able to modify memory in place, while still producing a pure function with the use of runST.<br />
<br />
<haskell><br />
import Control.Monad.ST<br />
import Data.STRef<br />
import Control.Monad<br />
<br />
<br />
sumST :: Num a => [a] -> a<br />
sumST xs = runST $ do -- runST takes out stateful code and makes it pure again.<br />
<br />
n <- newSTRef 0 -- Create an STRef (place in memory to store values)<br />
<br />
forM_ xs $ \x -> do -- For each element of xs ..<br />
modifySTRef n (+x) -- add it to what we have in n.<br />
<br />
readSTRef n -- read the value of n, and return it.<br />
<br />
<br />
</haskell><br />
<br />
An implementation of foldl using the ST monad (a lot like sum, and in fact sum can be defined in terms of foldlST):<br />
<br />
<haskell><br />
foldlST :: (a -> b -> a) -> a -> [b] -> a<br />
foldlST f acc xs = runST $ do<br />
acc' <- newSTRef acc -- Create a variable for the accumulator<br />
<br />
forM_ xs $ \x -> do -- For each x in xs...<br />
<br />
a <- readSTRef acc' -- read the accumulator<br />
writeSTRef acc' (f a x) -- apply f to the accumulator and x<br />
<br />
readSTRef acc' -- and finally read the result<br />
</haskell><br />
<br />
An example of the Fibonacci function running in constant¹ space:<br />
<br />
<haskell><br />
fibST :: Integer -> Integer<br />
fibST n = <br />
if n < 2<br />
then n<br />
else runST $ do<br />
x <- newSTRef 0<br />
y <- newSTRef 1<br />
fibST' n x y<br />
<br />
where fibST' 0 x _ = readSTRef x<br />
fibST' n x y = do<br />
x' <- readSTRef x<br />
y' <- readSTRef y<br />
writeSTRef x y'<br />
writeSTRef y (x'+y')<br />
fibST' (n-1) x y<br />
</haskell><br />
[1] (Since we're using Integers, technically it's not constant space, as they grow in size when they get bigger, but we can ignore this.)</div>Aninhumerhttps://wiki.haskell.org/index.php?title=Hierarchical_module_names&diff=41633Hierarchical module names2011-08-15T20:54:48Z<p>Aninhumer: </p>
<hr />
<div>'''Hierarchical module names''' are an early extension of Haskell 98. Haskell 98 only allowed atomic module names like <hask>List</hask> which was later moved into the hierarchical naming scheme as <hask>Data.List</hask>.<br />
<br />
For new libraries the question arises, of where to place new modules.<br />
If you upload a package to [http://hackage.haskell.org/ Hackage] it will check whether your modules at least use common names for module directories at the top level.<br />
<br />
<code><br />
Algebra -- Was this ever used?<br />
DomainConstructor -- formerly DoCon<br />
Geometric -- formerly BasGeomAlg<br />
<br />
Codec -- Coders/Decoders for various data formats<br />
Audio<br />
Wav<br />
MP3<br />
...<br />
Compression<br />
Gzip<br />
Bzip2<br />
...<br />
Encryption<br />
DES<br />
RSA<br />
BlowFish<br />
...<br />
Image<br />
GIF<br />
PNG<br />
JPEG<br />
TIFF<br />
...<br />
Text<br />
UTF8<br />
UTF16<br />
ISO8859<br />
...<br />
Video<br />
Mpeg<br />
QuickTime<br />
Avi<br />
...<br />
Binary -- these are for encoding binary data into text<br />
Base64<br />
Yenc<br />
<br />
Control<br />
Applicative<br />
Arrow<br />
Exception -- (opt, inc. error & undefined)<br />
Concurrent -- as hslibs/concurrent<br />
Chan -- these could all be moved under Data<br />
MVar<br />
Merge<br />
QSem<br />
QSemN<br />
SampleVar<br />
Semaphore<br />
Parallel -- as hslibs/concurrent/Parallel<br />
Strategies<br />
Monad -- Haskell 98 Monad library<br />
ST -- ST defaults to Strict variant?<br />
Strict -- renaming for ST<br />
Lazy -- renaming for LazyST<br />
State -- defaults to Lazy<br />
Strict<br />
Lazy<br />
Error<br />
Identity<br />
Monoid<br />
Reader<br />
Writer<br />
Cont<br />
Fix -- to be renamed to Rec?<br />
List<br />
RWS<br />
<br />
Data<br />
Binary -- Binary I/O<br />
Bits<br />
Bool -- &&, ||, not, otherwise<br />
Tuple -- fst, snd<br />
Char -- H98<br />
Complex -- H98<br />
Dynamic<br />
Either<br />
Int<br />
Maybe -- H98<br />
List -- H98<br />
PackedString<br />
Ratio -- H98<br />
Word<br />
IORef<br />
STRef -- Same as Data.STRef.Strict<br />
Strict <br />
Lazy -- The lazy version (for Control.Monad.ST.Lazy)<br />
Binary -- Haskell binary I/O<br />
Digest<br />
MD5<br />
... -- others (CRC ?)<br />
Array -- Haskell 98 Array library<br />
Unboxed<br />
IArray<br />
MArray<br />
IO -- mutable arrays in the IO/ST monads<br />
ST<br />
Trees<br />
AVL<br />
RedBlack<br />
BTree<br />
Queue<br />
Bankers<br />
FIFO<br />
Collection<br />
Graph -- start with GHC's DiGraph?<br />
FiniteMap<br />
Set<br />
Memo -- (opt)<br />
Unique<br />
<br />
Edison -- (opt, uses multi-param type classes)<br />
Prelude -- large self-contained packages should have<br />
Collection -- their own hierarchy? Like a vendor branch.<br />
Queue -- Or should the whole Edison tree be placed<br />
<br />
Database<br />
MySQL<br />
PostgreSQL<br />
ODBC<br />
<br />
Dotnet<br />
... -- Mirrors the MS .NET class hierarchy<br />
<br />
Debug -- see also: Test<br />
Trace<br />
Observe -- choose a default amongst the variants<br />
Textual -- Andy Gill's release 1<br />
ToXmlFile -- Andy Gill's XML browser variant<br />
GHood -- Claus Reinke's animated variant<br />
<br />
Foreign<br />
Ptr<br />
StablePtr<br />
ForeignPtr -- rename to FinalisedPtr? to void confusion with Foreign.Ptr<br />
Storable<br />
Marshal<br />
Alloc<br />
Array<br />
Errors<br />
Utils<br />
C<br />
Types<br />
Errors<br />
Strings<br />
<br />
GHC<br />
Exts -- hslibs/lang/GlaExts<br />
...<br />
<br />
Graphics<br />
HGL<br />
Rendering<br />
Direct3D<br />
FRAN<br />
Metapost<br />
Inventor<br />
Haven<br />
OpenGL<br />
GL<br />
GLU<br />
Pan<br />
UI<br />
FranTk<br />
Fudgets<br />
GLUT<br />
Gtk<br />
Motif<br />
ObjectIO<br />
TkHaskell<br />
X11<br />
Xt<br />
Xlib<br />
Xmu<br />
Xaw<br />
<br />
Hugs<br />
...<br />
<br />
Language<br />
Haskell -- hslibs/hssource<br />
Syntax<br />
Lexer<br />
Parser<br />
Pretty<br />
HaskellCore<br />
Python<br />
C<br />
...<br />
<br />
Nhc<br />
...<br />
<br />
Numeric -- exports std. H98 numeric type classes<br />
Statistics<br />
<br />
Network -- (== hslibs/net/Socket), depends on FFI only<br />
BER -- Basic Encoding Rules<br />
Socket -- or rename to Posix?<br />
URI -- general URI parsing<br />
CGI -- one in hslibs is ok?<br />
Protocol<br />
HTTP<br />
FTP<br />
SMTP<br />
<br />
Prelude -- Haskell98 Prelude (mostly just re-exports<br />
other parts of the tree).<br />
<br />
Sound -- Sound, Music, Digital Signal Processing<br />
ALSA<br />
JACK<br />
MIDI<br />
OpenAL<br />
SC3 -- SuperCollider<br />
<br />
System -- Interaction with the "system"<br />
Cmd -- ( system )<br />
CPUTime -- H98<br />
Directory -- H98<br />
Exit -- ( ExitCode(..), exitWith, exitFailure )<br />
Environment -- ( getArgs, getProgName, getEnv ... )<br />
Info -- info about the host system<br />
IO -- H98 + IOExts - IOArray - IORef<br />
Select<br />
Unsafe -- unsafePerformIO, unsafeInterleaveIO<br />
Console<br />
GetOpt<br />
Readline<br />
Locale -- H98<br />
Posix<br />
Console<br />
Directory<br />
DynamicLinker<br />
Prim<br />
Module<br />
IO<br />
Process<br />
Time<br />
Mem -- rename from cryptic 'GC'<br />
Weak -- (opt)<br />
StableName -- (opt)<br />
Time -- H98 + extensions<br />
Win32 -- the full win32 operating system API<br />
<br />
Test<br />
HUnit<br />
QuickCheck<br />
<br />
Text<br />
Encoding<br />
QuotedPrintable<br />
Rot13<br />
Read<br />
Lex -- cut down lexer for "read"<br />
Show<br />
Functions -- optional instance of Show for functions.<br />
Regex -- previously RegexString<br />
Posix -- Posix regular expression interface<br />
PrettyPrint -- default (HughesPJ?)<br />
HughesPJ<br />
Wadler<br />
Chitil<br />
...<br />
HTML -- HTML combinator lib<br />
XML<br />
Combinators<br />
Parse<br />
Pretty<br />
Types<br />
ParserCombinators -- no default<br />
ReadP -- a more efficient "ReadS"<br />
Parsec<br />
Hutton_Meijer<br />
...<br />
<br />
Training -- Collect study and learning materials<br />
<name of the tutor><br />
</code><br />
<br />
<br />
== Source ==<br />
<br />
This is an adapted version of Simon Marlow's original [http://www.haskell.org/~simonmar/lib-hierarchy.html overview].<br />
<br />
[[Category:Style]]</div>Aninhumerhttps://wiki.haskell.org/index.php?title=CamHac/PostHackathonReport&diff=41619CamHac/PostHackathonReport2011-08-15T11:18:05Z<p>Aninhumer: Added DHT project info</p>
<hr />
<div>= Post-Hackathon Report =<br />
<br />
This page is for listing what was done during the Hackathon. Please add a short description of what you worked on, with links to relevant blog posts, hackage packages, commits, etc.<br />
<br />
== fclabels 1.0 release ==<br />
<br />
New release of the '''fclabels''' package. The new package has a lot of code and documentation cleanups, support for partial labels in the case of multi-constructor datatypes and is about 20x as fast for setting and modifying as the previous version. Thanks everyone for helping me out!<br />
<br />
Hackage: http://hackage.haskell.org/package/fclabels-1.0.1<br />
<br />
Github: http://github.com/sebastiaanvisser/fclabels<br />
<br />
== GHC and base library improvements ==<br />
<br />
* [http://hackage.haskell.org/trac/ghc/ticket/5413 Add primops for bit population count]. These primops compile down to `POPCNT` instructions where available and fast fallbacks (implemented in C) otherwise.<br />
<br />
* [http://hackage.haskell.org/trac/ghc/ticket/5414 Add unchecked left and right bit shifts]: The Data.Bits.shift method uses a branch to check if the shift amount is larger than the word size and returns 0 in these cases. This extra safety makes performance worse in bit twiddling code.<br />
<br />
* Discussed unpacking of enums in GHC (not yet implemented).<br />
<br />
* Discussed refactoring compiler/util/Digraph.lhs into a reusable graph combinator library, along with porting over hoopl's control-flow-graph traversals (not yet implemented).<br />
<br />
== Context synonym families ==<br />
<br />
Started working on context synonym families and indexed context synonym families. We make this work by giving evidence the new kind Fact, and then allowing any type of kind Fact to appear on the left of a => arrow.<br />
<br />
(Max Bolingbroke, Dominic Orchard and Nicolas Wu)<br />
<br />
== Darcs ==<br />
<br />
New contributors:<br />
<br />
* use red text to report when <font color="red">we have a conflict</font> ([http://bugs.darcs.net/issue1681 issue1681],[http://bugs.darcs.net/patch646 patch646], Jeff Foster)<br />
* support 'since' in English dates parser<br />
* filter SSH output ([http://bugs.darcs.net/issue845 issue845], Jeff Foster and Sebastian Korten)<br />
* support arbitrary darcs command in darcs-test (Alexander Njemz)<br />
* output ISO dates in darcs changes? ([http://bugs.darcs.net/issue140 issue140], Alexander N, may be not a good idea)<br />
* add a last regrets prompt to interactive patch selection ([http://bugs.darcs.net/issue1920 issue1920], [http://bugs.darcs.net/patch655 patch655], Johannes Weiß)<br />
* [in-progress] support removing changes in amend-record ([http://bugs.darcs.net/issue1470 issue1470], Johannes Weiß)<br />
<br />
== wxHaskell ==<br />
<br />
* a Windows build fix ([https://sourceforge.net/mailarchive/forum.php?thread_name=CAA5%3D7kb%2BCmJ178tvrxtOnuswWBeBxYpSotiQWRXuKE3m_sByXA%40mail.gmail.com&forum_name=wxhaskell-devel patch])<br />
* a fix for [https://sourceforge.net/tracker/?func=detail&aid=3019730&group_id=73133&atid=536845 an issue with colorDialog] ([https://sourceforge.net/mailarchive/forum.php?thread_name=20110813150933.GA758%40dewdrop.local&forum_name=wxhaskell-devel patch])<br />
<br />
== hCole-server ==<br />
<br />
* A Snap-based web application that interacts with the COLE (see http://portal.acm.org/citation.cfm?id=1356080 and http://portal.acm.org/citation.cfm?id=1772965) framework for exploring compiler optimisation levels. The purpose of the web app is that collaborators can submit optimisation sequences to the COLE backend and retrieve the results when they are available after measuring.<br />
* Git repository of the web application can be found at https://github.com/itkovian/hcole-server<br />
<br />
== GObject Introspection ==<br />
<br />
* Work-in-progress binding generator for GObject-based libraries such as Gtk+ 3.<br />
* Started switching to [http://hackage.haskell.org/package/haskell-src-exts-1.11.1 haskell-src-exts] for code generation.<br />
* Patches currently on the ''camhac'' branch on [https://gitorious.org/haskell-gi/haskell-gi gitorious].<br />
<br />
== Snap Framework ==<br />
<br />
* Snap 0.5.3 and 0.5.3.1 released!<br />
<br />
* Several bugs squashed or nearly-squashed: [https://github.com/snapframework/snap-core/issues/2 #2] (IPv6 support, from Vlad Hanciuta), [https://github.com/snapframework/snap-core/issues/77 #77], [https://github.com/snapframework/snap-core/issues/78 #78], and [https://github.com/snapframework/snap-core/issues/79 #79].<br />
<br />
* File upload code: replaced "openBinaryTempFile" with something less dumb (mkstemp) on unix, and fixed some iteratee cleanup problems using an MVar finalizer<br />
<br />
* Removed the template haskell code from Data.Concurrent.HashMap in snap-server<br />
<br />
* Some work has been done on the authentication Snaplet, including an (incomplete) HDBC backend for it. An early work-in-progress can be found here: https://github.com/norm2782/snap<br />
* An example application which uses Snap 0.6 has been improved to use the authentication Snaplet. Another work-in-progress: https://github.com/norm2782/snap-guestbook<br />
<br />
== Data.Text ==<br />
<br />
* Further benchmarking, bug fixing to support the UTF-8 port<br />
* Progress can be found in the ''utf8'' branch [http://github.com/jaspervdj/text here]<br />
* The [http://jaspervdj.be/files/text.html GSoC project] is basically done, next up is writing a summary report of benchmark results and what advantages and disadvantages come with the port<br />
<br />
== hs-poker ==<br />
<br />
* A "redneck naive" poker hand evaluator. Code is on github (https://github.com/fffej/HS-Poker). Hopefully intend to turn this into a poker bot playground for Haskell (Jeff / Sebastian)<br />
<br />
== haskell-mpi ==<br />
* New version 1.1.0 uploaded to hackage, including support for more MPI implementations, bugfixes and general awesomness<br />
* Upcoming Monad Reader would feature and article about parallel programming with MPI, written during the course of the hackathon (Dmitry Astapov)<br />
<br />
== HTTP ==<br />
<br />
Some work was done on setting up tests for HTTP. Additionally, some bugs were fixed, code was cleaned up, warnings removed and a start was made on improving the Network.Browser module.<br />
<br />
== EchoNest API ==<br />
<br />
A very nascent API for accessing the EchoNest Music API http://developer.echonest.com/docs/v4/index.html . Coming to a GitHub server in the near future, as soon as it stops looking so ugly (Ian Knopke / Jose Calderon).<br />
<br />
== TagSoup/Derive/HLint ==<br />
<br />
All the above packages got upgraded to the latest GHC, along with a few bug fixes (Derive now deals with singleton constructors with no fields, HLint now supports an ANSI CPP flag) (Neil Mitchell)<br />
<br />
== Hoogle ==<br />
<br />
The current Hoogle parser for user queries is old, doesn't parse everything correctly, and in particular doesn't deal well with partial queries (when the user is still typing their search). We discussed lots of edge cases, and started implementing a new version (Jacek Generowicz, with guidance from Neil Mitchell)<br />
<br />
== CmdArgs ==<br />
<br />
The CmdArgs package lets you concisely specific command line arguments. I ported the package to GHC 7.2.1, did some cleanups, and fixed some bugs (you can now use Int64 etc). I then started working on two new features: 1) Given a CmdArgs program (such as Hoogle) you can specify you want to enter the arguments via a GUI hosted in the web browser. Currently the GUI is a simple textbox with realtime validation, but in future it will become a structured command line argument editor based on the options to your tool. 2) Adding automatic bash autocompletion - some of the work has been done, but the details are not yet finished. (Neil Mitchell)<br />
<br />
== Hackage server ==<br />
<br />
Further refactoring work, simplification of HTTP basic/digest authentication code. Started work on serving package changelogs. Improvements to admin pages to make various features more discoverable.<br />
<br />
Hackathon branch of the code is at (not all patches have been submitted yet):<br />
<br />
darcs get http://code.haskell.org/~duncan/camhac/hackage-server/<br />
<br />
== Bittorrent DHT ==<br />
<br />
Initial work on implementing [http://www.bittorrent.org/beps/bep_0005.html BEP 0005] in Haskell. Some core data structures seem to be working (although untested) and I'm currently working on the protocol. I will probably merge this into Haskell Torrent when everything is working, but I intend to keep the library available separately as I see potential uses for the network other than Bittorrent. (Alex Horsman)<br />
<br />
https://github.com/aninhumer/haskell-dht</div>Aninhumerhttps://wiki.haskell.org/index.php?title=Combinator&diff=41204Combinator2011-07-20T20:04:12Z<p>Aninhumer: </p>
<hr />
<div>A function or definition with no [[free variable]]s.<br />
<br />
'''Question:''' On which syllable do you put the stress when saying "combinator"?<br />
<br />
''I say COM-bin-ay-tur, since it comes from "combine". -- [[User:AndrewBromage]]''<br />
<br />
See also:<br />
* [[Combinator pattern]], which has a good start on how combinators are used in programming<br />
* [[Super combinator]]<br />
<br />
[[Category:Glossary]]<br />
<br />
[[Category:Combinators]]</div>Aninhumerhttps://wiki.haskell.org/index.php?title=Roll_your_own_IRC_bot&diff=40254Roll your own IRC bot2011-05-31T13:35:12Z<p>Aninhumer: Joined all lines correctly, code blocks still need to be formatted nicely</p>
<hr />
<div>This tutorial is designed as a practical guide to writing real world<br />
code in [http://haskell.org Haskell] and hopes to intuitively motivate<br />
and introduce some of the advanced features of Haskell to the novice<br />
programmer. Our goal is to write a concise, robust and elegant<br />
[http://haskell.org/haskellwiki/IRC_channel IRC] bot in Haskell.<br />
<br />
== Getting started ==<br />
<br />
You'll need a reasonably recent version of [http://haskell.org/ghc GHC]<br />
or [http://haskell.org/hugs Hugs]. Our first step is to get on the<br />
network. So let's start by importing the Network package, and the<br />
standard IO library and defining a server to connect to.<br />
<br />
<haskell><br />
import Network<br />
import System.IO<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
<br />
main = do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
t <- hGetContents h<br />
print t<br />
</haskell><br />
<br />
The key here is the <hask>main</hask> function. This is the entry point to a Haskell program. We first connect to the server, then set the buffering on the socket off. Once we've got a socket, we can then just read and print any data we receive.<br />
<br />
Put this code in the module <hask>1.hs</hask> and we can then run it. Use whichever system you like:<br />
<br />
Using runhaskell:<br />
<br />
$ runhaskell 1.hs<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or we can just compile it to an executable with GHC:<br />
<br />
$ ghc --make 1.hs -o tutbot<br />
Chasing modules from: 1.hs<br />
Compiling Main ( 1.hs, 1.o )<br />
Linking ...<br />
$ ./tutbot<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or using GHCi:<br />
<br />
$ ghci 1.hs<br />
*Main> main<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or in Hugs:<br />
<br />
$ runhugs 1.hs<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Great! We're on the network.<br />
<br />
== Talking IRC ==<br />
<br />
Now we're listening to the server, we better start sending some information back. Three details are important: the nick, the user name, and a channel to join. So let's send those.<br />
<br />
<haskell><br />
import Network<br />
import System.IO<br />
import Text.Printf<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
chan = "#tutbot-testing"<br />
nick = "tutbot"<br />
<br />
main = do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
write h "NICK" nick<br />
write h "USER" (nick++" 0 * :tutorial bot")<br />
write h "JOIN" chan<br />
listen h<br />
<br />
write :: Handle -> String -> String -> IO ()<br />
write h s t = do<br />
hPrintf h "%s %s\r\n" s t<br />
printf "> %s %s\n" s t<br />
<br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
s <- hGetLine h<br />
putStrLn s<br />
where<br />
forever a = do a; forever a<br />
</haskell><br />
<br />
Now, we've done quite a few things here. Firstly, we import <hask>Text.Printf</hask>, which will be useful. We also set up a channel name and bot nickname. The <hask>main</hask> function has been extended to send messages back to the IRC server using a <hask>write</hask> function. Let's look at that a bit more closely:<br />
<br />
<haskell><br />
write :: Handle -> String -> String -> IO ()<br />
write h s t = do<br />
hPrintf h "%s %s\r\n" s t<br />
printf "> %s %s\n" s t<br />
</haskell><br />
<br />
We've given <hask>write</hask> an explicit type to help document it, and we'll use explicit types signatures from now on, as they're just good practice (though of course not required, as Haskell uses type inference to work out the types anyway).<br />
<br />
The <hask>write</hask> function takes 3 arguments; a handle (our socket), and then two strings representing an IRC protocol action, and any arguments it takes. <hask>write</hask> then uses <hask>hPrintf</hask> to build an IRC message and write it over the wire to the server. For debugging purposes we also print to standard output the message we send.<br />
<br />
Our second function, <hask>listen</hask>, is as follows:<br />
<br />
<haskell><br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
s <- hGetLine h<br />
putStrLn s<br />
where<br />
forever a = do a; forever a<br />
</haskell><br />
<br />
This function takes a Handle argument, and sits in an infinite loop reading lines of text from the network and printing them. We take advantage of two powerful features; lazy evaluation and higher order functions to roll our own loop control structure, <hask>forever</hask>, as a normal function! <hask>forever</hask> takes a chunk of code as an argument, evaluates it and recurses - an infinite loop function. It is very common to roll our own control structures in Haskell this way, using higher order functions. No need to add new syntax to the language, lisp-like macros or meta programming - you just write a normal function to implement whatever control flow you wish. We can also avoid <hask>do</hask>-notation, and directly write: <hask>forever a = a >> forever a</hask>.<br />
<br />
Let's run this thing:<br />
<br />
<haskell><br />
$ runhaskell 2.hs<br />
> NICK tutbot<br />
> USER tutbot 0 * :tutorial bot<br />
> JOIN #tutbot-testing<br />
NOTICE AUTH :*** Looking up your hostname...<br />
NOTICE AUTH :*** Found your hostname, welcome back<br />
NOTICE AUTH :*** Checking ident<br />
NOTICE AUTH :*** No identd (auth) response<br />
:orwell.freenode.net 001 tutbot :Welcome to the freenode IRC Network tutbot<br />
:orwell.freenode.net 002 tutbot :Your host is orwell.freenode.net<br />
...<br />
:tutbot!n=tutbot@aa.bb.cc.dd JOIN :#tutbot-testing<br />
:orwell.freenode.net MODE #tutbot-testing +ns<br />
:orwell.freenode.net 353 tutbot @ #tutbot-testing :@tutbot<br />
:orwell.freenode.net 366 tutbot #tutbot-testing :End of /NAMES list.<br />
</haskell><br />
<br />
And we're in business! From an IRC client, we can watch the bot connect:<br />
<br />
15:02 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:02 dons> hello<br />
<br />
And the bot logs to standard output:<br />
<br />
:dons!i=dons@my.net PRIVMSG #tutbot-testing :hello<br />
<br />
We can now implement some commands.<br />
<br />
== A simple interpreter ==<br />
<br />
Add these additional imports before changing the <hask>listen</hask> function.<br />
<br />
<haskell><br />
import Data.List<br />
import System.Exit<br />
</haskell><br />
<br />
<haskell><br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
t <- hGetLine h<br />
let s = init t<br />
if ping s then pong s else eval h (clean s)<br />
putStrLn s<br />
where<br />
forever a = a >> forever a<br />
<br />
clean = drop 1 . dropWhile (/= ':') . drop 1<br />
<br />
ping x = "PING :" `isPrefixOf` x<br />
pong x = write h "PONG" (':' : drop 6 x)<br />
</haskell><br />
<br />
We add 3 features to the bot here by modifying <hask>listen</hask>.<br />
Firstly, it responds to <hask>PING</hask> messages: <hask>if ping s then pong s ... </hask>.<br />
This is useful for servers that require pings to keep clients connected.<br />
Before we can process a command, remember the IRC protocol generates<br />
input lines of the form:<br />
<haskell><br />
:dons!i=dons@my.net PRIVMSG #tutbot-testing :!id foo<br />
</haskell><br />
so we need a <hask>clean</hask> function to simply drop the leading ':'<br />
character, and then everything up to the next ':', leaving just the<br />
actual command content. We then pass this cleaned up string to<br />
<hask>eval</hask>, which then dispatches bot commands.<br />
<br />
<haskell><br />
eval :: Handle -> String -> IO ()<br />
eval h "!quit" = write h "QUIT" ":Exiting" >> exitWith ExitSuccess<br />
eval h x | "!id " `isPrefixOf` x = privmsg h (drop 4 x)<br />
eval _ _ = return () -- ignore everything else<br />
</haskell><br />
<br />
So, if the single string "!quit" is received, we inform the server and exit the program. If a string beginning with "!id" appears, we echo any argument string back to the server (<hask>id</hask> is the Haskell identity function, which just returns its argument). Finally, if no other matches occur, we do nothing.<br />
<br />
We add the <hask>privmsg</hask> function - a useful wrapper over <hask>write</hask> for sending <hask>PRIVMSG</hask> lines to the server.<br />
<br />
<haskell><br />
privmsg :: Handle -> String -> IO ()<br />
privmsg h s = write h "PRIVMSG" (chan ++ " :" ++ s)<br />
</haskell><br />
<br />
Here's a transcript from our minimal bot running in channel:<br />
<br />
15:12 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:13 dons> !id hello, world!<br />
15:13 tutbot> hello, world!<br />
15:13 dons> !id very pleased to meet you.<br />
15:13 tutbot> very pleased to meet you.<br />
15:13 dons> !quit<br />
15:13 -- tutbot [n=tutbot@aa.bb.cc.dd] has quit [Client Quit]<br />
<br />
Now, before we go further, let's refactor the code a bit.<br />
<br />
== Roll your own monad ==<br />
<br />
A small annoyance so far has been that we've had to thread around our socket to every function that needs to talk to the network. The socket is essentially <em>immutable state</em>, that could be treated as a global read only value in other languages. In Haskell, we can implement such a structure using a state <em>monad</em>. Monads are a very powerful abstraction, and we'll only touch on them here. The interested reader is referred to [http://www.haskell.org/all_about_monads/html/index.html All About Monads]. We'll be using a custom monad specifically to implement a read-only global state for our bot.<br />
<br />
The key requirement is that we wish to be able to perform IO actions, as well as thread a small state value transparently through the program. As this is Haskell, we can take the extra step of partitioning our stateful code from all other program code, using a new type.<br />
<br />
So let's define a small state monad:<br />
<haskell><br />
data Bot = Bot { socket :: Handle }<br />
<br />
type Net = ReaderT Bot IO<br />
</haskell><br />
<br />
Firstly, we define a data type for the global state. In this case, it is the <hask>Bot</hask> type, a simple struct storing our network socket. We then layer this data type over our existing IO code, with a <em>monad transformer</em>. This isn't as scary as it sounds and the effect is that we can just treat the socket as a global read-only value anywhere we need it. We'll call this new io + state structure the <hask>Net</hask> monad. <hask>ReaderT</hask> is a <em>type constructor</em>, essentially a type function, that takes 2 types as arguments, building a result type: the <hask>Net</hask> monad type.<br />
<br />
We can now throw out all that socket threading and just grab the socket when we need it. The key steps are connecting to the server, followed by the initialisation of our new state monad and then to run the main bot loop with that state. We add a small function, which takes the intial bot state and evaluates the bot's <hask>run</hask> loop "in" the Net monad, using the Reader monad's <hask>runReaderT</hask> function:<br />
<br />
<haskell><br />
loop st = runReaderT run st<br />
</haskell><br />
<br />
where <hask>run</hask> is a small function to register the bot's nick, join a channel, and start listening for commands.<br />
<br />
While we're here, we can tidy up the main function a little by using <hask>Control.Exception.bracket</hask> to explicitly delimit the connection, shutdown and main loop phases of the program - a useful technique. We can also make the code a bit more robust by wrapping the main loop in an exception handler using <hask>catch</hask>:<br />
<br />
<haskell><br />
main :: IO ()<br />
main = bracket connect disconnect loop<br />
where<br />
disconnect = hClose . socket<br />
loop st = catch (runReaderT run st) (const $ return ())<br />
</haskell><br />
<br />
That is, the higher order function <hask>bracket</hask> takes 3 arguments: a function to connect to the server, a function to disconnect and a main loop to run in between. We can use <hask>bracket</hask> whenever we wish to run some code before and after a particular action - like <hask>forever</hask>, this is another control structure implemented as a normal Haskell function.<br />
<br />
Rather than threading the socket around, we can now simply ask for it when needed. Note that the type of <hask>write</hask> changes - it is in the Net monad, which tells us that the bot must already by connected to a server (and thus it is ok to use the socket, as it is initialised).<br />
<br />
<haskell><br />
--<br />
-- Send a message out to the server we're currently connected to<br />
--<br />
write :: String -> String -> Net ()<br />
write s t = do<br />
h <- asks socket<br />
io $ hPrintf h "%s %s\r\n" s t<br />
io $ printf "> %s %s\n" s t<br />
</haskell><br />
<br />
In order to use both state and IO, we use the small <hask>io</hask> function to <em>lift</em> an IO expression into the Net monad making that IO function available to code in the <hask>Net</hask> monad.<br />
<br />
<haskell><br />
io :: IO a -> Net a<br />
io = liftIO<br />
</haskell><br />
<br />
Similarly, we can combine IO actions with pure functions by lifting them into the IO monad. We can therefore simplify our <hask>hGetLine</hask> call:<br />
<haskell><br />
do t <- io (hGetLine h)<br />
let s = init t<br />
</haskell><br />
by lifting <hask>init</hask> over IO:<br />
<haskell><br />
do s <- init `fmap` io (hGetLine h)<br />
</haskell><br />
<br />
The monadic, stateful, exception-handling bot in all its glory:<br />
<br />
<haskell><br />
import Data.List<br />
import Network<br />
import System.IO<br />
import System.Exit<br />
import Control.Arrow<br />
import Control.Monad.Reader<br />
import Control.Exception -- *** for base-3<br />
-- import Control.OldException -- *** for base-4<br />
import Text.Printf<br />
import Prelude hiding (catch)<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
chan = "#tutbot-testing"<br />
nick = "tutbot"<br />
<br />
-- The 'Net' monad, a wrapper over IO, carrying the bot's immutable state.<br />
type Net = ReaderT Bot IO<br />
data Bot = Bot { socket :: Handle }<br />
<br />
-- Set up actions to run on start and end, and run the main loop<br />
main :: IO ()<br />
main = bracket connect disconnect loop<br />
where<br />
disconnect = hClose . socket<br />
loop st = catch (runReaderT run st) (const $ return ())<br />
-- catch (runReaderT run st) (\(SomeException _) -> return ()) -- *** Control.Exception with base-4<br />
<br />
-- Connect to the server and return the initial bot state<br />
connect :: IO Bot<br />
connect = notify $ do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
return (Bot h)<br />
where<br />
notify a = bracket_<br />
(printf "Connecting to %s ... " server >> hFlush stdout)<br />
(putStrLn "done.")<br />
a<br />
<br />
-- We're in the Net monad now, so we've connected successfully<br />
-- Join a channel, and start processing commands<br />
run :: Net ()<br />
run = do<br />
write "NICK" nick<br />
write "USER" (nick++" 0 * :tutorial bot")<br />
write "JOIN" chan<br />
asks socket >>= listen<br />
<br />
-- Process each line from the server<br />
listen :: Handle -> Net ()<br />
listen h = forever $ do<br />
s <- init `fmap` io (hGetLine h)<br />
io (putStrLn s)<br />
if ping s then pong s else eval (clean s)<br />
where<br />
forever a = a >> forever a<br />
clean = drop 1 . dropWhile (/= ':') . drop 1<br />
ping x = "PING :" `isPrefixOf` x<br />
pong x = write "PONG" (':' : drop 6 x)<br />
<br />
-- Dispatch a command<br />
eval :: String -> Net ()<br />
eval "!quit" = write "QUIT" ":Exiting" >> io (exitWith ExitSuccess)<br />
eval x | "!id " `isPrefixOf` x = privmsg (drop 4 x)<br />
eval _ = return () -- ignore everything else<br />
<br />
-- Send a privmsg to the current chan + server<br />
privmsg :: String -> Net ()<br />
privmsg s = write "PRIVMSG" (chan ++ " :" ++ s)<br />
<br />
-- Send a message out to the server we're currently connected to<br />
write :: String -> String -> Net ()<br />
write s t = do<br />
h <- asks socket<br />
io $ hPrintf h "%s %s\r\n" s t<br />
io $ printf "> %s %s\n" s t<br />
<br />
-- Convenience.<br />
io :: IO a -> Net a<br />
io = liftIO<br />
</haskell><br />
<br />
Note that we threw in a new control structure, <hask>notify</hask>, for fun. Now we're almost done! Let's run this bot. Using runhaskell:<br />
<br />
$ runhaskell 4.hs<br />
<br />
or using GHC:<br />
<br />
$ ghc --make 4.hs -o tutbot<br />
Chasing modules from: 4.hs<br />
Compiling Main ( 4.hs, 4.o )<br />
Linking ...<br />
$ ./tutbot<br />
<br />
If you're using Hugs, you'll have to use the <hask>-98</hask> flag:<br />
<br />
$ runhugs -98 4.hs<br />
<br />
And from an IRC client we can watch it connect:<br />
<br />
15:26 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:28 dons> !id all good?<br />
15:28 tutbot> all good?<br />
15:28 dons> !quit<br />
15:28 -- tutbot [n=tutbot@aa.bb.cc.dd] has quit [Client Quit]<br />
<br />
So we now have a bot with explicit read-only monadic state, error handling, and some basic IRC operations. If we wished to add read-write state, we need only change the <hask>ReaderT</hask> transformer to <hask>StateT</hask>.<br />
<br />
== Extending the bot ==<br />
<br />
Let's implement a basic new command: uptime tracking. Conceptually, we need to remember the time the bot starts. Then, if a user requests, we work out the total running time and print it as a string. A nice way to do this is to extend the bot's state with a start time field:<br />
<br />
<haskell><br />
import System.Time<br />
</haskell><br />
<br />
<haskell><br />
data Bot = Bot { socket :: Handle, starttime :: ClockTime }<br />
</haskell><br />
<br />
We can then modify the initial <hask>connect</hask> function to also set the start time.<br />
<br />
<haskell><br />
connect :: IO Bot<br />
connect = notify $ do<br />
t <- getClockTime<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
return (Bot h t)<br />
</haskell><br />
<br />
We then add a new case to the <hask>eval</hask> function, to handle uptime requests:<br />
<br />
<haskell><br />
eval "!uptime" = uptime >>= privmsg<br />
</haskell><br />
<br />
This will just run the <hask>uptime</hask> function and send it back to the server. <hask>uptime</hask> itself is:<br />
<br />
<haskell><br />
uptime :: Net String<br />
uptime = do<br />
now <- io getClockTime<br />
zero <- asks starttime<br />
return . pretty $ diffClockTimes now zero<br />
</haskell><br />
<br />
That is, in the Net monad, find the current time and the start time, and then calculate the difference, returning that number as a string. Rather than use the normal representation for dates, we'll write our own custom formatter for dates:<br />
<br />
<haskell><br />
--<br />
-- Pretty print the date in '1d 9h 9m 17s' format<br />
--<br />
pretty :: TimeDiff -> String<br />
pretty td =<br />
unwords $ map (uncurry (++) . first show) $<br />
if null diffs then [(0,"s")] else diffs<br />
where merge (tot,acc) (sec,typ) = let (sec',tot') = divMod tot sec<br />
in (tot',(sec',typ):acc)<br />
metrics = [(86400,"d"),(3600,"h"),(60,"m"),(1,"s")]<br />
diffs = filter ((/= 0) . fst) $ reverse $ snd $<br />
foldl' merge (tdSec td,[]) metrics<br />
</haskell><br />
<br />
And that's it. Running the bot with this new command:<br />
<br />
16:03 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
16:03 dons> !uptime<br />
16:03 tutbot> 51s<br />
16:03 dons> !uptime<br />
16:03 tutbot> 1m 1s<br />
16:12 dons> !uptime<br />
16:12 tutbot> 9m 46s<br />
<br />
== Where to now? ==<br />
<br />
This is just a flavour of application programming in Haskell, and only<br />
hints at the power of Haskell's lazy evaluation, static typing, monadic<br />
effects and higher order functions. There is much, much more to be said<br />
on these topics. Some places to start:<br />
<br />
* The [[/Source|complete bot source]] (also [http://www.cse.unsw.edu.au/~dons/irc/bot.html mirrored here])<br />
* A [[/Transcript|full transcript]].<br />
* [[Haskell|Haskell.org]]<br />
* [[Example_code|More Haskell code]]<br />
* [[Books and tutorials|Learning Haskell]]<br />
* A gallery of [[Libraries_and_tools/Network|network apps]] in Haskell<br />
<br />
Or take the bot home and hack! Some suggestions:<br />
* Use <hask>forkIO</hask> to add a command line interface, and you've got yourself an irc client with 4 more lines of code.<br />
* Port some commands from [[Lambdabot]].<br />
<br />
Author: [http://www.cse.unsw.edu.au/~dons Don Stewart]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Code]]</div>Aninhumerhttps://wiki.haskell.org/index.php?title=CamHac&diff=40252CamHac2011-05-31T13:09:39Z<p>Aninhumer: </p>
<hr />
<div>Haskell Hackaton in Cambridge, UK, '''August 12-14, 2011'''<br />
<br />
== About ==<br />
<br />
Come and spend a weekend in Cambridge hacking Haskell code in great surroundings with fantastic company! Haskell Hackathons are a tradition where everyone is welcome; we get together, work on projects with others or just do your own thing, the overall goal being to improve the Haskell ecosystem.<br />
<br />
CamHac will be held from 12-14 August 2011, at [http://www.homertonconference.com/ Homerton College] in Cambridge. As with previous Hackathons, all are welcome -- you do not have to be a Haskell guru. All you need is a basic knowledge of Haskell, a willingness to learn, and a project you're excited to help with (or a project of your own to work on).<br />
<br />
There will be lots of hacking, good food, and, of course, fun! <br />
<br />
* Organiser: [mailto:marlowsd@gmail.com Simon Marlow] (<tt>JaffaCake</tt> on IRC)<br />
* Mailing list: [http://www.haskell.org/mailman/listinfo/hackathon hackathon@haskell.org]<br />
* IRC channel: #ghc on FreeNode<br />
<br />
Many thanks to [http://research.microsoft.com/en-us/labs/cambridge/default.aspx Microsoft Research Cambridge] for agreeing to sponsor the event.<br />
<br />
== Registration ==<br />
<br />
'''Registration deadline''': Friday 15th July 2011<br />
<br />
Registration is free. To register, please email [mailto:msrcevnt@microsoft.com msrcevnt@microsoft.com] stating that you would like to register for the "Haskell Hackathon", with the following information<br />
<br />
Full name:<br />
Which days you are attending on:<br />
day 1: yes/no<br />
day 2: yes/no<br />
day 3: yes/no<br />
Dietary requirements:<br />
<br />
The venue is '''limited to 50 people''', and registration is first-come first-served, so register quickly to reserve your place! (but only register if you definitely intend to come, and please let us know if you find you cannot make it for any reason after you have registered, so we can re-allocate your place).<br />
<br />
Some people will probably want to travel on Friday morning and join us later on that day - that's absolutely fine.<br />
<br />
== Venue ==<br />
<br />
We're in the [http://www.homertonconference.com/Horobin.html Horobin Room] of [http://www.homertonconference.com/ Homerton Conference Centre]. It is about [http://www.google.co.uk/maps?f=d&source=s_d&saddr=United+Kingdom+(Cambridge,+Railway+Station+(Stop+B))&daddr=CB2+8PH&hl=en&geocode=FehrHAMdjhUCACHpLU_p7S-CNg%3BFc5LHAMdNhMCACmn-uB8eXrYRzFlrDhff7fJ9A&mra=iwd&dirflg=w&sll=52.190667,0.134583&sspn=0.021547,0.040598&ie=UTF8&z=16 15 minutes walk from the train station], and Cambridge town centre is about 30 minutes walk.<br />
<br />
'''Times''': we have the room booked all day for the three days, and we'll probably start around 10am and finish around 6pm. Exact time details to be confirmed later. <br />
<br />
There will be WiFi access.<br />
<br />
There will be a projector for giving talks/demos. We will probably reserve a part of the time for talks and demos.<br />
<br />
== Food ==<br />
<br />
Tea and coffee will be supplied. We will have to go out to find lunch, but there are various places to eat and buy food at the [http://www.cambridge-x.co.uk Cambridge Leisure Park] a few minutes walk towards Cambridge town centre. In the evening we will probably head towards the town where there are plenty of good restaurants.<br />
<br />
== Local arrangements ==<br />
<br />
=== Getting to Cambridge ===<br />
<br />
==== By Plane ====<br />
<br />
* [http://www.stanstedairport.com/ Stansted Airport]: Stansted is the nearest of the London-area airports to Cambridge. It is mostly served by flights to and from mainland Europe, Ireland, and elsewhere in the UK. <br />
<br />
* [http://www.heathrowairport.com/ Heathrow Airport]: Heathrow is the principal London-area airport and one of the busiest in Europe with a wide range of national, European, and international services. <br />
<br />
* [http://www.gatwickairport.com/ Gatwick Airport]: Gatwick is the second "London" airport with a wide range of national, European and international services. <br />
<br />
* Other airports: [http://www.london-luton.co.uk/ Luton Airport], [http://www.norwichairport.co.uk/ Norwich airport], and [http://www.southendairport.com/ Southend airport] are other regional airports in the East Anglia region. If you use these, car or taxi is the best option for travel to Cambridge. <br />
<br />
==== Trains from London ====<br />
<br />
London has two train lines into Cambridge, London Kings Cross and London Liverpool Street. There is a regular service on both lines and duration is under an hour on the direct trains. Go to [http://www.nationalrail.co.uk National Rail] to check train times<br />
<br />
=== Getting to the venue ===<br />
<br />
[http://www.google.co.uk/maps?f=d&source=s_d&saddr=United+Kingdom+(Cambridge,+Railway+Station+(Stop+B))&daddr=CB2+8PH&hl=en&geocode=FehrHAMdjhUCACHpLU_p7S-CNg%3BFc5LHAMdNhMCACmn-uB8eXrYRzFlrDhff7fJ9A&mra=iwd&dirflg=w&sll=52.190667,0.134583&sspn=0.021547,0.040598&ie=UTF8&z=16 Walk from the train station] (about 15 minutes)<br />
<br />
[http://www.homertonconference.com/How-to-find-us.html How to find the venue]<br />
<br />
'''Local Taxis''': Panther Taxis 01223 715715<br />
<br />
=== Accommodation ===<br />
<br />
[http://www.visitcambridge.org/VisitCambridge/WhereToStay.aspx VisitCambridge: Where to Stay in Cambridge]<br />
<br />
The nearest hotels to the venue seem to be:<br />
<br />
* [http://www2.travelodge.co.uk/ Travelodge] (Cambridge Central) is just a few minutes walk from the venue. It is currently charging £65.80 per night for 11-14 August.<br />
* [http://www.helenhotel.co.uk/index.htm Helen Hotel]<br />
* [http://www.bandbincambridgeshire.co.uk/ Bridge Guest House]<br />
* [http://www.cheapguesthouses.com/ Fairways Guest House]<br />
* [http://www.abbeyfieldguesthouse.com/ Abbeyfield Guest House]<br />
* [http://rockviewguesthouse.co.uk/default.aspx Rock View Guest House]<br />
* [http://alingtonhouse.com/default.aspx Alington House Guest House]<br />
* [http://www.yha.org.uk/find-accommodation/east-of-england/hostels/cambridge/index.aspx Cambridge Youth Hostel]<br />
<br />
If you contact any of the above and find they're booked up, please remove them from the list.<br />
<br />
Microsoft Research recommends the following hotels to visitors, these are closer to the city centre but are probably a lot more expensive than those above:<br />
<br />
* [http://www.hilton.co.uk/cambridgegardenhouse Double Tree by Hilton Garden House Cambridge]<br />
* [http://www.ichotelsgroup.com/h/d/cp/1/en/hotel/cbguk Crowne Plaza Cambridge]<br />
* [http://www.devere.co.uk/our-locations/university-arms.html De Vere University Arms]<br />
<br />
== Projects ==<br />
<br />
Use this space to list projects you are interested in working on, and add your name to projects you are interested in helping with.<br />
<br />
* General hacking away at Snap Framework (exact goals TBD), perhaps adding/improving documentation/tutorials at the same time. (Jurriën Stutterheim)<br />
* Darcs<br />
* Something games/3d related? (Stephen L)<br />
<br />
== Attendees ==<br />
<br />
# Simon Marlow<br />
# Jurriën Stutterheim<br />
# Neil Mitchell<br />
# Jasper Van der Jeugt<br />
# Max Bolingbroke<br />
# Ben Millwood<br />
# Roman Leshchinskiy<br />
# Gregory Collins<br />
# Martijn van Steenbergen<br />
# Sjoerd Visscher<br />
# Sebastiaan Visser<br />
# Tom Lokhorst<br />
# Erik Hesselink<br />
# Jeff Foster<br />
# Sebastian Korten<br />
# Alessandro Vermeulen<br />
# Vlad Hanciuta<br />
# Ganesh Sittampalam<br />
# Eric Kow<br />
# Alexander Njemz<br />
# Mikolaj Konarski<br />
# Ian Lynagh<br />
# Andres Löh<br />
# Jeroen Janssen<br />
# Nicolas Wu<br />
# Duncan Coutts<br />
# Dominic Orchard<br />
# Jacek Generowicz<br />
# Owen Stephens<br />
# Benedict Eastaugh<br />
# Stephen Lavelle<br />
# Sam Martin<br />
# Alex Horsman<br />
* Add your name here, once registered...</div>Aninhumer