https://wiki.haskell.org/api.php?action=feedcontributions&user=Tanimoto&feedformat=atomHaskellWiki - User contributions [en]2016-08-29T19:58:30ZUser contributionsMediaWiki 1.19.14+dfsg-1https://wiki.haskell.org/Numeric_Haskell:_A_Repa_TutorialNumeric Haskell: A Repa Tutorial2011-05-18T00:14:20Z<p>Tanimoto: Typos in /* Example: parallel image desaturation */</p>
<hr />
<div>[http://hackage.haskell.org/package/repa Repa] is a Haskell library for<br />
high performance, regular, multi-dimensional parallel arrays. All<br />
numeric data is stored unboxed and functions written with the Repa<br />
combinators are automatically parallel (provided you supply "+RTS -N" on<br />
the command line when running the program).<br />
<br />
[[Image:Grid.png|right]]<br />
<br />
This document provides a tutorial on array programming in Haskell using the repa package.<br />
<br />
''Note: a companion tutorial to this is provided as the [http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Vector_Tutorial vector tutorial], and is based on the [http://www.scipy.org/Tentative_NumPy_Tutorial NumPy tutorial]''.<br />
<br />
''Authors: [http://donsbot.wordpress.com Don Stewart].''<br />
<br />
= Quick Tour =<br />
<br />
Repa (REgular PArallel arrays) is an advanced, multi-dimensional parallel arrays library for Haskell, with a number of distinct capabilities:<br />
<br />
* The arrays are "regular" (i.e. dense, rectangular and store elements all of the same type); and<br />
* Functions may be written that are polymorphic in the shape of the array;<br />
* Many operations on arrays are accomplished by changing only the shape of the array (without copying elements);<br />
* The library will automatically parallelize operations over arrays.<br />
<br />
This is a quick start guide for the package. For further information, consult:<br />
<br />
* [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa.html The Haddock Documentation]<br />
* [http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/rarrays.pdf Regular, Shape-polymorphic, Parallel Arrays in Haskell].<br />
* [http://www.cse.unsw.edu.au/~benl/papers/stencil/stencil-icfp2011-sub.pdf Efﬁcient Parallel Stencil Convolution in Haskell]<br />
<br />
== Importing the library ==<br />
<br />
Download the `repa` package:<br />
<br />
$ cabal install repa<br />
<br />
and import it qualified:<br />
<br />
import qualified Data.Array.Repa as R<br />
<br />
The library needs to be imported qualified as it shares the same function names as list operations in the Prelude.<br />
<br />
''Note: Operations that involve writing new index types for Repa arrays will require the '-XTypeOperators' language extension.''<br />
<br />
For non-core functionality, a number of related packages are available:<br />
<br />
* [http://hackage.haskell.org/package/repa-bytestring repa-bytestring]<br />
* [http://hackage.haskell.org/package/repa-io repa-io]<br />
* [http://hackage.haskell.org/package/repa-algorithms repa-algorithms]<br />
* [http://hackage.haskell.org/package/repa-devil repa-devil] (image loading)<br />
<br />
and example algorithms in:<br />
<br />
* [http://hackage.haskell.org/package/repa-examples repa-examples]<br />
<br />
== Index types and shapes ==<br />
<br />
Before we can get started manipulating arrays, we need a grasp of repa's notion of array shape. Much like the classic 'array' library in Haskell, repa-based arrays are parameterized via a type which determines the dimension of the array, and the type of its index. However, while classic arrays take tuples to represent multiple dimensions, Repa arrays use a [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa-Shape.html#t:Shape richer type language] for describing multi-dimensional array indices and shapes (technically, a ''heterogeneous snoc list'').<br />
<br />
Shape types are built somewhat like lists. The constructor '''Z''' corresponds<br />
to a rank zero shape, and is used to mark the end of the list. The ''':.''' constructor adds additional dimensions to the shape. So, for example, the shape:<br />
<br />
(Z:.3 :.2 :.3)<br />
<br />
is the shape of a small 3D array, with shape type<br />
<br />
(Z:.Int:.Int:.Int)<br />
<br />
The most common dimensions are given by the shorthand names:<br />
<br />
<haskell><br />
type DIM0 = Z<br />
type DIM1 = DIM0 :. Int<br />
type DIM2 = DIM1 :. Int<br />
type DIM3 = DIM2 :. Int<br />
type DIM4 = DIM3 :. Int<br />
type DIM5 = DIM4 :. Int<br />
</haskell><br />
<br />
thus,<br />
<br />
<haskell><br />
Array DIM2 Double<br />
</haskell><br />
<br />
is the type of a two-dimensional array of doubles, indexed via `Int` keys, while<br />
<br />
<haskell><br />
Array Z Double<br />
</haskell><br />
<br />
is a zero-dimension object (i.e. a point) holding a Double.<br />
<br />
Many operations over arrays are polymorphic in the shape / dimension<br />
component. Others require operating on the shape itself, rather than<br />
the array. A typeclass, <code>Shape</code>, lets us operate uniformly<br />
over arrays with different shape.<br />
<br />
=== Building shapes ===<br />
<br />
To build values of `shape` type, we can use the <code>Z</code> and <code>:.</code> constructors. Open the ghci and import Repa:<br />
<br />
<haskell><br />
Prelude> :m +Data.Array.Repa<br />
Repa> Z -- the zero-dimension<br />
Z<br />
</haskell><br />
<br />
For arrays of non-zero dimension, we must give a size. ''Note:'' a common error is to leave off the type of the size.<br />
<br />
<haskell><br />
Repa> :t Z :. 10<br />
Z :. 10 :: Num head => Z :. head<br />
</haskell><br />
<br />
leading to annoying type errors about unresolved instances, such as:<br />
<br />
No instance for (Shape (Z :. head0))<br />
<br />
To select the correct instance, you will need to annotate the size literals with their concrete type:<br />
<br />
<haskell><br />
Repa> :t Z :. (10 :: Int)<br />
Z :. (10 :: Int) :: Z :. Int<br />
</haskell><br />
<br />
is the shape of 1D arrays of length 10, indexed via Ints.<br />
<br />
Given an array, you can always find its shape by calling <code>extent</code>.<br />
<br />
Additional convenience types for selecting particular parts of a shape are also provided (<code>All, Any, Slice</code> etc.) which are covered later in the tutorial.<br />
<br />
=== Working with shapes ===<br />
<br />
That one key operation, '''extent''', gives us many attributes of an array:<br />
<br />
<haskell><br />
-- Extract the shape of the array<br />
extent :: Array sh a -> sh<br />
</haskell><br />
<br />
So, given a 3x3x3 array, of type '''Array DIM3 Int''', we can:<br />
<br />
<haskell><br />
-- build an array<br />
Repa> let x :: Array DIM3 Int; x = fromList (Z :. (3::Int) :. (3::Int) :. (3::Int)) [1..27]<br />
Repa> :t x<br />
x :: Array DIM3 Int<br />
<br />
-- query the extent<br />
Repa> extent x<br />
((Z :. 3) :. 3) :. 3<br />
<br />
-- compute the rank (number of dimensions)<br />
Repa> let sh = extent x<br />
Repa> rank sh<br />
3<br />
<br />
-- compute the size (total number of elements)<br />
> size sh<br />
27<br />
<br />
-- extract the elements of the array as a flat vector<br />
Repa> toVector x<br />
fromList [1,2,3,4,5,6,7,8,9,10<br />
,11,12,13,14,15,16,17,18,19<br />
,20,21,22,23,24,25,26,27] :: Data.Vector.Unboxed.Vector<br />
</haskell><br />
<br />
== Generating arrays ==<br />
<br />
New repa arrays ("arrays" from here on) can be generated in many ways, and we always begin by importing the <code>Data.Array.Repa</code> module:<br />
<br />
<br />
$ ghci<br />
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help<br />
Loading package ghc-prim ... linking ... done.<br />
Loading package integer-gmp ... linking ... done.<br />
Loading package base ... linking ... done.<br />
Loading package ffi-1.0 ... linking ... done.<br />
Prelude> :m + Data.Array.Repa<br />
<br />
<br />
They may be constructed from lists, for example. Here is a one dimensional array of length 10, here, given the shape `(Z :. 10)`:<br />
<br />
<haskell><br />
Repa> let inputs = [1..10] :: [Double]<br />
Repa> let x = fromList (Z :. (10::Int)) inputs<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
The type of `x` is inferred as:<br />
<br />
<haskell><br />
Repa> :t x<br />
x :: Array (Z :. Int) Double<br />
</haskell><br />
<br />
which we can read as "an array of dimension 1, indexed via Int keys, holding elements of type Double"<br />
<br />
We could also have written the type as:<br />
<br />
<haskell><br />
Repa> let x' = fromList (Z :. 10 :: DIM1) inputs<br />
Repa> :t x'<br />
x' :: Array DIM1 Double<br />
</haskell><br />
<br />
The same data may also be treated as a two dimensional array, by changing the shape parameter:<br />
<br />
<haskell><br />
Repa> let x2 = fromList (Z :. (5::Int) :. (2::Int)) inputs<br />
Repa> x2<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
which has the type:<br />
<br />
<haskell><br />
Repa> :t x2<br />
x2 :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
or, as above, if we define it with the type synonym for 2 dimensional Int- indexed arrays, DIM2:<br />
<br />
<haskell><br />
Repa> let x2' = fromList (Z :. 5 :. 2 :: DIM2) inputs<br />
Repa> x2'<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa> :t x2'<br />
x2' :: Array DIM2 Double<br />
</haskell><br />
<br />
=== Building arrays from vectors ===<br />
<br />
It is also possible to build arrays from unboxed vectors, from the 'vector' package:<br />
<br />
<haskell><br />
fromVector :: Shape sh => sh -> Vector a -> Array sh a<br />
</haskell><br />
<br />
New arrays are built by applying a shape to the vector. For example:<br />
<br />
<haskell><br />
Repa> import Data.Vector.Unboxed --recent ghci's support this import syntax<br />
Repa Unboxed> let x = fromVector (Z :. (10::Int)) (enumFromN 0 10)<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
</haskell><br />
<br />
is a one-dimensional array of doubles. As usual, we can also impose other<br />
shapes:<br />
<br />
<haskell><br />
Repa Unboxed> let x = fromVector (Z :. (3::Int) :. (3::Int)) (enumFromN 0 9)<br />
Repa Unboxed> x<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]<br />
Repa Unboxed> :t x<br />
x :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
to create a 3x3 array.<br />
<br />
=== Generating random arrays ===<br />
<br />
The [http://hackage.haskell.org/package/repa-algorithsm repa-algorithms] package lets us generate new arrays with random data:<br />
<br />
<haskell><br />
-- 3d array of Ints, bounded between 0 and 255.<br />
> randomishIntArray (Z :. (3::Int) :. (3::Int) :. (3::Int)) 0 255 1<br />
[217,42,130,200,216,254<br />
,67,77,152,85,140,226,179<br />
,71,23,17,152,84,47,17,45<br />
,5,88,245,107,214,136]<br />
</haskell><br />
<br />
=== Reading arrays from files ===<br />
<br />
Using the [http://hackage.haskell.org/package/repa-io repa-io] package, arrays may be written and read from files in a number of formats:<br />
<br />
* as BMP files; and<br />
* in a number of text formats.<br />
<br />
with other formats rapidly appearing. For the special case of arrays of Word8 values, the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] library supports generating bytestrings in memory.<br />
<br />
An example: to write an 2D array to an ascii file:<br />
<br />
<haskell><br />
Repa> :m +Data.Array.Repa.IO.Matrix<br />
Repa Matrix> let x = fromList (Z :. 5 :. 2 :: DIM2) [1..10]<br />
Repa Matrix> writeMatrixToTextFile "test.dat" x<br />
</haskell><br />
<br />
This will result in a file containing:<br />
<br />
MATRIX<br />
2 5<br />
1.0<br />
2.0<br />
3.0<br />
4.0<br />
5.0<br />
6.0<br />
7.0<br />
8.0<br />
9.0<br />
10.0<br />
<br />
In turn, this file may be read back in via <code>readMatrixFromTextFile</code>.<br />
<br />
<haskell><br />
Repa Matrix> xx <- readMatrixFromTextFile "test.dat" <br />
Repa Matrix> xx<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa Matrix> :t xx<br />
it :: Array DIM2 Double<br />
</haskell><br />
<br />
<br />
To process [http://en.wikipedia.org/wiki/BMP_file_format .bmp files], use [http://hackage.haskell.org/packages/archive/repa-io/2.0.0.3/doc/html/Data-Array-Repa-IO-BMP.html Data.Array.Repa.IO.BMP], as follows (currently reading only works for 24 bit .bmp):<br />
<br />
<haskell><br />
Data.Array.Repa.IO.BMP> x <- readImageFromBMP "/tmp/test24.bmp"<br />
</haskell><br />
<br />
Reads this .bmp image:<br />
<br />
http://i.imgur.com/T4ttx.png<br />
<br />
as a 3D array of Word8, which can be further processed.<br />
<br />
''Note: at the time of writing, there are no binary instances for repa arrays''<br />
<br />
For image IO in many, many formats, use the [http://hackage.haskell.org/package/repa-devil repa-devil] library.<br />
<br />
=== Copying arrays from pointers ===<br />
<br />
You can also generate new repa arrays by copying data from a pointer, using the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] package. Here is an example, using "copyFromPtrWord8":<br />
<br />
<haskell><br />
import Data.Word<br />
import Foreign.Ptr<br />
<br />
import qualified Data.Vector.Storable as V<br />
import qualified Data.Array.Repa as R<br />
import Data.Array.Repa<br />
import qualified Data.Array.Repa.ByteString as R<br />
<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
i, j, k :: Int <br />
(i, j, k) = (255, 255, 4 {-RGBA-})<br />
<br />
-- 1d vector, filled with pretty colors<br />
v :: V.Vector Word8<br />
v = V.fromList . take (i * j * k) . cycle $ concat<br />
[ [ r, g, b, 255 ]<br />
| r <- [0 .. 255]<br />
, g <- [0 .. 255]<br />
, b <- [0 .. 255]<br />
] <br />
<br />
ptr2repa :: Ptr Word8 -> IO (R.Array R.DIM3 Word8)<br />
ptr2repa p = R.copyFromPtrWord8 (Z :. i :. j :. k) p<br />
<br />
main = do<br />
-- copy our 1d vector to a repa 3d array, via a pointer<br />
r <- V.unsafeWith v ptr2repa<br />
runIL $ writeImage "test.png" r <br />
return ()<br />
</haskell><br />
<br />
This fills a vector, converts it to a pointer, then copies that pointer to a 3d array, before writing the result out as this image:<br />
<br />
http://i.imgur.com/o0Cv2.png<br />
<br />
== Indexing arrays ==<br />
<br />
To access elements in repa arrays, you provide an array and a shape, to access the element:<br />
<br />
<haskell><br />
(!) :: (Shape sh, Elt a) => Array sh a -> sh -> a<br />
</haskell><br />
<br />
So:<br />
<br />
<haskell><br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x ! (Z :. 2)<br />
3.0<br />
</haskell><br />
<br />
Note that we can't give just a bare literal as the shape, even for one-dimensional arrays, :<br />
<br />
<haskell><br />
> x ! 2<br />
<br />
No instance for (Num (Z :. Int))<br />
arising from the literal `2'<br />
</haskell><br />
<br />
as the Z type isn't in the Num class, and Haskell's numeric literals are overloaded.<br />
<br />
What if the index is out of bounds, though?<br />
<br />
<haskell><br />
> x ! (Z :. 11)<br />
*** Exception: ./Data/Vector/Generic.hs:222 ((!)): index out of bounds (11,10)<br />
</haskell><br />
<br />
an exception is thrown. An alternative is to use indexing functions that return a Maybe:<br />
<br />
<haskell><br />
(!?) :: (Shape sh, Elt a) => Array sh a -> sh -> Maybe a<br />
</haskell><br />
<br />
An example:<br />
<br />
<haskell><br />
> x !? (Z :. 9)<br />
Just 10.0<br />
<br />
> x !? (Z :. 11)<br />
Nothing<br />
</haskell><br />
<br />
== Operations on arrays ==<br />
<br />
Besides indexing, there are many regular, list-like operations on arrays. Since many of the names parallel those in the Prelude, we import Repa qualified:<br />
<br />
Repa> import qualified Data.Array.Repa as Repa<br />
<br />
=== Maps, zips, filters and folds ===<br />
<br />
We can map over multi-dimensional arrays:<br />
<br />
Repa> let x = fromList (Z :. (3::Int) :. (3::Int)) [1..9]<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
<br />
since `map` conflicts with the definition in the Prelude, we have to use it qualified as we requested:<br />
<br />
Repa> Repa.map (^2) x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
<br />
Maps leave the dimension unchanged.<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
Repa> extent (Repa.map (^2) x)<br />
(Z :. 3) :. 3<br />
<br />
Folding reduces the inner dimension of the array.<br />
<br />
fold :: (Shape sh, Elt a) <br />
=> (a -> a -> a) -> a -> Array (sh :. Int) a -> Array sh a<br />
<br />
The 'x' defined above is a 2D array:<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
<br />
If we sum each row:<br />
<br />
Repa> Repa.fold (+) 0 x<br />
[6.0,15.0,24.0]<br />
<br />
we get a 1D array instead:<br />
<br />
Repa> extent (Repa.fold (+) 0 x)<br />
Z :. 3<br />
<br />
Similarly, if 'y' is a (3 x 3 x 3) 3D array:<br />
<br />
Repa> let y = fromList ((Z :. 3 :. 3 :. 3) :: DIM3) [1..27]<br />
Repa> y<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0]<br />
<br />
we can fold over the inner dimension: <br />
<br />
Repa> Repa.fold (+) 0 y<br />
[6.0,15.0,24.0,33.0,42.0,51.0,60.0,69.0,78.0]<br />
<br />
yielding a 2D (3 x 3) array in place of our 3D (3 x 3 x 3) array<br />
Repa> extent y<br />
((Z :. 3) :. 3) :. 3<br />
Repa> extent (Repa.fold (+) 0 y)<br />
(Z :. 3) :. 3<br />
<br />
Two arrays may be combined via <code>zipWith</code>:<br />
<br />
zipWith :: (Shape sh, Elt b, Elt c, Elt a) =><br />
(a -> b -> c) -> Array sh a -> Array sh b -> Array sh c<br />
<br />
an example:<br />
<br />
Repa> Repa.zipWith (*) x x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
Repa> extent it<br />
(Z :. 3) :. 3<br />
<br />
Repa> Repa.zipWith (*) y y <br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,<br />
100.0,121.0,144.0,169.0,196.0,225.0,256.0,289.0,324.0,<br />
361.0,400.0,441.0,484.0,529.0,576.0,625.0,676.0,729.0] --reformatted<br />
Repa> extent it<br />
((Z :. 3) :. 3) :. 3<br />
<br />
=== Numeric operations: negation, addition, subtraction, multiplication ===<br />
<br />
Repa arrays are instances of the <code>Num</code>. This means that<br />
operations on numerical elements are lifted automagically onto arrays of<br />
such elements. For example, <code>(+)</code> on two double values corresponds to<br />
element-wise addition, <code>(+)</code>, of the two arrays of doubles:<br />
<br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x + x<br />
[2.0,4.0,6.0,8.0,10.0,12.0,14.0,16.0,18.0,20.0]<br />
<br />
Other operations from the Num class work just as well:<br />
<br />
> -x<br />
[-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0,-8.0,-9.0,-10.0]<br />
<br />
> x ^ 3<br />
[1.0,8.0,27.0,64.0,125.0,216.0,343.0,512.0,729.0,1000.0]<br />
<br />
> x * x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,100.0]<br />
<br />
== Changing the shape of an array ==<br />
<br />
One of the main advantages of repa-style arrays over other arrays in<br />
Haskell is the ability to reshape data without copying. This is achieved<br />
via *index-space transformations*. <br />
<br />
An example: transposing a 2D array (this example taken from the repa<br />
paper). First, the type of the transformation:<br />
<br />
transpose2D :: Elt e => Array DIM2 e -> Array DIM2 e <br />
<br />
Note that this transform will work on DIM2 arrays holding any elements.<br />
Now, to swap rows and columns, we have to modify the shape:<br />
<br />
transpose2D a = backpermute (swap e) swap a<br />
where<br />
e = extent a<br />
swap (Z :. i :. j) = Z :. j :. i<br />
<br />
The swap function reorders the index space of the array.<br />
To do this, we extract the current shape of the array, and write a function<br />
that maps the index space from the old array to the new array. That index space function<br />
is then passed to backpermute which actually constructs the new<br />
array from the old one.<br />
<br />
backpermute generates a new array from an old, when given the new shape, and a<br />
function that translates between the index space of each array (i.e. a shape<br />
transformer).<br />
<br />
backpermute<br />
:: (Shape sh, Shape sh', Elt a) <br />
=> sh' <br />
-> (sh' -> sh) <br />
-> Array sh a <br />
-> Array sh' a<br />
<br />
Note that the array created is not actually evaluated (we only modified the index space of the array).<br />
<br />
Transposition is such a common operation that it is provided by the<br />
library:<br />
<br />
transpose :: (Shape sh, Elt a)<br />
=> Array ((sh :. Int) :. Int) a -> Array ((sh :. Int) :. Int)<br />
<br />
the type indicate that it works on the lowest two dimensions of the<br />
array.<br />
<br />
Other operations on index spaces include taking slices and joining<br />
arrays into larger ones.<br />
<br />
== Examples ==<br />
<br />
Following are some examples of useful functions that exercise the API.<br />
<br />
=== Example: Rotating an image with backpermute ===<br />
<br />
Flip an image upside down:<br />
<br />
<haskell><br />
import System.Environment<br />
import Data.Word<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
main = do<br />
[f] <- getArgs<br />
runIL $ do<br />
v <- readImage f<br />
writeImage ("flip-"++f) (rot180 v)<br />
<br />
rot180 :: Array DIM3 Word8 -> Array DIM3 Word8<br />
rot180 g = backpermute e flop g<br />
where<br />
e@(Z :. x :. y :. _) = extent g<br />
<br />
flop (Z :. i :. j :. k) =<br />
(Z :. x - i - 1 :. y - j - 1 :. k)<br />
</haskell><br />
<br />
Running this:<br />
<br />
$ ghc -O2 --make A.hs<br />
$ ./A haskell.jpg <br />
<br />
Results in:<br />
<br />
http://i.imgur.com/YsGA8.jpg<br />
<br />
=== Example: matrix-matrix multiplication ===<br />
<br />
A more advanced example from the Repa paper: matrix-matrix multiplication: the result of<br />
matrix multiplication is a matrix whose elements are found by<br />
multiplying the elements of each row from the first matrix by the<br />
associated elements of the same column from the second matrix and<br />
summing the result.<br />
<br />
if <math>A=\begin{bmatrix}a&b\\c&d\end{bmatrix}</math> and <math>B=\begin{bmatrix}e&f\\g&h\end{bmatrix}</math><br />
<br />
then <br />
<br />
<math>AB=\begin{bmatrix}a&b\\c&d\end{bmatrix}\begin{bmatrix}e&f\\g&h\end{bmatrix}=\begin{bmatrix}ae+bg&af+bh\\ce+dg&cf+dh\end{bmatrix}</math><br />
<br />
So we take two, 2D arrays and generate a new array, using our transpose<br />
function from earlier:<br />
<br />
<haskell><br />
mmMult :: (Num e, Elt e)<br />
=> Array DIM2 e<br />
-> Array DIM2 e<br />
-> Array DIM2 e<br />
<br />
mmMult a b = sum (zipWith (*) aRepl bRepl)<br />
where<br />
t = transpose2D b<br />
aRepl = extend (Z :.All :.colsB :.All) a<br />
bRepl = extend (Z :.rowsA :.All :.All) t<br />
(Z :.colsA :.rowsA) = extent a<br />
(Z :.colsB :.rowsB) = extent b<br />
</haskell><br />
<br />
The idea is to expand both 2D argument arrays into 3D arrays by<br />
replicating them across a new axis. The front face of the cuboid that<br />
results represents the array <code>a</code>, which we replicate as often<br />
as <code>b</code> has columns <code>(colsB)</code>, producing<br />
<code>aRepl</code>.<br />
<br />
The top face represents <code>t</code> (the transposed b), which we<br />
replicate as often as a has rows <code>(rowsA)</code>, producing<br />
<code>bRepl,</code>. The two replicated arrays have the same extent,<br />
which corresponds to the index space of matrix multiplication<br />
<br />
Optimized implementations of this function are available in the<br />
repa-algorithms package.<br />
<br />
=== Example: parallel image desaturation ===<br />
<br />
To convert an image from color to greyscale, we can use the luminosity method to average RGB pixels into a common grey value, where the average is weighted for human perception of green.<br />
<br />
The formula for luminosity is 0.21 R + 0.71 G + 0.07 B.<br />
<br />
We can write a parallel image desaturation tool using repa and the [http://hackage.haskell.org/package/repa-devil repa-devil image library]:<br />
<br />
<haskell><br />
import Data.Array.Repa.IO.DevIL<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Word<br />
import System.Environment<br />
<br />
--<br />
-- Read an image, desaturate, write out with new name.<br />
--<br />
main = do <br />
[f] <- getArgs<br />
runIL $ do<br />
a <- readImage f<br />
let b = traverse a id luminosity <br />
writeImage ("grey-" ++ f) b<br />
</haskell><br />
<br />
And now the luminosity transform itself, which averages the 3 RGB colors based on perceived weight:<br />
<br />
<haskell><br />
--<br />
-- (Parallel) desaturation of an image via the luminosity method.<br />
--<br />
luminosity :: (DIM3 -> Word8) -> DIM3 -> Word8<br />
luminosity _ (Z :. _ :. _ :. 3) = 255 -- alpha channel<br />
luminosity f (Z :. i :. j :. _) = ceiling $ 0.21 * r + 0.71 * g + 0.07 * b<br />
where<br />
r = fromIntegral $ f (Z :. i :. j :. 0)<br />
g = fromIntegral $ f (Z :. i :. j :. 1)<br />
b = fromIntegral $ f (Z :. i :. j :. 2)<br />
</haskell><br />
<br />
And that's it! The result is a parallel image desaturator, when compiled with <br />
<br />
$ ghc -O -threaded -rtsopts --make A.hs -fforce-recomp<br />
<br />
which we can run, to use two cores:<br />
<br />
$ time ./A sunflower.png +RTS -N2 -H <br />
./A sunflower.png +RTS -N2 -H 0.19s user 0.03s system 135% cpu 0.165 total<br />
<br />
Given an image like this:<br />
<br />
http://i.imgur.com/iu4gV.png<br />
<br />
The desaturated result from Haskell:<br />
<br />
http://i.imgur.com/REhA5.png<br />
<br />
[[Category:Libraries]]<br />
[[Category:Packages]]<br />
[[Category:Performance]]<br />
[[Category:Tutorials]]<br />
[[Category:Parallel]]</div>Tanimotohttps://wiki.haskell.org/Numeric_Haskell:_A_Repa_TutorialNumeric Haskell: A Repa Tutorial2011-05-18T00:08:55Z<p>Tanimoto: Typo in /* Indexing arrays */</p>
<hr />
<div>[http://hackage.haskell.org/package/repa Repa] is a Haskell library for<br />
high performance, regular, multi-dimensional parallel arrays. All<br />
numeric data is stored unboxed and functions written with the Repa<br />
combinators are automatically parallel (provided you supply "+RTS -N" on<br />
the command line when running the program).<br />
<br />
[[Image:Grid.png|right]]<br />
<br />
This document provides a tutorial on array programming in Haskell using the repa package.<br />
<br />
''Note: a companion tutorial to this is provided as the [http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Vector_Tutorial vector tutorial], and is based on the [http://www.scipy.org/Tentative_NumPy_Tutorial NumPy tutorial]''.<br />
<br />
''Authors: [http://donsbot.wordpress.com Don Stewart].''<br />
<br />
= Quick Tour =<br />
<br />
Repa (REgular PArallel arrays) is an advanced, multi-dimensional parallel arrays library for Haskell, with a number of distinct capabilities:<br />
<br />
* The arrays are "regular" (i.e. dense, rectangular and store elements all of the same type); and<br />
* Functions may be written that are polymorphic in the shape of the array;<br />
* Many operations on arrays are accomplished by changing only the shape of the array (without copying elements);<br />
* The library will automatically parallelize operations over arrays.<br />
<br />
This is a quick start guide for the package. For further information, consult:<br />
<br />
* [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa.html The Haddock Documentation]<br />
* [http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/rarrays.pdf Regular, Shape-polymorphic, Parallel Arrays in Haskell].<br />
* [http://www.cse.unsw.edu.au/~benl/papers/stencil/stencil-icfp2011-sub.pdf Efﬁcient Parallel Stencil Convolution in Haskell]<br />
<br />
== Importing the library ==<br />
<br />
Download the `repa` package:<br />
<br />
$ cabal install repa<br />
<br />
and import it qualified:<br />
<br />
import qualified Data.Array.Repa as R<br />
<br />
The library needs to be imported qualified as it shares the same function names as list operations in the Prelude.<br />
<br />
''Note: Operations that involve writing new index types for Repa arrays will require the '-XTypeOperators' language extension.''<br />
<br />
For non-core functionality, a number of related packages are available:<br />
<br />
* [http://hackage.haskell.org/package/repa-bytestring repa-bytestring]<br />
* [http://hackage.haskell.org/package/repa-io repa-io]<br />
* [http://hackage.haskell.org/package/repa-algorithms repa-algorithms]<br />
* [http://hackage.haskell.org/package/repa-devil repa-devil] (image loading)<br />
<br />
and example algorithms in:<br />
<br />
* [http://hackage.haskell.org/package/repa-examples repa-examples]<br />
<br />
== Index types and shapes ==<br />
<br />
Before we can get started manipulating arrays, we need a grasp of repa's notion of array shape. Much like the classic 'array' library in Haskell, repa-based arrays are parameterized via a type which determines the dimension of the array, and the type of its index. However, while classic arrays take tuples to represent multiple dimensions, Repa arrays use a [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa-Shape.html#t:Shape richer type language] for describing multi-dimensional array indices and shapes (technically, a ''heterogeneous snoc list'').<br />
<br />
Shape types are built somewhat like lists. The constructor '''Z''' corresponds<br />
to a rank zero shape, and is used to mark the end of the list. The ''':.''' constructor adds additional dimensions to the shape. So, for example, the shape:<br />
<br />
(Z:.3 :.2 :.3)<br />
<br />
is the shape of a small 3D array, with shape type<br />
<br />
(Z:.Int:.Int:.Int)<br />
<br />
The most common dimensions are given by the shorthand names:<br />
<br />
<haskell><br />
type DIM0 = Z<br />
type DIM1 = DIM0 :. Int<br />
type DIM2 = DIM1 :. Int<br />
type DIM3 = DIM2 :. Int<br />
type DIM4 = DIM3 :. Int<br />
type DIM5 = DIM4 :. Int<br />
</haskell><br />
<br />
thus,<br />
<br />
<haskell><br />
Array DIM2 Double<br />
</haskell><br />
<br />
is the type of a two-dimensional array of doubles, indexed via `Int` keys, while<br />
<br />
<haskell><br />
Array Z Double<br />
</haskell><br />
<br />
is a zero-dimension object (i.e. a point) holding a Double.<br />
<br />
Many operations over arrays are polymorphic in the shape / dimension<br />
component. Others require operating on the shape itself, rather than<br />
the array. A typeclass, <code>Shape</code>, lets us operate uniformly<br />
over arrays with different shape.<br />
<br />
=== Building shapes ===<br />
<br />
To build values of `shape` type, we can use the <code>Z</code> and <code>:.</code> constructors. Open the ghci and import Repa:<br />
<br />
<haskell><br />
Prelude> :m +Data.Array.Repa<br />
Repa> Z -- the zero-dimension<br />
Z<br />
</haskell><br />
<br />
For arrays of non-zero dimension, we must give a size. ''Note:'' a common error is to leave off the type of the size.<br />
<br />
<haskell><br />
Repa> :t Z :. 10<br />
Z :. 10 :: Num head => Z :. head<br />
</haskell><br />
<br />
leading to annoying type errors about unresolved instances, such as:<br />
<br />
No instance for (Shape (Z :. head0))<br />
<br />
To select the correct instance, you will need to annotate the size literals with their concrete type:<br />
<br />
<haskell><br />
Repa> :t Z :. (10 :: Int)<br />
Z :. (10 :: Int) :: Z :. Int<br />
</haskell><br />
<br />
is the shape of 1D arrays of length 10, indexed via Ints.<br />
<br />
Given an array, you can always find its shape by calling <code>extent</code>.<br />
<br />
Additional convenience types for selecting particular parts of a shape are also provided (<code>All, Any, Slice</code> etc.) which are covered later in the tutorial.<br />
<br />
=== Working with shapes ===<br />
<br />
That one key operation, '''extent''', gives us many attributes of an array:<br />
<br />
<haskell><br />
-- Extract the shape of the array<br />
extent :: Array sh a -> sh<br />
</haskell><br />
<br />
So, given a 3x3x3 array, of type '''Array DIM3 Int''', we can:<br />
<br />
<haskell><br />
-- build an array<br />
Repa> let x :: Array DIM3 Int; x = fromList (Z :. (3::Int) :. (3::Int) :. (3::Int)) [1..27]<br />
Repa> :t x<br />
x :: Array DIM3 Int<br />
<br />
-- query the extent<br />
Repa> extent x<br />
((Z :. 3) :. 3) :. 3<br />
<br />
-- compute the rank (number of dimensions)<br />
Repa> let sh = extent x<br />
Repa> rank sh<br />
3<br />
<br />
-- compute the size (total number of elements)<br />
> size sh<br />
27<br />
<br />
-- extract the elements of the array as a flat vector<br />
Repa> toVector x<br />
fromList [1,2,3,4,5,6,7,8,9,10<br />
,11,12,13,14,15,16,17,18,19<br />
,20,21,22,23,24,25,26,27] :: Data.Vector.Unboxed.Vector<br />
</haskell><br />
<br />
== Generating arrays ==<br />
<br />
New repa arrays ("arrays" from here on) can be generated in many ways, and we always begin by importing the <code>Data.Array.Repa</code> module:<br />
<br />
<br />
$ ghci<br />
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help<br />
Loading package ghc-prim ... linking ... done.<br />
Loading package integer-gmp ... linking ... done.<br />
Loading package base ... linking ... done.<br />
Loading package ffi-1.0 ... linking ... done.<br />
Prelude> :m + Data.Array.Repa<br />
<br />
<br />
They may be constructed from lists, for example. Here is a one dimensional array of length 10, here, given the shape `(Z :. 10)`:<br />
<br />
<haskell><br />
Repa> let inputs = [1..10] :: [Double]<br />
Repa> let x = fromList (Z :. (10::Int)) inputs<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
The type of `x` is inferred as:<br />
<br />
<haskell><br />
Repa> :t x<br />
x :: Array (Z :. Int) Double<br />
</haskell><br />
<br />
which we can read as "an array of dimension 1, indexed via Int keys, holding elements of type Double"<br />
<br />
We could also have written the type as:<br />
<br />
<haskell><br />
Repa> let x' = fromList (Z :. 10 :: DIM1) inputs<br />
Repa> :t x'<br />
x' :: Array DIM1 Double<br />
</haskell><br />
<br />
The same data may also be treated as a two dimensional array, by changing the shape parameter:<br />
<br />
<haskell><br />
Repa> let x2 = fromList (Z :. (5::Int) :. (2::Int)) inputs<br />
Repa> x2<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
which has the type:<br />
<br />
<haskell><br />
Repa> :t x2<br />
x2 :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
or, as above, if we define it with the type synonym for 2 dimensional Int- indexed arrays, DIM2:<br />
<br />
<haskell><br />
Repa> let x2' = fromList (Z :. 5 :. 2 :: DIM2) inputs<br />
Repa> x2'<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa> :t x2'<br />
x2' :: Array DIM2 Double<br />
</haskell><br />
<br />
=== Building arrays from vectors ===<br />
<br />
It is also possible to build arrays from unboxed vectors, from the 'vector' package:<br />
<br />
<haskell><br />
fromVector :: Shape sh => sh -> Vector a -> Array sh a<br />
</haskell><br />
<br />
New arrays are built by applying a shape to the vector. For example:<br />
<br />
<haskell><br />
Repa> import Data.Vector.Unboxed --recent ghci's support this import syntax<br />
Repa Unboxed> let x = fromVector (Z :. (10::Int)) (enumFromN 0 10)<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
</haskell><br />
<br />
is a one-dimensional array of doubles. As usual, we can also impose other<br />
shapes:<br />
<br />
<haskell><br />
Repa Unboxed> let x = fromVector (Z :. (3::Int) :. (3::Int)) (enumFromN 0 9)<br />
Repa Unboxed> x<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]<br />
Repa Unboxed> :t x<br />
x :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
to create a 3x3 array.<br />
<br />
=== Generating random arrays ===<br />
<br />
The [http://hackage.haskell.org/package/repa-algorithsm repa-algorithms] package lets us generate new arrays with random data:<br />
<br />
<haskell><br />
-- 3d array of Ints, bounded between 0 and 255.<br />
> randomishIntArray (Z :. (3::Int) :. (3::Int) :. (3::Int)) 0 255 1<br />
[217,42,130,200,216,254<br />
,67,77,152,85,140,226,179<br />
,71,23,17,152,84,47,17,45<br />
,5,88,245,107,214,136]<br />
</haskell><br />
<br />
=== Reading arrays from files ===<br />
<br />
Using the [http://hackage.haskell.org/package/repa-io repa-io] package, arrays may be written and read from files in a number of formats:<br />
<br />
* as BMP files; and<br />
* in a number of text formats.<br />
<br />
with other formats rapidly appearing. For the special case of arrays of Word8 values, the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] library supports generating bytestrings in memory.<br />
<br />
An example: to write an 2D array to an ascii file:<br />
<br />
<haskell><br />
Repa> :m +Data.Array.Repa.IO.Matrix<br />
Repa Matrix> let x = fromList (Z :. 5 :. 2 :: DIM2) [1..10]<br />
Repa Matrix> writeMatrixToTextFile "test.dat" x<br />
</haskell><br />
<br />
This will result in a file containing:<br />
<br />
MATRIX<br />
2 5<br />
1.0<br />
2.0<br />
3.0<br />
4.0<br />
5.0<br />
6.0<br />
7.0<br />
8.0<br />
9.0<br />
10.0<br />
<br />
In turn, this file may be read back in via <code>readMatrixFromTextFile</code>.<br />
<br />
<haskell><br />
Repa Matrix> xx <- readMatrixFromTextFile "test.dat" <br />
Repa Matrix> xx<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa Matrix> :t xx<br />
it :: Array DIM2 Double<br />
</haskell><br />
<br />
<br />
To process [http://en.wikipedia.org/wiki/BMP_file_format .bmp files], use [http://hackage.haskell.org/packages/archive/repa-io/2.0.0.3/doc/html/Data-Array-Repa-IO-BMP.html Data.Array.Repa.IO.BMP], as follows (currently reading only works for 24 bit .bmp):<br />
<br />
<haskell><br />
Data.Array.Repa.IO.BMP> x <- readImageFromBMP "/tmp/test24.bmp"<br />
</haskell><br />
<br />
Reads this .bmp image:<br />
<br />
http://i.imgur.com/T4ttx.png<br />
<br />
as a 3D array of Word8, which can be further processed.<br />
<br />
''Note: at the time of writing, there are no binary instances for repa arrays''<br />
<br />
For image IO in many, many formats, use the [http://hackage.haskell.org/package/repa-devil repa-devil] library.<br />
<br />
=== Copying arrays from pointers ===<br />
<br />
You can also generate new repa arrays by copying data from a pointer, using the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] package. Here is an example, using "copyFromPtrWord8":<br />
<br />
<haskell><br />
import Data.Word<br />
import Foreign.Ptr<br />
<br />
import qualified Data.Vector.Storable as V<br />
import qualified Data.Array.Repa as R<br />
import Data.Array.Repa<br />
import qualified Data.Array.Repa.ByteString as R<br />
<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
i, j, k :: Int <br />
(i, j, k) = (255, 255, 4 {-RGBA-})<br />
<br />
-- 1d vector, filled with pretty colors<br />
v :: V.Vector Word8<br />
v = V.fromList . take (i * j * k) . cycle $ concat<br />
[ [ r, g, b, 255 ]<br />
| r <- [0 .. 255]<br />
, g <- [0 .. 255]<br />
, b <- [0 .. 255]<br />
] <br />
<br />
ptr2repa :: Ptr Word8 -> IO (R.Array R.DIM3 Word8)<br />
ptr2repa p = R.copyFromPtrWord8 (Z :. i :. j :. k) p<br />
<br />
main = do<br />
-- copy our 1d vector to a repa 3d array, via a pointer<br />
r <- V.unsafeWith v ptr2repa<br />
runIL $ writeImage "test.png" r <br />
return ()<br />
</haskell><br />
<br />
This fills a vector, converts it to a pointer, then copies that pointer to a 3d array, before writing the result out as this image:<br />
<br />
http://i.imgur.com/o0Cv2.png<br />
<br />
== Indexing arrays ==<br />
<br />
To access elements in repa arrays, you provide an array and a shape, to access the element:<br />
<br />
<haskell><br />
(!) :: (Shape sh, Elt a) => Array sh a -> sh -> a<br />
</haskell><br />
<br />
So:<br />
<br />
<haskell><br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x ! (Z :. 2)<br />
3.0<br />
</haskell><br />
<br />
Note that we can't give just a bare literal as the shape, even for one-dimensional arrays, :<br />
<br />
<haskell><br />
> x ! 2<br />
<br />
No instance for (Num (Z :. Int))<br />
arising from the literal `2'<br />
</haskell><br />
<br />
as the Z type isn't in the Num class, and Haskell's numeric literals are overloaded.<br />
<br />
What if the index is out of bounds, though?<br />
<br />
<haskell><br />
> x ! (Z :. 11)<br />
*** Exception: ./Data/Vector/Generic.hs:222 ((!)): index out of bounds (11,10)<br />
</haskell><br />
<br />
an exception is thrown. An alternative is to use indexing functions that return a Maybe:<br />
<br />
<haskell><br />
(!?) :: (Shape sh, Elt a) => Array sh a -> sh -> Maybe a<br />
</haskell><br />
<br />
An example:<br />
<br />
<haskell><br />
> x !? (Z :. 9)<br />
Just 10.0<br />
<br />
> x !? (Z :. 11)<br />
Nothing<br />
</haskell><br />
<br />
== Operations on arrays ==<br />
<br />
Besides indexing, there are many regular, list-like operations on arrays. Since many of the names parallel those in the Prelude, we import Repa qualified:<br />
<br />
Repa> import qualified Data.Array.Repa as Repa<br />
<br />
=== Maps, zips, filters and folds ===<br />
<br />
We can map over multi-dimensional arrays:<br />
<br />
Repa> let x = fromList (Z :. (3::Int) :. (3::Int)) [1..9]<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
<br />
since `map` conflicts with the definition in the Prelude, we have to use it qualified as we requested:<br />
<br />
Repa> Repa.map (^2) x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
<br />
Maps leave the dimension unchanged.<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
Repa> extent (Repa.map (^2) x)<br />
(Z :. 3) :. 3<br />
<br />
Folding reduces the inner dimension of the array.<br />
<br />
fold :: (Shape sh, Elt a) <br />
=> (a -> a -> a) -> a -> Array (sh :. Int) a -> Array sh a<br />
<br />
The 'x' defined above is a 2D array:<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
<br />
If we sum each row:<br />
<br />
Repa> Repa.fold (+) 0 x<br />
[6.0,15.0,24.0]<br />
<br />
we get a 1D array instead:<br />
<br />
Repa> extent (Repa.fold (+) 0 x)<br />
Z :. 3<br />
<br />
Similarly, if 'y' is a (3 x 3 x 3) 3D array:<br />
<br />
Repa> let y = fromList ((Z :. 3 :. 3 :. 3) :: DIM3) [1..27]<br />
Repa> y<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0]<br />
<br />
we can fold over the inner dimension: <br />
<br />
Repa> Repa.fold (+) 0 y<br />
[6.0,15.0,24.0,33.0,42.0,51.0,60.0,69.0,78.0]<br />
<br />
yielding a 2D (3 x 3) array in place of our 3D (3 x 3 x 3) array<br />
Repa> extent y<br />
((Z :. 3) :. 3) :. 3<br />
Repa> extent (Repa.fold (+) 0 y)<br />
(Z :. 3) :. 3<br />
<br />
Two arrays may be combined via <code>zipWith</code>:<br />
<br />
zipWith :: (Shape sh, Elt b, Elt c, Elt a) =><br />
(a -> b -> c) -> Array sh a -> Array sh b -> Array sh c<br />
<br />
an example:<br />
<br />
Repa> Repa.zipWith (*) x x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
Repa> extent it<br />
(Z :. 3) :. 3<br />
<br />
Repa> Repa.zipWith (*) y y <br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,<br />
100.0,121.0,144.0,169.0,196.0,225.0,256.0,289.0,324.0,<br />
361.0,400.0,441.0,484.0,529.0,576.0,625.0,676.0,729.0] --reformatted<br />
Repa> extent it<br />
((Z :. 3) :. 3) :. 3<br />
<br />
=== Numeric operations: negation, addition, subtraction, multiplication ===<br />
<br />
Repa arrays are instances of the <code>Num</code>. This means that<br />
operations on numerical elements are lifted automagically onto arrays of<br />
such elements. For example, <code>(+)</code> on two double values corresponds to<br />
element-wise addition, <code>(+)</code>, of the two arrays of doubles:<br />
<br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x + x<br />
[2.0,4.0,6.0,8.0,10.0,12.0,14.0,16.0,18.0,20.0]<br />
<br />
Other operations from the Num class work just as well:<br />
<br />
> -x<br />
[-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0,-8.0,-9.0,-10.0]<br />
<br />
> x ^ 3<br />
[1.0,8.0,27.0,64.0,125.0,216.0,343.0,512.0,729.0,1000.0]<br />
<br />
> x * x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,100.0]<br />
<br />
== Changing the shape of an array ==<br />
<br />
One of the main advantages of repa-style arrays over other arrays in<br />
Haskell is the ability to reshape data without copying. This is achieved<br />
via *index-space transformations*. <br />
<br />
An example: transposing a 2D array (this example taken from the repa<br />
paper). First, the type of the transformation:<br />
<br />
transpose2D :: Elt e => Array DIM2 e -> Array DIM2 e <br />
<br />
Note that this transform will work on DIM2 arrays holding any elements.<br />
Now, to swap rows and columns, we have to modify the shape:<br />
<br />
transpose2D a = backpermute (swap e) swap a<br />
where<br />
e = extent a<br />
swap (Z :. i :. j) = Z :. j :. i<br />
<br />
The swap function reorders the index space of the array.<br />
To do this, we extract the current shape of the array, and write a function<br />
that maps the index space from the old array to the new array. That index space function<br />
is then passed to backpermute which actually constructs the new<br />
array from the old one.<br />
<br />
backpermute generates a new array from an old, when given the new shape, and a<br />
function that translates between the index space of each array (i.e. a shape<br />
transformer).<br />
<br />
backpermute<br />
:: (Shape sh, Shape sh', Elt a) <br />
=> sh' <br />
-> (sh' -> sh) <br />
-> Array sh a <br />
-> Array sh' a<br />
<br />
Note that the array created is not actually evaluated (we only modified the index space of the array).<br />
<br />
Transposition is such a common operation that it is provided by the<br />
library:<br />
<br />
transpose :: (Shape sh, Elt a)<br />
=> Array ((sh :. Int) :. Int) a -> Array ((sh :. Int) :. Int)<br />
<br />
the type indicate that it works on the lowest two dimensions of the<br />
array.<br />
<br />
Other operations on index spaces include taking slices and joining<br />
arrays into larger ones.<br />
<br />
== Examples ==<br />
<br />
Following are some examples of useful functions that exercise the API.<br />
<br />
=== Example: Rotating an image with backpermute ===<br />
<br />
Flip an image upside down:<br />
<br />
<haskell><br />
import System.Environment<br />
import Data.Word<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
main = do<br />
[f] <- getArgs<br />
runIL $ do<br />
v <- readImage f<br />
writeImage ("flip-"++f) (rot180 v)<br />
<br />
rot180 :: Array DIM3 Word8 -> Array DIM3 Word8<br />
rot180 g = backpermute e flop g<br />
where<br />
e@(Z :. x :. y :. _) = extent g<br />
<br />
flop (Z :. i :. j :. k) =<br />
(Z :. x - i - 1 :. y - j - 1 :. k)<br />
</haskell><br />
<br />
Running this:<br />
<br />
$ ghc -O2 --make A.hs<br />
$ ./A haskell.jpg <br />
<br />
Results in:<br />
<br />
http://i.imgur.com/YsGA8.jpg<br />
<br />
=== Example: matrix-matrix multiplication ===<br />
<br />
A more advanced example from the Repa paper: matrix-matrix multiplication: the result of<br />
matrix multiplication is a matrix whose elements are found by<br />
multiplying the elements of each row from the first matrix by the<br />
associated elements of the same column from the second matrix and<br />
summing the result.<br />
<br />
if <math>A=\begin{bmatrix}a&b\\c&d\end{bmatrix}</math> and <math>B=\begin{bmatrix}e&f\\g&h\end{bmatrix}</math><br />
<br />
then <br />
<br />
<math>AB=\begin{bmatrix}a&b\\c&d\end{bmatrix}\begin{bmatrix}e&f\\g&h\end{bmatrix}=\begin{bmatrix}ae+bg&af+bh\\ce+dg&cf+dh\end{bmatrix}</math><br />
<br />
So we take two, 2D arrays and generate a new array, using our transpose<br />
function from earlier:<br />
<br />
<haskell><br />
mmMult :: (Num e, Elt e)<br />
=> Array DIM2 e<br />
-> Array DIM2 e<br />
-> Array DIM2 e<br />
<br />
mmMult a b = sum (zipWith (*) aRepl bRepl)<br />
where<br />
t = transpose2D b<br />
aRepl = extend (Z :.All :.colsB :.All) a<br />
bRepl = extend (Z :.rowsA :.All :.All) t<br />
(Z :.colsA :.rowsA) = extent a<br />
(Z :.colsB :.rowsB) = extent b<br />
</haskell><br />
<br />
The idea is to expand both 2D argument arrays into 3D arrays by<br />
replicating them across a new axis. The front face of the cuboid that<br />
results represents the array <code>a</code>, which we replicate as often<br />
as <code>b</code> has columns <code>(colsB)</code>, producing<br />
<code>aRepl</code>.<br />
<br />
The top face represents <code>t</code> (the transposed b), which we<br />
replicate as often as a has rows <code>(rowsA)</code>, producing<br />
<code>bRepl,</code>. The two replicated arrays have the same extent,<br />
which corresponds to the index space of matrix multiplication<br />
<br />
Optimized implementations of this function are available in the<br />
repa-algorithms package.<br />
<br />
=== Example: parallel image desaturation ===<br />
<br />
To convert an image from color to greyscale, we can use the luminosity method to averge RGB pixels into a common grey value, where the average is weighted for human perception of green<br />
<br />
The formula for luminosity is 0.21 R + 0.71 G + 0.07 B.<br />
<br />
We can write a parallel image desaturation tool using repa and the [http://hackage.haskell.org/package/repa-devil repa-devil image library]:<br />
<br />
<haskell><br />
import Data.Array.Repa.IO.DevIL<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Word<br />
import System.Environment<br />
<br />
--<br />
-- Read an image, desaturate, write out with new name.<br />
--<br />
main = do <br />
[f] <- getArgs<br />
runIL $ do<br />
a <- readImage f<br />
let b = traverse a id luminosity <br />
writeImage ("grey-" ++ f) b<br />
</haskell><br />
<br />
And now the luminosity transform itself, which averages the 3 RGB colors based on preceived weight:<br />
<br />
<haskell><br />
--<br />
-- (Parallel) desaturation of an image via the luminosity method.<br />
--<br />
luminosity :: (DIM3 -> Word8) -> DIM3 -> Word8<br />
luminosity _ (Z :. _ :. _ :. 3) = 255 -- alpha channel<br />
luminosity f (Z :. i :. j :. _) = ceiling $ 0.21 * r + 0.71 * g + 0.07 * b<br />
where<br />
r = fromIntegral $ f (Z :. i :. j :. 0)<br />
g = fromIntegral $ f (Z :. i :. j :. 1)<br />
b = fromIntegral $ f (Z :. i :. j :. 2)<br />
</haskell><br />
<br />
And that's it! The result is a parallel image desaturator, when compiled with <br />
<br />
$ ghc -O -threaded -rtsopts --make A.hs -fforce-recomp<br />
<br />
which we can run, to use two cores:<br />
<br />
$ time ./A sunflower.png +RTS -N2 -H <br />
./A sunflower.png +RTS -N2 -H 0.19s user 0.03s system 135% cpu 0.165 total<br />
<br />
Given an image like this:<br />
<br />
http://i.imgur.com/iu4gV.png<br />
<br />
The desaturated result from Haskell:<br />
<br />
http://i.imgur.com/REhA5.png<br />
<br />
[[Category:Libraries]]<br />
[[Category:Packages]]<br />
[[Category:Performance]]<br />
[[Category:Tutorials]]<br />
[[Category:Parallel]]</div>Tanimotohttps://wiki.haskell.org/Numeric_Haskell:_A_Repa_TutorialNumeric Haskell: A Repa Tutorial2011-05-18T00:01:21Z<p>Tanimoto: Fixed typo: uniformly</p>
<hr />
<div>[http://hackage.haskell.org/package/repa Repa] is a Haskell library for<br />
high performance, regular, multi-dimensional parallel arrays. All<br />
numeric data is stored unboxed and functions written with the Repa<br />
combinators are automatically parallel (provided you supply "+RTS -N" on<br />
the command line when running the program).<br />
<br />
[[Image:Grid.png|right]]<br />
<br />
This document provides a tutorial on array programming in Haskell using the repa package.<br />
<br />
''Note: a companion tutorial to this is provided as the [http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Vector_Tutorial vector tutorial], and is based on the [http://www.scipy.org/Tentative_NumPy_Tutorial NumPy tutorial]''.<br />
<br />
''Authors: [http://donsbot.wordpress.com Don Stewart].''<br />
<br />
= Quick Tour =<br />
<br />
Repa (REgular PArallel arrays) is an advanced, multi-dimensional parallel arrays library for Haskell, with a number of distinct capabilities:<br />
<br />
* The arrays are "regular" (i.e. dense, rectangular and store elements all of the same type); and<br />
* Functions may be written that are polymorphic in the shape of the array;<br />
* Many operations on arrays are accomplished by changing only the shape of the array (without copying elements);<br />
* The library will automatically parallelize operations over arrays.<br />
<br />
This is a quick start guide for the package. For further information, consult:<br />
<br />
* [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa.html The Haddock Documentation]<br />
* [http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/rarrays.pdf Regular, Shape-polymorphic, Parallel Arrays in Haskell].<br />
* [http://www.cse.unsw.edu.au/~benl/papers/stencil/stencil-icfp2011-sub.pdf Efﬁcient Parallel Stencil Convolution in Haskell]<br />
<br />
== Importing the library ==<br />
<br />
Download the `repa` package:<br />
<br />
$ cabal install repa<br />
<br />
and import it qualified:<br />
<br />
import qualified Data.Array.Repa as R<br />
<br />
The library needs to be imported qualified as it shares the same function names as list operations in the Prelude.<br />
<br />
''Note: Operations that involve writing new index types for Repa arrays will require the '-XTypeOperators' language extension.''<br />
<br />
For non-core functionality, a number of related packages are available:<br />
<br />
* [http://hackage.haskell.org/package/repa-bytestring repa-bytestring]<br />
* [http://hackage.haskell.org/package/repa-io repa-io]<br />
* [http://hackage.haskell.org/package/repa-algorithms repa-algorithms]<br />
* [http://hackage.haskell.org/package/repa-devil repa-devil] (image loading)<br />
<br />
and example algorithms in:<br />
<br />
* [http://hackage.haskell.org/package/repa-examples repa-examples]<br />
<br />
== Index types and shapes ==<br />
<br />
Before we can get started manipulating arrays, we need a grasp of repa's notion of array shape. Much like the classic 'array' library in Haskell, repa-based arrays are parameterized via a type which determines the dimension of the array, and the type of its index. However, while classic arrays take tuples to represent multiple dimensions, Repa arrays use a [http://hackage.haskell.org/packages/archive/repa/2.0.0.3/doc/html/Data-Array-Repa-Shape.html#t:Shape richer type language] for describing multi-dimensional array indices and shapes (technically, a ''heterogeneous snoc list'').<br />
<br />
Shape types are built somewhat like lists. The constructor '''Z''' corresponds<br />
to a rank zero shape, and is used to mark the end of the list. The ''':.''' constructor adds additional dimensions to the shape. So, for example, the shape:<br />
<br />
(Z:.3 :.2 :.3)<br />
<br />
is the shape of a small 3D array, with shape type<br />
<br />
(Z:.Int:.Int:.Int)<br />
<br />
The most common dimensions are given by the shorthand names:<br />
<br />
<haskell><br />
type DIM0 = Z<br />
type DIM1 = DIM0 :. Int<br />
type DIM2 = DIM1 :. Int<br />
type DIM3 = DIM2 :. Int<br />
type DIM4 = DIM3 :. Int<br />
type DIM5 = DIM4 :. Int<br />
</haskell><br />
<br />
thus,<br />
<br />
<haskell><br />
Array DIM2 Double<br />
</haskell><br />
<br />
is the type of a two-dimensional array of doubles, indexed via `Int` keys, while<br />
<br />
<haskell><br />
Array Z Double<br />
</haskell><br />
<br />
is a zero-dimension object (i.e. a point) holding a Double.<br />
<br />
Many operations over arrays are polymorphic in the shape / dimension<br />
component. Others require operating on the shape itself, rather than<br />
the array. A typeclass, <code>Shape</code>, lets us operate uniformly<br />
over arrays with different shape.<br />
<br />
=== Building shapes ===<br />
<br />
To build values of `shape` type, we can use the <code>Z</code> and <code>:.</code> constructors. Open the ghci and import Repa:<br />
<br />
<haskell><br />
Prelude> :m +Data.Array.Repa<br />
Repa> Z -- the zero-dimension<br />
Z<br />
</haskell><br />
<br />
For arrays of non-zero dimension, we must give a size. ''Note:'' a common error is to leave off the type of the size.<br />
<br />
<haskell><br />
Repa> :t Z :. 10<br />
Z :. 10 :: Num head => Z :. head<br />
</haskell><br />
<br />
leading to annoying type errors about unresolved instances, such as:<br />
<br />
No instance for (Shape (Z :. head0))<br />
<br />
To select the correct instance, you will need to annotate the size literals with their concrete type:<br />
<br />
<haskell><br />
Repa> :t Z :. (10 :: Int)<br />
Z :. (10 :: Int) :: Z :. Int<br />
</haskell><br />
<br />
is the shape of 1D arrays of length 10, indexed via Ints.<br />
<br />
Given an array, you can always find its shape by calling <code>extent</code>.<br />
<br />
Additional convenience types for selecting particular parts of a shape are also provided (<code>All, Any, Slice</code> etc.) which are covered later in the tutorial.<br />
<br />
=== Working with shapes ===<br />
<br />
That one key operation, '''extent''', gives us many attributes of an array:<br />
<br />
<haskell><br />
-- Extract the shape of the array<br />
extent :: Array sh a -> sh<br />
</haskell><br />
<br />
So, given a 3x3x3 array, of type '''Array DIM3 Int''', we can:<br />
<br />
<haskell><br />
-- build an array<br />
Repa> let x :: Array DIM3 Int; x = fromList (Z :. (3::Int) :. (3::Int) :. (3::Int)) [1..27]<br />
Repa> :t x<br />
x :: Array DIM3 Int<br />
<br />
-- query the extent<br />
Repa> extent x<br />
((Z :. 3) :. 3) :. 3<br />
<br />
-- compute the rank (number of dimensions)<br />
Repa> let sh = extent x<br />
Repa> rank sh<br />
3<br />
<br />
-- compute the size (total number of elements)<br />
> size sh<br />
27<br />
<br />
-- extract the elements of the array as a flat vector<br />
Repa> toVector x<br />
fromList [1,2,3,4,5,6,7,8,9,10<br />
,11,12,13,14,15,16,17,18,19<br />
,20,21,22,23,24,25,26,27] :: Data.Vector.Unboxed.Vector<br />
</haskell><br />
<br />
== Generating arrays ==<br />
<br />
New repa arrays ("arrays" from here on) can be generated in many ways, and we always begin by importing the <code>Data.Array.Repa</code> module:<br />
<br />
<br />
$ ghci<br />
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help<br />
Loading package ghc-prim ... linking ... done.<br />
Loading package integer-gmp ... linking ... done.<br />
Loading package base ... linking ... done.<br />
Loading package ffi-1.0 ... linking ... done.<br />
Prelude> :m + Data.Array.Repa<br />
<br />
<br />
They may be constructed from lists, for example. Here is a one dimensional array of length 10, here, given the shape `(Z :. 10)`:<br />
<br />
<haskell><br />
Repa> let inputs = [1..10] :: [Double]<br />
Repa> let x = fromList (Z :. (10::Int)) inputs<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
The type of `x` is inferred as:<br />
<br />
<haskell><br />
Repa> :t x<br />
x :: Array (Z :. Int) Double<br />
</haskell><br />
<br />
which we can read as "an array of dimension 1, indexed via Int keys, holding elements of type Double"<br />
<br />
We could also have written the type as:<br />
<br />
<haskell><br />
Repa> let x' = fromList (Z :. 10 :: DIM1) inputs<br />
Repa> :t x'<br />
x' :: Array DIM1 Double<br />
</haskell><br />
<br />
The same data may also be treated as a two dimensional array, by changing the shape parameter:<br />
<br />
<haskell><br />
Repa> let x2 = fromList (Z :. (5::Int) :. (2::Int)) inputs<br />
Repa> x2<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
</haskell><br />
<br />
which has the type:<br />
<br />
<haskell><br />
Repa> :t x2<br />
x2 :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
or, as above, if we define it with the type synonym for 2 dimensional Int- indexed arrays, DIM2:<br />
<br />
<haskell><br />
Repa> let x2' = fromList (Z :. 5 :. 2 :: DIM2) inputs<br />
Repa> x2'<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa> :t x2'<br />
x2' :: Array DIM2 Double<br />
</haskell><br />
<br />
=== Building arrays from vectors ===<br />
<br />
It is also possible to build arrays from unboxed vectors, from the 'vector' package:<br />
<br />
<haskell><br />
fromVector :: Shape sh => sh -> Vector a -> Array sh a<br />
</haskell><br />
<br />
New arrays are built by applying a shape to the vector. For example:<br />
<br />
<haskell><br />
Repa> import Data.Vector.Unboxed --recent ghci's support this import syntax<br />
Repa Unboxed> let x = fromVector (Z :. (10::Int)) (enumFromN 0 10)<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
</haskell><br />
<br />
is a one-dimensional array of doubles. As usual, we can also impose other<br />
shapes:<br />
<br />
<haskell><br />
Repa Unboxed> let x = fromVector (Z :. (3::Int) :. (3::Int)) (enumFromN 0 9)<br />
Repa Unboxed> x<br />
[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]<br />
Repa Unboxed> :t x<br />
x :: Array ((Z :. Int) :. Int) Double<br />
</haskell><br />
<br />
to create a 3x3 array.<br />
<br />
=== Generating random arrays ===<br />
<br />
The [http://hackage.haskell.org/package/repa-algorithsm repa-algorithms] package lets us generate new arrays with random data:<br />
<br />
<haskell><br />
-- 3d array of Ints, bounded between 0 and 255.<br />
> randomishIntArray (Z :. (3::Int) :. (3::Int) :. (3::Int)) 0 255 1<br />
[217,42,130,200,216,254<br />
,67,77,152,85,140,226,179<br />
,71,23,17,152,84,47,17,45<br />
,5,88,245,107,214,136]<br />
</haskell><br />
<br />
=== Reading arrays from files ===<br />
<br />
Using the [http://hackage.haskell.org/package/repa-io repa-io] package, arrays may be written and read from files in a number of formats:<br />
<br />
* as BMP files; and<br />
* in a number of text formats.<br />
<br />
with other formats rapidly appearing. For the special case of arrays of Word8 values, the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] library supports generating bytestrings in memory.<br />
<br />
An example: to write an 2D array to an ascii file:<br />
<br />
<haskell><br />
Repa> :m +Data.Array.Repa.IO.Matrix<br />
Repa Matrix> let x = fromList (Z :. 5 :. 2 :: DIM2) [1..10]<br />
Repa Matrix> writeMatrixToTextFile "test.dat" x<br />
</haskell><br />
<br />
This will result in a file containing:<br />
<br />
MATRIX<br />
2 5<br />
1.0<br />
2.0<br />
3.0<br />
4.0<br />
5.0<br />
6.0<br />
7.0<br />
8.0<br />
9.0<br />
10.0<br />
<br />
In turn, this file may be read back in via <code>readMatrixFromTextFile</code>.<br />
<br />
<haskell><br />
Repa Matrix> xx <- readMatrixFromTextFile "test.dat" <br />
Repa Matrix> xx<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]<br />
Repa Matrix> :t xx<br />
it :: Array DIM2 Double<br />
</haskell><br />
<br />
<br />
To process [http://en.wikipedia.org/wiki/BMP_file_format .bmp files], use [http://hackage.haskell.org/packages/archive/repa-io/2.0.0.3/doc/html/Data-Array-Repa-IO-BMP.html Data.Array.Repa.IO.BMP], as follows (currently reading only works for 24 bit .bmp):<br />
<br />
<haskell><br />
Data.Array.Repa.IO.BMP> x <- readImageFromBMP "/tmp/test24.bmp"<br />
</haskell><br />
<br />
Reads this .bmp image:<br />
<br />
http://i.imgur.com/T4ttx.png<br />
<br />
as a 3D array of Word8, which can be further processed.<br />
<br />
''Note: at the time of writing, there are no binary instances for repa arrays''<br />
<br />
For image IO in many, many formats, use the [http://hackage.haskell.org/package/repa-devil repa-devil] library.<br />
<br />
=== Copying arrays from pointers ===<br />
<br />
You can also generate new repa arrays by copying data from a pointer, using the [http://hackage.haskell.org/package/repa-bytestring repa-bytestring] package. Here is an example, using "copyFromPtrWord8":<br />
<br />
<haskell><br />
import Data.Word<br />
import Foreign.Ptr<br />
<br />
import qualified Data.Vector.Storable as V<br />
import qualified Data.Array.Repa as R<br />
import Data.Array.Repa<br />
import qualified Data.Array.Repa.ByteString as R<br />
<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
i, j, k :: Int <br />
(i, j, k) = (255, 255, 4 {-RGBA-})<br />
<br />
-- 1d vector, filled with pretty colors<br />
v :: V.Vector Word8<br />
v = V.fromList . take (i * j * k) . cycle $ concat<br />
[ [ r, g, b, 255 ]<br />
| r <- [0 .. 255]<br />
, g <- [0 .. 255]<br />
, b <- [0 .. 255]<br />
] <br />
<br />
ptr2repa :: Ptr Word8 -> IO (R.Array R.DIM3 Word8)<br />
ptr2repa p = R.copyFromPtrWord8 (Z :. i :. j :. k) p<br />
<br />
main = do<br />
-- copy our 1d vector to a repa 3d array, via a pointer<br />
r <- V.unsafeWith v ptr2repa<br />
runIL $ writeImage "test.png" r <br />
return ()<br />
</haskell><br />
<br />
This fills a vector, converts it to a pointer, then copies that pointer to a 3d array, before writing the result out as this image:<br />
<br />
http://i.imgur.com/o0Cv2.png<br />
<br />
== Indexing arrays ==<br />
<br />
To access elements in repa arrays, you provide an array and a shape, to access the element:<br />
<br />
<haskell><br />
(!) :: (Shape sh, Elt a) => Array sh a -> sh -> a<br />
</haskell><br />
<br />
So:<br />
<br />
<haskell><br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x ! (Z :. 2)<br />
3.0<br />
</haskell><br />
<br />
Note that we can't give just a bare literal as the shape, even for one-dimensional arrays, :<br />
<br />
<haskell><br />
> x ! 2<br />
<br />
No instance for (Num (Z :. Int))<br />
arising from the literal `2'<br />
</haskell><br />
<br />
as the Z type isn't in the Num class, and Haskell's numeric literals are overloaded.<br />
<br />
What if the index is out of bounds, though?<br />
<br />
<haskell><br />
> x ! (Z :. 11)<br />
*** Exception: ./Data/Vector/Generic.hs:222 ((!)): index out of bounds (11,10)<br />
</haskell><br />
<br />
an exception is thrown. An altnerative is to indexing functions that return a Maybe:<br />
<br />
<haskell><br />
(!?) :: (Shape sh, Elt a) => Array sh a -> sh -> Maybe a<br />
</haskell><br />
<br />
An example:<br />
<br />
<haskell><br />
> x !? (Z :. 9)<br />
Just 10.0<br />
<br />
> x !? (Z :. 11)<br />
Nothing<br />
</haskell><br />
<br />
== Operations on arrays ==<br />
<br />
Besides indexing, there are many regular, list-like operations on arrays. Since many of the names parallel those in the Prelude, we import Repa qualified:<br />
<br />
Repa> import qualified Data.Array.Repa as Repa<br />
<br />
=== Maps, zips, filters and folds ===<br />
<br />
We can map over multi-dimensional arrays:<br />
<br />
Repa> let x = fromList (Z :. (3::Int) :. (3::Int)) [1..9]<br />
Repa> x<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]<br />
<br />
since `map` conflicts with the definition in the Prelude, we have to use it qualified as we requested:<br />
<br />
Repa> Repa.map (^2) x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
<br />
Maps leave the dimension unchanged.<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
Repa> extent (Repa.map (^2) x)<br />
(Z :. 3) :. 3<br />
<br />
Folding reduces the inner dimension of the array.<br />
<br />
fold :: (Shape sh, Elt a) <br />
=> (a -> a -> a) -> a -> Array (sh :. Int) a -> Array sh a<br />
<br />
The 'x' defined above is a 2D array:<br />
<br />
Repa> extent x<br />
(Z :. 3) :. 3<br />
<br />
If we sum each row:<br />
<br />
Repa> Repa.fold (+) 0 x<br />
[6.0,15.0,24.0]<br />
<br />
we get a 1D array instead:<br />
<br />
Repa> extent (Repa.fold (+) 0 x)<br />
Z :. 3<br />
<br />
Similarly, if 'y' is a (3 x 3 x 3) 3D array:<br />
<br />
Repa> let y = fromList ((Z :. 3 :. 3 :. 3) :: DIM3) [1..27]<br />
Repa> y<br />
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0]<br />
<br />
we can fold over the inner dimension: <br />
<br />
Repa> Repa.fold (+) 0 y<br />
[6.0,15.0,24.0,33.0,42.0,51.0,60.0,69.0,78.0]<br />
<br />
yielding a 2D (3 x 3) array in place of our 3D (3 x 3 x 3) array<br />
Repa> extent y<br />
((Z :. 3) :. 3) :. 3<br />
Repa> extent (Repa.fold (+) 0 y)<br />
(Z :. 3) :. 3<br />
<br />
Two arrays may be combined via <code>zipWith</code>:<br />
<br />
zipWith :: (Shape sh, Elt b, Elt c, Elt a) =><br />
(a -> b -> c) -> Array sh a -> Array sh b -> Array sh c<br />
<br />
an example:<br />
<br />
Repa> Repa.zipWith (*) x x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0]<br />
Repa> extent it<br />
(Z :. 3) :. 3<br />
<br />
Repa> Repa.zipWith (*) y y <br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,<br />
100.0,121.0,144.0,169.0,196.0,225.0,256.0,289.0,324.0,<br />
361.0,400.0,441.0,484.0,529.0,576.0,625.0,676.0,729.0] --reformatted<br />
Repa> extent it<br />
((Z :. 3) :. 3) :. 3<br />
<br />
=== Numeric operations: negation, addition, subtraction, multiplication ===<br />
<br />
Repa arrays are instances of the <code>Num</code>. This means that<br />
operations on numerical elements are lifted automagically onto arrays of<br />
such elements. For example, <code>(+)</code> on two double values corresponds to<br />
element-wise addition, <code>(+)</code>, of the two arrays of doubles:<br />
<br />
> let x = fromList (Z :. (10::Int)) [1..10]<br />
> x + x<br />
[2.0,4.0,6.0,8.0,10.0,12.0,14.0,16.0,18.0,20.0]<br />
<br />
Other operations from the Num class work just as well:<br />
<br />
> -x<br />
[-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0,-8.0,-9.0,-10.0]<br />
<br />
> x ^ 3<br />
[1.0,8.0,27.0,64.0,125.0,216.0,343.0,512.0,729.0,1000.0]<br />
<br />
> x * x<br />
[1.0,4.0,9.0,16.0,25.0,36.0,49.0,64.0,81.0,100.0]<br />
<br />
== Changing the shape of an array ==<br />
<br />
One of the main advantages of repa-style arrays over other arrays in<br />
Haskell is the ability to reshape data without copying. This is achieved<br />
via *index-space transformations*. <br />
<br />
An example: transposing a 2D array (this example taken from the repa<br />
paper). First, the type of the transformation:<br />
<br />
transpose2D :: Elt e => Array DIM2 e -> Array DIM2 e <br />
<br />
Note that this transform will work on DIM2 arrays holding any elements.<br />
Now, to swap rows and columns, we have to modify the shape:<br />
<br />
transpose2D a = backpermute (swap e) swap a<br />
where<br />
e = extent a<br />
swap (Z :. i :. j) = Z :. j :. i<br />
<br />
The swap function reorders the index space of the array.<br />
To do this, we extract the current shape of the array, and write a function<br />
that maps the index space from the old array to the new array. That index space function<br />
is then passed to backpermute which actually constructs the new<br />
array from the old one.<br />
<br />
backpermute generates a new array from an old, when given the new shape, and a<br />
function that translates between the index space of each array (i.e. a shape<br />
transformer).<br />
<br />
backpermute<br />
:: (Shape sh, Shape sh', Elt a) <br />
=> sh' <br />
-> (sh' -> sh) <br />
-> Array sh a <br />
-> Array sh' a<br />
<br />
Note that the array created is not actually evaluated (we only modified the index space of the array).<br />
<br />
Transposition is such a common operation that it is provided by the<br />
library:<br />
<br />
transpose :: (Shape sh, Elt a)<br />
=> Array ((sh :. Int) :. Int) a -> Array ((sh :. Int) :. Int)<br />
<br />
the type indicate that it works on the lowest two dimensions of the<br />
array.<br />
<br />
Other operations on index spaces include taking slices and joining<br />
arrays into larger ones.<br />
<br />
== Examples ==<br />
<br />
Following are some examples of useful functions that exercise the API.<br />
<br />
=== Example: Rotating an image with backpermute ===<br />
<br />
Flip an image upside down:<br />
<br />
<haskell><br />
import System.Environment<br />
import Data.Word<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Array.Repa.IO.DevIL<br />
<br />
main = do<br />
[f] <- getArgs<br />
runIL $ do<br />
v <- readImage f<br />
writeImage ("flip-"++f) (rot180 v)<br />
<br />
rot180 :: Array DIM3 Word8 -> Array DIM3 Word8<br />
rot180 g = backpermute e flop g<br />
where<br />
e@(Z :. x :. y :. _) = extent g<br />
<br />
flop (Z :. i :. j :. k) =<br />
(Z :. x - i - 1 :. y - j - 1 :. k)<br />
</haskell><br />
<br />
Running this:<br />
<br />
$ ghc -O2 --make A.hs<br />
$ ./A haskell.jpg <br />
<br />
Results in:<br />
<br />
http://i.imgur.com/YsGA8.jpg<br />
<br />
=== Example: matrix-matrix multiplication ===<br />
<br />
A more advanced example from the Repa paper: matrix-matrix multiplication: the result of<br />
matrix multiplication is a matrix whose elements are found by<br />
multiplying the elements of each row from the first matrix by the<br />
associated elements of the same column from the second matrix and<br />
summing the result.<br />
<br />
if <math>A=\begin{bmatrix}a&b\\c&d\end{bmatrix}</math> and <math>B=\begin{bmatrix}e&f\\g&h\end{bmatrix}</math><br />
<br />
then <br />
<br />
<math>AB=\begin{bmatrix}a&b\\c&d\end{bmatrix}\begin{bmatrix}e&f\\g&h\end{bmatrix}=\begin{bmatrix}ae+bg&af+bh\\ce+dg&cf+dh\end{bmatrix}</math><br />
<br />
So we take two, 2D arrays and generate a new array, using our transpose<br />
function from earlier:<br />
<br />
<haskell><br />
mmMult :: (Num e, Elt e)<br />
=> Array DIM2 e<br />
-> Array DIM2 e<br />
-> Array DIM2 e<br />
<br />
mmMult a b = sum (zipWith (*) aRepl bRepl)<br />
where<br />
t = transpose2D b<br />
aRepl = extend (Z :.All :.colsB :.All) a<br />
bRepl = extend (Z :.rowsA :.All :.All) t<br />
(Z :.colsA :.rowsA) = extent a<br />
(Z :.colsB :.rowsB) = extent b<br />
</haskell><br />
<br />
The idea is to expand both 2D argument arrays into 3D arrays by<br />
replicating them across a new axis. The front face of the cuboid that<br />
results represents the array <code>a</code>, which we replicate as often<br />
as <code>b</code> has columns <code>(colsB)</code>, producing<br />
<code>aRepl</code>.<br />
<br />
The top face represents <code>t</code> (the transposed b), which we<br />
replicate as often as a has rows <code>(rowsA)</code>, producing<br />
<code>bRepl,</code>. The two replicated arrays have the same extent,<br />
which corresponds to the index space of matrix multiplication<br />
<br />
Optimized implementations of this function are available in the<br />
repa-algorithms package.<br />
<br />
=== Example: parallel image desaturation ===<br />
<br />
To convert an image from color to greyscale, we can use the luminosity method to averge RGB pixels into a common grey value, where the average is weighted for human perception of green<br />
<br />
The formula for luminosity is 0.21 R + 0.71 G + 0.07 B.<br />
<br />
We can write a parallel image desaturation tool using repa and the [http://hackage.haskell.org/package/repa-devil repa-devil image library]:<br />
<br />
<haskell><br />
import Data.Array.Repa.IO.DevIL<br />
import Data.Array.Repa hiding ((++))<br />
import Data.Word<br />
import System.Environment<br />
<br />
--<br />
-- Read an image, desaturate, write out with new name.<br />
--<br />
main = do <br />
[f] <- getArgs<br />
runIL $ do<br />
a <- readImage f<br />
let b = traverse a id luminosity <br />
writeImage ("grey-" ++ f) b<br />
</haskell><br />
<br />
And now the luminosity transform itself, which averages the 3 RGB colors based on preceived weight:<br />
<br />
<haskell><br />
--<br />
-- (Parallel) desaturation of an image via the luminosity method.<br />
--<br />
luminosity :: (DIM3 -> Word8) -> DIM3 -> Word8<br />
luminosity _ (Z :. _ :. _ :. 3) = 255 -- alpha channel<br />
luminosity f (Z :. i :. j :. _) = ceiling $ 0.21 * r + 0.71 * g + 0.07 * b<br />
where<br />
r = fromIntegral $ f (Z :. i :. j :. 0)<br />
g = fromIntegral $ f (Z :. i :. j :. 1)<br />
b = fromIntegral $ f (Z :. i :. j :. 2)<br />
</haskell><br />
<br />
And that's it! The result is a parallel image desaturator, when compiled with <br />
<br />
$ ghc -O -threaded -rtsopts --make A.hs -fforce-recomp<br />
<br />
which we can run, to use two cores:<br />
<br />
$ time ./A sunflower.png +RTS -N2 -H <br />
./A sunflower.png +RTS -N2 -H 0.19s user 0.03s system 135% cpu 0.165 total<br />
<br />
Given an image like this:<br />
<br />
http://i.imgur.com/iu4gV.png<br />
<br />
The desaturated result from Haskell:<br />
<br />
http://i.imgur.com/REhA5.png<br />
<br />
[[Category:Libraries]]<br />
[[Category:Packages]]<br />
[[Category:Performance]]<br />
[[Category:Tutorials]]<br />
[[Category:Parallel]]</div>Tanimotohttps://wiki.haskell.org/Haskell_mode_for_EmacsHaskell mode for Emacs2009-10-25T16:58:11Z<p>Tanimoto: Copied setup section from README</p>
<hr />
<div>haskell-mode is a major mode for Emacs and XEmacs specifically for writing Haskell code. You can get haskell-mode from the web page: http://projects.haskell.org/haskellmode-emacs/ or on Debian you can type <code>apt-get install haskell-mode</code> (although this currently doesn't have the latest version). It is currently maintained by Svein Ove Aas[http://www.mail-archive.com/haskell-cafe@haskell.org/msg66300.html].<br />
<br />
==Development Version==<br />
<br />
<code><br />
$ darcs get http://code.haskell.org/haskellmode-emacs/<br />
</code><br />
<br />
==Setup==<br />
<br />
Download and unpack the basic mode and modules into a suitable directory, e.g. <code>~/lib/emacs/haskell-mode/</code> where <code>~</code> stands for your home directory.<br />
<br />
Assuming you have placed the basic mode haskell-mode.el and the modules you want to use in the directory <code>~/lib/emacs/haskell-mode/</code>, add the following command to your init file (<code>~/.emacs</code>):<br />
<br />
<code><br />
(load "~/lib/emacs/haskell-mode/haskell-site-file")<br />
</code><br />
<br />
adding the following lines according to which modules you want to use:<br />
<br />
<code><br />
(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)<br />
(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)<br />
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)<br />
;;(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)<br />
</code><br />
<br />
Note that the three indentation modules are mutually exclusive - add at most one. Note that the line of code for simple indentation is commented out (using a preceding ;) in preference for the more advanced indentation module. Installation is now complete!<br />
<br />
==== Inferior Mode ====<br />
<br />
Normally, inf-haskell automatically finds ghci or hugs in your <code>PATH</code>, but if that's not the case (common under Windows), or if you need to specify your preference, just tell Emacs which executable to use with:<br />
<br />
<code><br />
(setq haskell-program-name "/some/where/ghci.exe")<br />
</code><br />
<br />
If you want to use different settings when you use Cygwin Emacs and NTEmacs,<br />
you can test the value of `system-type':<br />
<br />
<code><br />
(setq haskell-program-name<br />
(if (eq system-type 'cygwin)<br />
"/cygdrive/c/ghc/ghc-6.8.1/bin/ghcii.sh"<br />
"c:/ghc/ghc-6.8.1/bin/ghci.exe"))<br />
</code><br />
<br />
Note that Cygwin binaries tend to interact poorly with NTEmacs, especially<br />
w.r.t signal-handling.<br />
<br />
==Tips and use==<br />
Handy keybindings in haskell-mode. See the documentation <code>C-h m</code> for more information:<br />
*<code>C-c C-=</code> inserts an = sign and lines up type signatures and other pattern matches nicely.<br />
*<code>C-c C-|</code> inserts a guard<br />
*<code>C-c C-o</code> inserts a guard <hask>| otherwise =</hask> and lines up existing guards<br />
*<code>C-c C-w</code> inserts a where keyword<br />
*<code>C-c C-.</code> aligns code over a region in a "sensible" fashion.<br />
<br />
Now in version 2.2:<br />
*<code>C-c C-t</code> gets :type for symbol at point, and remembers it<br />
*<code>C-u C-c C-t</code> inserts a type annotation, for symbol at point, on the line above<br />
*<code>C-c C-i</code> gets :info for symbol at point<br />
*<code>C-c M-.</code> find definition of (interpreted) symbol at point<br />
<br />
(See the section below on [[#inf-haskell.el:_the_best_thing_since_the_breadknife|inf-haskell]].)<br />
<br />
Here's an example for <code>C-c C-=</code>. Put your cursor after myInt and hit <code>C-c C-=</code><br />
<haskell><br />
blah :: Int -> Int<br />
blah myInt<br />
</haskell><br />
note how the function signature is reindented to match the column of the = sign.<br />
<haskell><br />
blah :: Int -> Int<br />
blah myInt =<br />
</haskell><br />
<br />
You could also achieve the same effect by selecting the region and typing <code>C-c C-.</code><br />
<br />
You can also use Haskell-Mode to load Emacs buffers with Haskell code in either Hugs or GHC. To load something in Hugs or ghci, type <code>C-c C-l</code> to load the file. Then, you can go on to type <code>C-c C-r</code> (or simply <code>C-c C-l</code> again) to reload the current module when you have made a change.<br />
<br />
=== Indentation ===<br />
Indentation is one thing that nearly all programming modes provide. However, indenting Haskell code is very hard: for a given line, there are nearly always more than column for which indentation makes sense. For example, imagine the following is open in a haskell-mode buffer, where <code>!</code> represents the point:<br />
<br />
<haskell><br />
foo :: Int -> String<br />
foo 0 = f 4 ++ s<br />
where f 4 = "hello" ++ <br />
!<br />
</haskell><br />
<br />
If you ask haskell-mode to indent for you, where should it indent to? There are four basic options:<br />
<br />
<ol><br />
<li><br />
You want to finish off the expression you were writing in the last line. Haskell-mode indents to be underneath the <code>"</code> character at the beginning of <code>"hello"</code>:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
This is debatably a bad choice as you'd probably want to indent a bit further in to make it clear that you were carrying on an expression, but the layout rule would accept something like the following:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
"world"<br />
</haskell><br />
<br />
</li><br />
<li><br />
You want to add a second equation for <code>f</code>. Haskell-mode will indent to line up with the first argument, and fill in the <code>f</code> in the equation:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
f !<br />
</haskell><br />
<br />
This is an unlikely choice as the expression in the previous line isn't complete, but haskell-mode isn't smart enough to know that. (If <code>f</code> had been something without arguments, like <hask>where f = "hello"</hask>, then it's impossible to have more than one equation and haskell-mode won't offer this indentation level.)<br />
</li><br />
<li><br />
You want to add a second binding to the <code>where</code>-block. Haskell-mode indents to line up with the <code>f</code>:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
</li><br />
<li>You want to start an entirely new top-level binding. Haskell-mode indents to the first column:<br />
<br />
<haskell><br />
foo :: Int -> String<br />
foo 0 = f 4 ++ s<br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
</li><br />
</ol><br />
<br />
These four locations can be reached by repeatedly pressing <code>TAB</code>. This is what's known as the tab-cycle. The innermost location is offered first, then cycling progresses outwards. Although this may seem like an inefficient system (and it is indeed a shame that Haskell's design didn't result in an unambiguous indentation system), you do quickly get used to the tab-cycle and indenting Haskell code.<br />
<br />
==== indent-region ====<br />
Using indent-region is generally a bad idea on Haskell code, because it would need to know which of the tab-cycle stops you wish to choose for each line. The innermost one is chosen in each case, which often results in unusable code. Moral: just don't use indent-region with haskell-mode.<br />
<br />
==== Unicodifying symbols (Pretty Lambda for Haskell-mode) ====<br />
In Haskell code, you can end up using a lot of mathematical symbols. It is possible to hack the fontifying features of Emacs to change the ASCII textual representations of arrows and operators into the nice-looking real symbols, much like you could with TeX. The following code is a compilation of Emacs lisp code found on the Emacs wiki on the [http://www.emacswiki.org/cgi-bin/wiki/PrettyLambda#toc4 Pretty Lambda] page (that page also has examples of how to apply the general Unicode defuns to other languages):<br />
<br />
HOWEVER: due to the symbols taking up less space, this has the unfortunate side effect of changing the indentation stops that the indent key offers. This will mean that your code may not look properly aligned to those who do not have this feature in their editor, or could even mean that your code means something different to how it looks. (It is possible to contrive an example that looks correct in emacs, but actually fails to compile). The following is left for interest, but probably should NOT be used.<br />
<br />
Haskell-mode has included this feature for a long time now, so you probably just need to <code>(setq haskell-font-lock-symbols t)</code> in your .emacs to use this feature.<br />
<br />
<code><br />
(defun unicode-symbol (name)<br />
"Translate a symbolic name for a Unicode character -- e.g., LEFT-ARROW <br />
or GREATER-THAN into an actual Unicode character code. "<br />
(decode-char 'ucs (case name <br />
('left-arrow 8592)<br />
('up-arrow 8593)<br />
('right-arrow 8594)<br />
('down-arrow 8595) <br />
('double-vertical-bar #X2551) <br />
('equal #X003d)<br />
('not-equal #X2260)<br />
('identical #X2261)<br />
('not-identical #X2262)<br />
('less-than #X003c)<br />
('greater-than #X003e)<br />
('less-than-or-equal-to #X2264)<br />
('greater-than-or-equal-to #X2265) <br />
('logical-and #X2227)<br />
('logical-or #X2228)<br />
('logical-neg #X00AC) <br />
('nil #X2205)<br />
('horizontal-ellipsis #X2026)<br />
('double-exclamation #X203C)<br />
('prime #X2032)<br />
('double-prime #X2033)<br />
('for-all #X2200)<br />
('there-exists #X2203)<br />
('element-of #X2208) <br />
('square-root #X221A)<br />
('squared #X00B2)<br />
('cubed #X00B3) <br />
('lambda #X03BB)<br />
('alpha #X03B1)<br />
('beta #X03B2)<br />
('gamma #X03B3)<br />
('delta #X03B4))))<br />
<br />
(defun substitute-pattern-with-unicode (pattern symbol)<br />
"Add a font lock hook to replace the matched part of PATTERN with the <br />
Unicode symbol SYMBOL looked up with UNICODE-SYMBOL."<br />
(interactive)<br />
(font-lock-add-keywords<br />
nil `((,pattern <br />
(0 (progn (compose-region (match-beginning 1) (match-end 1)<br />
,(unicode-symbol symbol)<br />
'decompose-region)<br />
nil))))))<br />
<br />
(defun substitute-patterns-with-unicode (patterns)<br />
"Call SUBSTITUTE-PATTERN-WITH-UNICODE repeatedly."<br />
(mapcar #'(lambda (x)<br />
(substitute-pattern-with-unicode (car x)<br />
(cdr x)))<br />
patterns))<br />
<br />
(defun haskell-unicode ()<br />
(interactive)<br />
(substitute-patterns-with-unicode<br />
(list (cons "\\(<-\\)" 'left-arrow)<br />
(cons "\\(->\\)" 'right-arrow)<br />
(cons "\\(==\\)" 'identical)<br />
(cons "\\(/=\\)" 'not-identical)<br />
(cons "\\(()\\)" 'nil)<br />
(cons "\\<\\(sqrt\\)\\>" 'square-root)<br />
(cons "\\(&&\\)" 'logical-and)<br />
(cons "\\(||\\)" 'logical-or)<br />
(cons "\\<\\(not\\)\\>" 'logical-neg)<br />
(cons "\\(>\\)\\[^=\\]" 'greater-than)<br />
(cons "\\(<\\)\\[^=\\]" 'less-than)<br />
(cons "\\(>=\\)" 'greater-than-or-equal-to)<br />
(cons "\\(<=\\)" 'less-than-or-equal-to)<br />
(cons "\\<\\(alpha\\)\\>" 'alpha)<br />
(cons "\\<\\(beta\\)\\>" 'beta)<br />
(cons "\\<\\(gamma\\)\\>" 'gamma)<br />
(cons "\\<\\(delta\\)\\>" 'delta)<br />
(cons "\\(<nowiki>''</nowiki>\\)" 'double-prime)<br />
(cons "\\('\\)" 'prime)<br />
(cons "\\(!!\\)" 'double-exclamation)<br />
(cons "\\(\\.\\.\\)" 'horizontal-ellipsis))))<br />
<br />
(add-hook 'haskell-mode-hook 'haskell-unicode)</code><br />
<br />
== Bugs ==<br />
Bugs and feature requests should be sent to the maintainer [mailto:svein.ove@aas.no Svein Ove Aas].<br />
For people using the Debian package, Debian maintains a [http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=haskell-mode list of bugs] for haskell-mode, they should be reported there.<br />
<br />
===XEmacs===<br />
On some the GNU/Linux systems with XEmacs, admittedly, only verified on Ubuntu and Debian and with haskell-mode 2.2, there is a system function missing that interferes with automatic indenting. Secondly, there seems to be an issue with setting the <code-lisp>haskell-default-face</code-lisp> to <code-lisp>nil</code-lisp>.<br />
<br />
====line-end-position====<br />
<br />
To fix this, find where the haskell mode package is installed on your system. (Usually <code>/usr/share/emacs/site-lisp/haskell-mode</code>). Edit the file <code>haskell-indent.el</code> and add the lines:<br />
<pre-lisp><br />
(eval-and-compile<br />
<br />
;; If `line-end-position' isn't available provide one.<br />
(unless (fboundp 'line-end-position)<br />
(defun line-end-position (&optional n)<br />
"Return the `point' of the end of the current line."<br />
(save-excursion<br />
(end-of-line n)<br />
(point)))))<br />
</pre-lisp><br />
right after the comments at the top. That should fix the issue.<br />
<br />
====haskell-default-face====<br />
<br />
This one shows up when typing in code (at various spots - most often when typing a qualified function, such as <hask>List.map</hask>.)<br />
<br />
To fix this one, edit the file <code>haskell-font-lock.el</code>. Look for the line that says:<br />
<pre-lisp><br />
(defvar haskell-default-face nil)<br />
</pre-lisp><br />
and change this to <br />
<pre-lisp><br />
(defvar haskell-default-face 'default)<br />
</pre-lisp><br />
In my version, this is line 168.<br />
<br />
Then, look for the line that says:<br />
<pre-lisp><br />
(,qvarid 0 haskell-default-face)<br />
</pre-lisp><br />
and change it to<br />
<pre-lisp><br />
(,qvarid 0 (symbol-value 'haskell-default-face))<br />
</pre-lisp><br />
<br />
For me, this is line 326 of the file.<br />
YMMV - hope this helps.<br />
<br />
<!--<br />
=== GNU Emacs ===<br />
<br />
==== ghci buffer infested with "^J"s, C-c C-t doesn't work ====<br />
<br />
(only happens after loading a haskell file into ghci)<br />
<br />
--><br />
<br />
<br />
== inf-haskell.el: the best thing since the breadknife ==<br />
inf-haskell.el is _awesome_. At one point I decided to sit down and write a list of functions I'd love to have in haskell-mode, intending to write them myself. I thought I'd check to see whether the key shortcuts I'd chosen were free but I was surprised to find that ''every one'' of these functions is already provided by inf-haskell.el! Here's a selection of the highlights:<br />
<br />
<br />
=== Getting set up ===<br />
inf-haskell.el is usually already setup as part of the haskell-mode package, so there is nothing special to do for it. On some systems, you may need this in your .emacs:<br />
<br />
<pre-lisp><br />
(require 'inf-haskell)<br />
</pre-lisp><br />
<br />
To use the following functions, first find a .hs file, then hit C-c C-l (inferior-haskell-load-file). This fires up Hugs or Ghci (you can change this by customising haskell-program-name) on your file. Don't worry if it's not an isolated module, GHCi will load all the modules it imports as normal. You can even load entire programs this way by using C-c C-l on the Main.hs file. If everything loads without errors, you'll be able to use the functions below.<br />
<br />
=== inferior-haskell-type (C-c C-t) ===<br />
Say you have the following code:<br />
<br />
foo = foldr (+) 0 [1..20]<br />
<br />
Perhaps you've forgotten the order of arguments to foldr. It's easily done; I can never remember whether the operation or final value comes first. That's easy to check: just put your point between the 'f' and 'r' of 'foldr' and hit C-c C-t RET. The type of foldr will be revealed in the echo area. This isn't particularly impressive; haskell-doc.el already did this. However, this will work for ''any'' function in the module in question ''or'' in those modules imported by the current module (including the standard libs)!<br />
<br />
If you find that the type shown in the echo area is overwritten after a short amount of time (or any other such problem, of course), please report it as a bug. We know of no such bug, but someone apparently bumped into some such problem which he says he worked around by disabling doc-mode and decl-scan:<br />
<br />
To turn off haskell-doc-mode, add the following to your .emacs:<br />
<pre-lisp><br />
(remove-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)<br />
</pre-lisp><br />
To turn off haskell-decl-scan, just refrain from turning it on (it's not enabled by default).<br />
<br />
(P.S. I re-use haskell-doc-mode to save queried type info, and re-display it in the minibuffer. Disabling doc mode would disable that. -- mrd)<br />
<br />
Another nice feature of this function is the ability to automatically insert type signatures for the function at point on the line above. For example, suppose you have the below open in Emacs, with the point represented by -!-:<br />
<br />
-!-map _ [] = []<br />
map f (x:xs) = f x : map f xs<br />
<br />
And press C-u C-c C-t (note the prefix argument), it will result in the following:<br />
<br />
map :: (a -> b) -> [a] -> [b]<br />
-!-map _ [] = []<br />
map f (x:xs) = f x : map f xs<br />
<br />
=== inferior-haskell-info (C-c C-i) ===<br />
The :info command in GHCi/Hugs is extremely useful; it'll tell you:<br />
<br />
* The definition of an algebraic datatype given its name. E.g. try <code>:info Bool</code>. The output will contain something like <code>data Bool = True | False</code>.<br />
* The classes a type instantiates given the type's name. <code>:info Bool</code> will also give you the classes Bool instantiates. If you can't see an instance you think should be there, make sure the module where that instance is declared is loaded.<br />
* The type of a function, given its name.<br />
* The types of the methods of a class, and the number of arguments of that class, given the class name.<br />
* The expansion of a type synonym given that synonym's name.<br />
<br />
And for all of the above, :info will also tell you the filename and line where that thing is defined. inferior-haskell-info lets you hook into this power. Use it with C-c C-i on anything within a Haskell file.<br />
<br />
=== inferior-haskell-find-definition (C-c M-.) ===<br />
This one needs little explanation. Sometimes you just need to find the source of a function, or datatype, or class, or type synonym etc. to see how it works, and this function lets you do just that. Unfortunately, it won't work on the standard lib modules or anything that isn't 'local' to your project. This is one of the most useful functions inf-haskell.el provides.<br />
<br />
(Basically, it only works on interpreted code, for which ghci has location information. If you want a more general find-definition, use hasktags to create a TAGS file and then use the normal emacs <code>M-.</code> with that. -- mrd)<br />
: Note that you can also create a TAGS file using GHCi's :etags command. [[User:DavidHouse|DavidHouse]] 14:38, 29 April 2007 (UTC)<br />
<br />
: Again, :etags/:ctags only works for interpreted code.<br />
<br />
== Tricks and tweaks ==<br />
<br />
=== Automatic unit testing ===<br />
Here's a cute trick I've evolved:<br />
<br />
I'm a great fan of [[unit test first]], as described by eXtremeProgramming on TheOriginalWiki.<br />
<br />
With the code below, I can press F12 and immediately run all of my unit tests, and immediately see whether they all passed or not.<br />
I've put all of my unit tests into their own file with a main function that runs the tests and gives an exitcode according to the test results. I've specified that the compile-command for that file compiles and runs the file.<br />
<br />
This elisp code will run the <code>compile</code> command from the F12 key in emacs. The output will popup a new window twelve lines tall. If the compilation is successful (exitcode zero) the window goes away. If the exitcode is 1 or greater, the window stays so you can see the output.<br />
<pre-lisp><br />
(require 'compile)<br />
<br />
;; this means hitting the compile button always saves the buffer<br />
;; having to separately hit C-x C-s is a waste of time<br />
(setq mode-compile-always-save-buffer-p t)<br />
;; make the compile window stick at 12 lines tall<br />
(setq compilation-window-height 12)<br />
<br />
;; from enberg on #emacs<br />
;; if the compilation has a zero exit code, <br />
;; the windows disappears after two seconds<br />
;; otherwise it stays<br />
(setq compilation-finish-function<br />
(lambda (buf str)<br />
(unless (string-match "exited abnormally" str)<br />
;;no errors, make the compilation window go away in a few seconds<br />
(run-at-time<br />
"2 sec" nil 'delete-windows-on<br />
(get-buffer-create "*compilation*"))<br />
(message "No Compilation Errors!"))))<br />
<br />
<br />
;; one-button testing, tada!<br />
(global-set-key [f12] 'compile)<br />
</pre-lisp><br />
<br />
<br />
This Haskell code has some Emacs local variable settings at the bottom specifying what the compile-command should be for this buffer.<br />
<haskell><br />
import HUnit<br />
import System<br />
<br />
myTestList = <br />
TestList [<br />
"add numbers" ~: 5 ~=? (3 + 2)<br />
,"add numbers" ~: 5 ~=? (3 + 3)<br />
]<br />
<br />
h = runTestTT myTestList<br />
<br />
main = do c <- h<br />
putStr $ show c<br />
let errs = errors c<br />
fails = failures c<br />
System.exitWith (codeGet errs fails)<br />
<br />
codeGet errs fails<br />
| fails > 0 = ExitFailure 2<br />
| errs > 0 = ExitFailure 1<br />
| otherwise = ExitSuccess<br />
<br />
-- Local Variables:<br />
-- compile-command: "ghc --make -o Test_Demo -i/home/shae/src/haskell/libraries/ HUnitDemo.hs && ./Test_Demo"<br />
-- End:<br />
</haskell><br />
<br />
<br />
If you have any questions, ideas, or suggestions for this code, the maintainer would love to hear them.<br />
<br />
=== Hoogle integration ===<br />
From haskell-mode version 2.4 onwards, the built-in function haskell-hoogle will hoogle the identifier at point.<br />
<br />
=== Using rectangular region commands ===<br />
<br />
Emacs has a set of commands which operate on the region as if it were rectangular. This turns out to be extremely useful when dealing with whitespace sensitive languages.<br />
<br />
<code>C-x r o</code> is "Open Rectangle". It will shift any text within the rectangle to the right side. Also see:<br />
<br />
<code>C-x r t</code> is "String Rectangle". It will shift any text within the rectangle over to the right, and insert a given string prefixing all the lines in the region. If comment-region didn't already exist, you could use this instead, for example.<br />
<br />
<code>C-x r d</code> is "Delete Rectangle". It will delete the contents of the rectangle and move anything on the right over.<br />
<br />
<code>C-x r r</code> is "Copy Rectangle to Register". It will prompt you for a register number so it can save it for later.<br />
<br />
<code>C-x r g</code> is "Insert register". This will insert the contents of the given register, overwriting whatever happens to be within the target rectangle. (So make room)<br />
<br />
<code>C-x r k</code> is "Kill rectangle". Delete rectangle and save contents for:<br />
<br />
<code>C-x r y</code> is "Yank rectangle". This will insert the contents of<br />
the last killed rectangle.<br />
<br />
As with all Emacs modifier combos, you can type <code>C-x r C-h</code> to find out what keys are bound beginning with the <code>C-x r</code> prefix.<br />
<br />
=== Aligning code ===<br />
<br />
Emacs22 has a neat tool called: align-regexp. Select a region you want to align text within, M-x align-regexp, and type a regexp representing the alignment delimiter.<br />
<br />
For example, I often line up my Haddock comments:<br />
<br />
<haskell><br />
f :: a -- ^ does a<br />
-> Foo b -- ^ and b<br />
-> c -- ^ to c<br />
</haskell><br />
<br />
Select the region, and let the regexp be: <code>--</code><br />
<br />
<haskell><br />
f :: a -- ^ does a<br />
-> Foo b -- ^ and b<br />
-> c -- ^ to c<br />
</haskell><br />
<br />
Of course, this works for just about anything. Personally, I've globally bound it to <code>C-x a r</code>:<br />
<br />
<code>(global-set-key (kbd "C-x a r") 'align-regexp)</code>.<br />
<br />
=== Automatically building ===<br />
Emacs 21 has a package that can be installed (included by default in 22 and up) called 'FlyMake'; the idea is that as you are editing away, it occasionally calls the interpreter/compiler automatically and keeps track of whether the code works or not. You can fairly easily get it to work for Haskell as well; see [http://www.emacswiki.org/cgi-bin/wiki/FlymakeHaskell FlymakeHaskell] on the Emacs wiki.<br />
<br />
=== Emacs Integration with Hayoo ===<br />
<br />
My newly installed system would not allow me to hoogle what I wanted (no xmonad or xmonadcontrib in hoogle) so someone suggested Hayoo.<br />
<br />
<code><br />
(define-key haskell-mode-map (kbd "<f3>") (lambda()(interactive)(browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s&start" (region-or-word-at-point)))))<br />
</code><br />
<br />
region-or-word-at-point is available in the thing-at-pt+.el library.<br />
<br />
Added 22-12-2008 - Promt for hayoo word<br />
<br />
<code><br />
(defun rgr/hayoo()<br />
(interactive)<br />
(let* ((default (region-or-word-at-point))<br />
(term (read-string (format "Hayoo for the following phrase (%s): "<br />
default))))<br />
(let ((term (if (zerop(length term)) default term)))<br />
(browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s&start" term)))))<br />
<br />
<br />
(define-key haskell-mode-map (kbd "<f3>") (lambda()(interactive)(rgr/hayoo)))<br />
</code><br />
<br />
Alteratively use the excellent browse-apropos-url stuff:<br />
<br />
http://www.emacswiki.org/emacs/BrowseAproposURL#toc6<br />
<br />
[http://richardriley.net Richard]<br />
<br />
Note: Using and URL like this should work too and will give better results (not yet tested as I'm not an emacs user):<br />
<br />
<code><br />
http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s<br />
</code><br />
<br />
[[User:Tbh|Tbh]] 00:56, 25 January 2009 (UTC)<br />
<br />
=== Integration with HLint ===<br />
<br />
[http://www-users.cs.york.ac.uk/~ndm/hlint/ HLint] could be used directly from Emacs buffer. There is [http://www.cs.york.ac.uk/fp/darcs/hlint/data/hs-lint.el hs-lint.el] package (in HLint distribution, in the data subdirectory), that allows user to run HLint and navigate through errors, or apply suggestions to the source code.<br />
<br />
This package implements `hs-lint` command, that behaves differently depending on settings. If the `hs-lint-replace-with-suggestions` variable is set to `t`, then it will ask user and apply concrete suggested change to source code, otherwise you'll be able to navigate through list of suggestions with `next-error` command. If the `hs-lint-replace-without-ask` variable is also set to `t`, then all suggestions will applied automatically. <br />
<br />
You can also bind `hs-lint` command to some key (in this example this is `C-c l`) with following code:<br />
<br />
<code><br />
(defun my-haskell-mode-hook ()<br />
(local-set-key "\C-cl" 'hs-lint))<br />
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)<br />
</code><br />
<br />
All settings, described above are available for customization via `hs-lint` customization group.<br />
<br />
[[Category:Development tools]]</div>Tanimotohttps://wiki.haskell.org/Haskell_mode_for_EmacsHaskell mode for Emacs2009-10-25T16:01:37Z<p>Tanimoto: New maintainer, new release</p>
<hr />
<div>haskell-mode is a major mode for Emacs and XEmacs specifically for writing Haskell code. You can get haskell-mode from the web page: http://projects.haskell.org/haskellmode-emacs/ or on Debian you can type <code>apt-get install haskell-mode</code> (although this currently doesn't have the latest version). It is currently maintained by Svein Ove Aas[http://www.mail-archive.com/haskell-cafe@haskell.org/msg66300.html].<br />
<br />
==Development Version==<br />
<br />
<code>$ darcs get http://code.haskell.org/haskellmode-emacs/</code><br />
<br />
==Minimal setup==<br />
<br />
Insert in your ~/.emacs or other appropriate file:<br />
<br />
<code>(load "/path/to/haskell-mode/haskell-site-file")</code><br />
<br />
==Tips and use==<br />
Handy keybindings in haskell-mode. See the documentation <code>C-h m</code> for more information:<br />
*<code>C-c C-=</code> inserts an = sign and lines up type signatures and other pattern matches nicely.<br />
*<code>C-c C-|</code> inserts a guard<br />
*<code>C-c C-o</code> inserts a guard <hask>| otherwise =</hask> and lines up existing guards<br />
*<code>C-c C-w</code> inserts a where keyword<br />
*<code>C-c C-.</code> aligns code over a region in a "sensible" fashion.<br />
<br />
Now in version 2.2:<br />
*<code>C-c C-t</code> gets :type for symbol at point, and remembers it<br />
*<code>C-u C-c C-t</code> inserts a type annotation, for symbol at point, on the line above<br />
*<code>C-c C-i</code> gets :info for symbol at point<br />
*<code>C-c M-.</code> find definition of (interpreted) symbol at point<br />
<br />
(See the section below on [[#inf-haskell.el:_the_best_thing_since_the_breadknife|inf-haskell]].)<br />
<br />
Here's an example for <code>C-c C-=</code>. Put your cursor after myInt and hit <code>C-c C-=</code><br />
<haskell><br />
blah :: Int -> Int<br />
blah myInt<br />
</haskell><br />
note how the function signature is reindented to match the column of the = sign.<br />
<haskell><br />
blah :: Int -> Int<br />
blah myInt =<br />
</haskell><br />
<br />
You could also achieve the same effect by selecting the region and typing <code>C-c C-.</code><br />
<br />
You can also use Haskell-Mode to load Emacs buffers with Haskell code in either Hugs or GHC. To load something in Hugs or ghci, type <code>C-c C-l</code> to load the file. Then, you can go on to type <code>C-c C-r</code> (or simply <code>C-c C-l</code> again) to reload the current module when you have made a change.<br />
<br />
=== Indentation ===<br />
Indentation is one thing that nearly all programming modes provide. However, indenting Haskell code is very hard: for a given line, there are nearly always more than column for which indentation makes sense. For example, imagine the following is open in a haskell-mode buffer, where <code>!</code> represents the point:<br />
<br />
<haskell><br />
foo :: Int -> String<br />
foo 0 = f 4 ++ s<br />
where f 4 = "hello" ++ <br />
!<br />
</haskell><br />
<br />
If you ask haskell-mode to indent for you, where should it indent to? There are four basic options:<br />
<br />
<ol><br />
<li><br />
You want to finish off the expression you were writing in the last line. Haskell-mode indents to be underneath the <code>"</code> character at the beginning of <code>"hello"</code>:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
This is debatably a bad choice as you'd probably want to indent a bit further in to make it clear that you were carrying on an expression, but the layout rule would accept something like the following:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
"world"<br />
</haskell><br />
<br />
</li><br />
<li><br />
You want to add a second equation for <code>f</code>. Haskell-mode will indent to line up with the first argument, and fill in the <code>f</code> in the equation:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
f !<br />
</haskell><br />
<br />
This is an unlikely choice as the expression in the previous line isn't complete, but haskell-mode isn't smart enough to know that. (If <code>f</code> had been something without arguments, like <hask>where f = "hello"</hask>, then it's impossible to have more than one equation and haskell-mode won't offer this indentation level.)<br />
</li><br />
<li><br />
You want to add a second binding to the <code>where</code>-block. Haskell-mode indents to line up with the <code>f</code>:<br />
<br />
<haskell><br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
</li><br />
<li>You want to start an entirely new top-level binding. Haskell-mode indents to the first column:<br />
<br />
<haskell><br />
foo :: Int -> String<br />
foo 0 = f 4 ++ s<br />
where f 4 = "hello" ++<br />
!<br />
</haskell><br />
<br />
</li><br />
</ol><br />
<br />
These four locations can be reached by repeatedly pressing <code>TAB</code>. This is what's known as the tab-cycle. The innermost location is offered first, then cycling progresses outwards. Although this may seem like an inefficient system (and it is indeed a shame that Haskell's design didn't result in an unambiguous indentation system), you do quickly get used to the tab-cycle and indenting Haskell code.<br />
<br />
==== indent-region ====<br />
Using indent-region is generally a bad idea on Haskell code, because it would need to know which of the tab-cycle stops you wish to choose for each line. The innermost one is chosen in each case, which often results in unusable code. Moral: just don't use indent-region with haskell-mode.<br />
<br />
==== Unicodifying symbols (Pretty Lambda for Haskell-mode) ====<br />
In Haskell code, you can end up using a lot of mathematical symbols. It is possible to hack the fontifying features of Emacs to change the ASCII textual representations of arrows and operators into the nice-looking real symbols, much like you could with TeX. The following code is a compilation of Emacs lisp code found on the Emacs wiki on the [http://www.emacswiki.org/cgi-bin/wiki/PrettyLambda#toc4 Pretty Lambda] page (that page also has examples of how to apply the general Unicode defuns to other languages):<br />
<br />
HOWEVER: due to the symbols taking up less space, this has the unfortunate side effect of changing the indentation stops that the indent key offers. This will mean that your code may not look properly aligned to those who do not have this feature in their editor, or could even mean that your code means something different to how it looks. (It is possible to contrive an example that looks correct in emacs, but actually fails to compile). The following is left for interest, but probably should NOT be used.<br />
<br />
Haskell-mode has included this feature for a long time now, so you probably just need to <code>(setq haskell-font-lock-symbols t)</code> in your .emacs to use this feature.<br />
<br />
<code><br />
(defun unicode-symbol (name)<br />
"Translate a symbolic name for a Unicode character -- e.g., LEFT-ARROW <br />
or GREATER-THAN into an actual Unicode character code. "<br />
(decode-char 'ucs (case name <br />
('left-arrow 8592)<br />
('up-arrow 8593)<br />
('right-arrow 8594)<br />
('down-arrow 8595) <br />
('double-vertical-bar #X2551) <br />
('equal #X003d)<br />
('not-equal #X2260)<br />
('identical #X2261)<br />
('not-identical #X2262)<br />
('less-than #X003c)<br />
('greater-than #X003e)<br />
('less-than-or-equal-to #X2264)<br />
('greater-than-or-equal-to #X2265) <br />
('logical-and #X2227)<br />
('logical-or #X2228)<br />
('logical-neg #X00AC) <br />
('nil #X2205)<br />
('horizontal-ellipsis #X2026)<br />
('double-exclamation #X203C)<br />
('prime #X2032)<br />
('double-prime #X2033)<br />
('for-all #X2200)<br />
('there-exists #X2203)<br />
('element-of #X2208) <br />
('square-root #X221A)<br />
('squared #X00B2)<br />
('cubed #X00B3) <br />
('lambda #X03BB)<br />
('alpha #X03B1)<br />
('beta #X03B2)<br />
('gamma #X03B3)<br />
('delta #X03B4))))<br />
<br />
(defun substitute-pattern-with-unicode (pattern symbol)<br />
"Add a font lock hook to replace the matched part of PATTERN with the <br />
Unicode symbol SYMBOL looked up with UNICODE-SYMBOL."<br />
(interactive)<br />
(font-lock-add-keywords<br />
nil `((,pattern <br />
(0 (progn (compose-region (match-beginning 1) (match-end 1)<br />
,(unicode-symbol symbol)<br />
'decompose-region)<br />
nil))))))<br />
<br />
(defun substitute-patterns-with-unicode (patterns)<br />
"Call SUBSTITUTE-PATTERN-WITH-UNICODE repeatedly."<br />
(mapcar #'(lambda (x)<br />
(substitute-pattern-with-unicode (car x)<br />
(cdr x)))<br />
patterns))<br />
<br />
(defun haskell-unicode ()<br />
(interactive)<br />
(substitute-patterns-with-unicode<br />
(list (cons "\\(<-\\)" 'left-arrow)<br />
(cons "\\(->\\)" 'right-arrow)<br />
(cons "\\(==\\)" 'identical)<br />
(cons "\\(/=\\)" 'not-identical)<br />
(cons "\\(()\\)" 'nil)<br />
(cons "\\<\\(sqrt\\)\\>" 'square-root)<br />
(cons "\\(&&\\)" 'logical-and)<br />
(cons "\\(||\\)" 'logical-or)<br />
(cons "\\<\\(not\\)\\>" 'logical-neg)<br />
(cons "\\(>\\)\\[^=\\]" 'greater-than)<br />
(cons "\\(<\\)\\[^=\\]" 'less-than)<br />
(cons "\\(>=\\)" 'greater-than-or-equal-to)<br />
(cons "\\(<=\\)" 'less-than-or-equal-to)<br />
(cons "\\<\\(alpha\\)\\>" 'alpha)<br />
(cons "\\<\\(beta\\)\\>" 'beta)<br />
(cons "\\<\\(gamma\\)\\>" 'gamma)<br />
(cons "\\<\\(delta\\)\\>" 'delta)<br />
(cons "\\(<nowiki>''</nowiki>\\)" 'double-prime)<br />
(cons "\\('\\)" 'prime)<br />
(cons "\\(!!\\)" 'double-exclamation)<br />
(cons "\\(\\.\\.\\)" 'horizontal-ellipsis))))<br />
<br />
(add-hook 'haskell-mode-hook 'haskell-unicode)</code><br />
<br />
== Bugs ==<br />
Bugs and feature requests should be sent to the maintainer [mailto:svein.ove@aas.no Svein Ove Aas].<br />
For people using the Debian package, Debian maintains a [http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=haskell-mode list of bugs] for haskell-mode, they should be reported there.<br />
<br />
===XEmacs===<br />
On some the GNU/Linux systems with XEmacs, admittedly, only verified on Ubuntu and Debian and with haskell-mode 2.2, there is a system function missing that interferes with automatic indenting. Secondly, there seems to be an issue with setting the <code-lisp>haskell-default-face</code-lisp> to <code-lisp>nil</code-lisp>.<br />
<br />
====line-end-position====<br />
<br />
To fix this, find where the haskell mode package is installed on your system. (Usually <code>/usr/share/emacs/site-lisp/haskell-mode</code>). Edit the file <code>haskell-indent.el</code> and add the lines:<br />
<pre-lisp><br />
(eval-and-compile<br />
<br />
;; If `line-end-position' isn't available provide one.<br />
(unless (fboundp 'line-end-position)<br />
(defun line-end-position (&optional n)<br />
"Return the `point' of the end of the current line."<br />
(save-excursion<br />
(end-of-line n)<br />
(point)))))<br />
</pre-lisp><br />
right after the comments at the top. That should fix the issue.<br />
<br />
====haskell-default-face====<br />
<br />
This one shows up when typing in code (at various spots - most often when typing a qualified function, such as <hask>List.map</hask>.)<br />
<br />
To fix this one, edit the file <code>haskell-font-lock.el</code>. Look for the line that says:<br />
<pre-lisp><br />
(defvar haskell-default-face nil)<br />
</pre-lisp><br />
and change this to <br />
<pre-lisp><br />
(defvar haskell-default-face 'default)<br />
</pre-lisp><br />
In my version, this is line 168.<br />
<br />
Then, look for the line that says:<br />
<pre-lisp><br />
(,qvarid 0 haskell-default-face)<br />
</pre-lisp><br />
and change it to<br />
<pre-lisp><br />
(,qvarid 0 (symbol-value 'haskell-default-face))<br />
</pre-lisp><br />
<br />
For me, this is line 326 of the file.<br />
YMMV - hope this helps.<br />
<br />
<!--<br />
=== GNU Emacs ===<br />
<br />
==== ghci buffer infested with "^J"s, C-c C-t doesn't work ====<br />
<br />
(only happens after loading a haskell file into ghci)<br />
<br />
--><br />
<br />
<br />
== inf-haskell.el: the best thing since the breadknife ==<br />
inf-haskell.el is _awesome_. At one point I decided to sit down and write a list of functions I'd love to have in haskell-mode, intending to write them myself. I thought I'd check to see whether the key shortcuts I'd chosen were free but I was surprised to find that ''every one'' of these functions is already provided by inf-haskell.el! Here's a selection of the highlights:<br />
<br />
<br />
=== Getting set up ===<br />
inf-haskell.el is usually already setup as part of the haskell-mode package, so there is nothing special to do for it. On some systems, you may need this in your .emacs:<br />
<br />
<pre-lisp><br />
(require 'inf-haskell)<br />
</pre-lisp><br />
<br />
To use the following functions, first find a .hs file, then hit C-c C-l (inferior-haskell-load-file). This fires up Hugs or Ghci (you can change this by customising haskell-program-name) on your file. Don't worry if it's not an isolated module, GHCi will load all the modules it imports as normal. You can even load entire programs this way by using C-c C-l on the Main.hs file. If everything loads without errors, you'll be able to use the functions below.<br />
<br />
=== inferior-haskell-type (C-c C-t) ===<br />
Say you have the following code:<br />
<br />
foo = foldr (+) 0 [1..20]<br />
<br />
Perhaps you've forgotten the order of arguments to foldr. It's easily done; I can never remember whether the operation or final value comes first. That's easy to check: just put your point between the 'f' and 'r' of 'foldr' and hit C-c C-t RET. The type of foldr will be revealed in the echo area. This isn't particularly impressive; haskell-doc.el already did this. However, this will work for ''any'' function in the module in question ''or'' in those modules imported by the current module (including the standard libs)!<br />
<br />
If you find that the type shown in the echo area is overwritten after a short amount of time (or any other such problem, of course), please report it as a bug. We know of no such bug, but someone apparently bumped into some such problem which he says he worked around by disabling doc-mode and decl-scan:<br />
<br />
To turn off haskell-doc-mode, add the following to your .emacs:<br />
<pre-lisp><br />
(remove-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)<br />
</pre-lisp><br />
To turn off haskell-decl-scan, just refrain from turning it on (it's not enabled by default).<br />
<br />
(P.S. I re-use haskell-doc-mode to save queried type info, and re-display it in the minibuffer. Disabling doc mode would disable that. -- mrd)<br />
<br />
Another nice feature of this function is the ability to automatically insert type signatures for the function at point on the line above. For example, suppose you have the below open in Emacs, with the point represented by -!-:<br />
<br />
-!-map _ [] = []<br />
map f (x:xs) = f x : map f xs<br />
<br />
And press C-u C-c C-t (note the prefix argument), it will result in the following:<br />
<br />
map :: (a -> b) -> [a] -> [b]<br />
-!-map _ [] = []<br />
map f (x:xs) = f x : map f xs<br />
<br />
=== inferior-haskell-info (C-c C-i) ===<br />
The :info command in GHCi/Hugs is extremely useful; it'll tell you:<br />
<br />
* The definition of an algebraic datatype given its name. E.g. try <code>:info Bool</code>. The output will contain something like <code>data Bool = True | False</code>.<br />
* The classes a type instantiates given the type's name. <code>:info Bool</code> will also give you the classes Bool instantiates. If you can't see an instance you think should be there, make sure the module where that instance is declared is loaded.<br />
* The type of a function, given its name.<br />
* The types of the methods of a class, and the number of arguments of that class, given the class name.<br />
* The expansion of a type synonym given that synonym's name.<br />
<br />
And for all of the above, :info will also tell you the filename and line where that thing is defined. inferior-haskell-info lets you hook into this power. Use it with C-c C-i on anything within a Haskell file.<br />
<br />
=== inferior-haskell-find-definition (C-c M-.) ===<br />
This one needs little explanation. Sometimes you just need to find the source of a function, or datatype, or class, or type synonym etc. to see how it works, and this function lets you do just that. Unfortunately, it won't work on the standard lib modules or anything that isn't 'local' to your project. This is one of the most useful functions inf-haskell.el provides.<br />
<br />
(Basically, it only works on interpreted code, for which ghci has location information. If you want a more general find-definition, use hasktags to create a TAGS file and then use the normal emacs <code>M-.</code> with that. -- mrd)<br />
: Note that you can also create a TAGS file using GHCi's :etags command. [[User:DavidHouse|DavidHouse]] 14:38, 29 April 2007 (UTC)<br />
<br />
: Again, :etags/:ctags only works for interpreted code.<br />
<br />
== Tricks and tweaks ==<br />
<br />
=== Automatic unit testing ===<br />
Here's a cute trick I've evolved:<br />
<br />
I'm a great fan of [[unit test first]], as described by eXtremeProgramming on TheOriginalWiki.<br />
<br />
With the code below, I can press F12 and immediately run all of my unit tests, and immediately see whether they all passed or not.<br />
I've put all of my unit tests into their own file with a main function that runs the tests and gives an exitcode according to the test results. I've specified that the compile-command for that file compiles and runs the file.<br />
<br />
This elisp code will run the <code>compile</code> command from the F12 key in emacs. The output will popup a new window twelve lines tall. If the compilation is successful (exitcode zero) the window goes away. If the exitcode is 1 or greater, the window stays so you can see the output.<br />
<pre-lisp><br />
(require 'compile)<br />
<br />
;; this means hitting the compile button always saves the buffer<br />
;; having to separately hit C-x C-s is a waste of time<br />
(setq mode-compile-always-save-buffer-p t)<br />
;; make the compile window stick at 12 lines tall<br />
(setq compilation-window-height 12)<br />
<br />
;; from enberg on #emacs<br />
;; if the compilation has a zero exit code, <br />
;; the windows disappears after two seconds<br />
;; otherwise it stays<br />
(setq compilation-finish-function<br />
(lambda (buf str)<br />
(unless (string-match "exited abnormally" str)<br />
;;no errors, make the compilation window go away in a few seconds<br />
(run-at-time<br />
"2 sec" nil 'delete-windows-on<br />
(get-buffer-create "*compilation*"))<br />
(message "No Compilation Errors!"))))<br />
<br />
<br />
;; one-button testing, tada!<br />
(global-set-key [f12] 'compile)<br />
</pre-lisp><br />
<br />
<br />
This Haskell code has some Emacs local variable settings at the bottom specifying what the compile-command should be for this buffer.<br />
<haskell><br />
import HUnit<br />
import System<br />
<br />
myTestList = <br />
TestList [<br />
"add numbers" ~: 5 ~=? (3 + 2)<br />
,"add numbers" ~: 5 ~=? (3 + 3)<br />
]<br />
<br />
h = runTestTT myTestList<br />
<br />
main = do c <- h<br />
putStr $ show c<br />
let errs = errors c<br />
fails = failures c<br />
System.exitWith (codeGet errs fails)<br />
<br />
codeGet errs fails<br />
| fails > 0 = ExitFailure 2<br />
| errs > 0 = ExitFailure 1<br />
| otherwise = ExitSuccess<br />
<br />
-- Local Variables:<br />
-- compile-command: "ghc --make -o Test_Demo -i/home/shae/src/haskell/libraries/ HUnitDemo.hs && ./Test_Demo"<br />
-- End:<br />
</haskell><br />
<br />
<br />
If you have any questions, ideas, or suggestions for this code, the maintainer would love to hear them.<br />
<br />
=== Hoogle integration ===<br />
From haskell-mode version 2.4 onwards, the built-in function haskell-hoogle will hoogle the identifier at point.<br />
<br />
=== Using rectangular region commands ===<br />
<br />
Emacs has a set of commands which operate on the region as if it were rectangular. This turns out to be extremely useful when dealing with whitespace sensitive languages.<br />
<br />
<code>C-x r o</code> is "Open Rectangle". It will shift any text within the rectangle to the right side. Also see:<br />
<br />
<code>C-x r t</code> is "String Rectangle". It will shift any text within the rectangle over to the right, and insert a given string prefixing all the lines in the region. If comment-region didn't already exist, you could use this instead, for example.<br />
<br />
<code>C-x r d</code> is "Delete Rectangle". It will delete the contents of the rectangle and move anything on the right over.<br />
<br />
<code>C-x r r</code> is "Copy Rectangle to Register". It will prompt you for a register number so it can save it for later.<br />
<br />
<code>C-x r g</code> is "Insert register". This will insert the contents of the given register, overwriting whatever happens to be within the target rectangle. (So make room)<br />
<br />
<code>C-x r k</code> is "Kill rectangle". Delete rectangle and save contents for:<br />
<br />
<code>C-x r y</code> is "Yank rectangle". This will insert the contents of<br />
the last killed rectangle.<br />
<br />
As with all Emacs modifier combos, you can type <code>C-x r C-h</code> to find out what keys are bound beginning with the <code>C-x r</code> prefix.<br />
<br />
=== Aligning code ===<br />
<br />
Emacs22 has a neat tool called: align-regexp. Select a region you want to align text within, M-x align-regexp, and type a regexp representing the alignment delimiter.<br />
<br />
For example, I often line up my Haddock comments:<br />
<br />
<haskell><br />
f :: a -- ^ does a<br />
-> Foo b -- ^ and b<br />
-> c -- ^ to c<br />
</haskell><br />
<br />
Select the region, and let the regexp be: <code>--</code><br />
<br />
<haskell><br />
f :: a -- ^ does a<br />
-> Foo b -- ^ and b<br />
-> c -- ^ to c<br />
</haskell><br />
<br />
Of course, this works for just about anything. Personally, I've globally bound it to <code>C-x a r</code>:<br />
<br />
<code>(global-set-key (kbd "C-x a r") 'align-regexp)</code>.<br />
<br />
=== Automatically building ===<br />
Emacs 21 has a package that can be installed (included by default in 22 and up) called 'FlyMake'; the idea is that as you are editing away, it occasionally calls the interpreter/compiler automatically and keeps track of whether the code works or not. You can fairly easily get it to work for Haskell as well; see [http://www.emacswiki.org/cgi-bin/wiki/FlymakeHaskell FlymakeHaskell] on the Emacs wiki.<br />
<br />
=== Emacs Integration with Hayoo ===<br />
<br />
My newly installed system would not allow me to hoogle what I wanted (no xmonad or xmonadcontrib in hoogle) so someone suggested Hayoo.<br />
<br />
<code><br />
(define-key haskell-mode-map (kbd "<f3>") (lambda()(interactive)(browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s&start" (region-or-word-at-point)))))<br />
</code><br />
<br />
region-or-word-at-point is available in the thing-at-pt+.el library.<br />
<br />
Added 22-12-2008 - Promt for hayoo word<br />
<br />
<code><br />
(defun rgr/hayoo()<br />
(interactive)<br />
(let* ((default (region-or-word-at-point))<br />
(term (read-string (format "Hayoo for the following phrase (%s): "<br />
default))))<br />
(let ((term (if (zerop(length term)) default term)))<br />
(browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s&start" term)))))<br />
<br />
<br />
(define-key haskell-mode-map (kbd "<f3>") (lambda()(interactive)(rgr/hayoo)))<br />
</code><br />
<br />
Alteratively use the excellent browse-apropos-url stuff:<br />
<br />
http://www.emacswiki.org/emacs/BrowseAproposURL#toc6<br />
<br />
[http://richardriley.net Richard]<br />
<br />
Note: Using and URL like this should work too and will give better results (not yet tested as I'm not an emacs user):<br />
<br />
<code><br />
http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s<br />
</code><br />
<br />
[[User:Tbh|Tbh]] 00:56, 25 January 2009 (UTC)<br />
<br />
=== Integration with HLint ===<br />
<br />
[http://www-users.cs.york.ac.uk/~ndm/hlint/ HLint] could be used directly from Emacs buffer. There is [http://www.cs.york.ac.uk/fp/darcs/hlint/data/hs-lint.el hs-lint.el] package (in HLint distribution, in the data subdirectory), that allows user to run HLint and navigate through errors, or apply suggestions to the source code.<br />
<br />
This package implements `hs-lint` command, that behaves differently depending on settings. If the `hs-lint-replace-with-suggestions` variable is set to `t`, then it will ask user and apply concrete suggested change to source code, otherwise you'll be able to navigate through list of suggestions with `next-error` command. If the `hs-lint-replace-without-ask` variable is also set to `t`, then all suggestions will applied automatically. <br />
<br />
You can also bind `hs-lint` command to some key (in this example this is `C-c l`) with following code:<br />
<br />
<code><br />
(defun my-haskell-mode-hook ()<br />
(local-set-key "\C-cl" 'hs-lint))<br />
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)<br />
</code><br />
<br />
All settings, described above are available for customization via `hs-lint` customization group.<br />
<br />
[[Category:Development tools]]</div>Tanimotohttps://wiki.haskell.org/IterateeIteratee2009-10-12T04:14:17Z<p>Tanimoto: Page for iteratee's implementation</p>
<hr />
<div>Page about the implementation of Oleg's Iteratee maintained by John Lato.<br />
<br />
== Installing ==<br />
<br />
Iteratee can be installed via cabal:<br />
<br />
<haskell><br />
$ cabal update<br />
$ cabal install iteratee<br />
</haskell><br />
<br />
== Downloading ==<br />
<br />
* [http://hackage.haskell.org/package/iteratee Hackage Package]<br />
* [http://inmachina.net/~jwlato/haskell/iteratee Darcs Repository]<br />
<br />
== Documentation ==<br />
<br />
* [http://hackage.haskell.org/packages/archive/iteratee/latest/doc/html/Data-Iteratee.html Latest API]<br />
* [[/Tutorial|Tutorial]]<br />
* [[/Examples|Examples]]<br />
* [http://inmachina.net/~jwlato/iteratee Future of Iteratee]<br />
<br />
== Resources ==<br />
<br />
=== Original Iteratee ===<br />
<br />
* [http://okmij.org/ftp/Haskell/Iteratee Oleg's Original Implementation]<br />
* [http://okmij.org/ftp/Haskell/Iteratee/DEFUN08-talk-notes.pdf Oleg's Slides]<br />
* [http://okmij.org/ftp/Streams.html Oleg's Page on Streams]<br />
<br />
=== Haskell Wiki ===<br />
<br />
* [[Iteratee_I/O|Entry for Iteratee I/O]]<br />
* [[Enumerator_and_iteratee|Entry for Enumerator and Iteratee]]<br />
<br />
=== Blog Articles ===<br />
<br />
* [http://johnlato.blogspot.com John Lato's Blog]<br />
* [http://comonad.com/reader/2009/iteratees-parsec-and-monoid Iteratees, Parsec and Monoids]<br />
* [http://therning.org/magnus/archives/735 Trying to work out iteratees]<br />
<br />
=== Discussions ===<br />
<br />
* [http://www.mail-archive.com/haskell-cafe@haskell.org/msg45890.html Lazy vs correct IO]<br />
* [http://stackoverflow.com/questions/1319705/introduction-or-simple-examples-for-iteratee Question on StackOverflow]<br />
<br />
=== Videos ===<br />
<br />
* [http://vimeo.com/6573255 Rant about Lazy I/O]<br />
<br />
=== Other Libraries ===<br />
<br />
* [http://hackage.haskell.org/package/Takusen Takusen]<br />
* [http://hackage.haskell.org/package/hyena Hyena]</div>Tanimotohttps://wiki.haskell.org/Simonpj/Talk:FunWithTypeFunsSimonpj/Talk:FunWithTypeFuns2009-07-20T03:40:09Z<p>Tanimoto: more incorrect alignment</p>
<hr />
<div>= Fun with Type Functions =<br />
<br />
Here is Version 2 of our paper:<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/typefun.pdf Fun With Type Functions (version 2)]''', Oleg Kiselyov, Ken Shan, and Simon Peyton Jones<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/FunWithTypeFuns-Apr09.pdf Slides (PDF)]'''<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/fun-with-type-funs.zip Source code]'''<br />
<br />
which will appear in the proceedings of Tony Hoare's 75th birthday celebration.<br />
<blockquote><br />
'''Abstract'''. Tony Hoare has always been a leader in writing down and proving<br />
properties of programs. To prove properties of programs automatically,<br />
the most widely used technology today is by far the ubiquitous type checker.<br />
Alas, static type systems inevitably exclude some good programs<br />
and allow some bad ones. This dilemma motivates us to describe some fun we've<br />
been having with Haskell, by making the type system more expressive<br />
without losing the benefits of automatic proof and compact expression.<br />
<p><br />
Haskell's type system extends Hindley-Milner with two distinctive<br />
features: polymorphism over type constructors and overloading<br />
using type classes. These features have been integral to Haskell<br />
since its beginning, and they are widely used and appreciated. More recently, Haskell has been enriched with<br />
''type families'', or ''associated types'', <br />
which allows functions on types to be<br />
expressed as straightforwardly as functions on values. This facility<br />
makes it easier for programmers to effectively extend the compiler by<br />
writing functional programs that execute during type-checking.<br />
</p><p><br />
This paper gives a programmer's tour of type families as they are<br />
supported in GHC today.<br />
</p></blockquote><br />
<br />
This Wiki page is a discussion page for the paper. If you are kind enough to read this paper, please help us by jotting down any thoughts it triggers off. Things to think about:<br />
* What is unclear?<br />
* What is omitted that you'd like to see?<br />
* Do you have any cool examples that are of a somewhat different character than the ones we describe? (If so, do explain the example on this page!)<br />
<br />
You can identify your entries by preceding them with four tildes. Doing so adds your name, and the date. Thus:<br />
<br />
:[[User:Simonpj|Simonpj]] 08:42, 19 April 2007 (UTC) Note from Simon<br />
<br />
If you say who you are in this way, we'll be able to acknowledge your help in a revised version of the paper.<br />
<br />
------------------------<br />
Add comments here (newest at the top):<br />
<br />
[[User:Tanimoto|tanimoto]] 03:38, 20 July 2009 (UTC) Comments not aligned correctly<br />
<br />
In Appendix A, item 1, "ILLEGAL" and "OK" could be aligned with the previous comments.<br />
<br />
In Appendix A, item 3, type T5, "OK" is not aligned with the previous comments. The same goes for the signature.<br />
<br />
Some code snippets go off the right margin, I hope it's not a problem: pp. 10, 17, 18, 25, 35, 37.<br />
<br />
<br />
[[User:Bens|bens]] 01:13, 20 July 2009 (UTC) In Appendix C, "fmt1 ^ fmt2 = fmt1 ++ \x -> fmt2 x" -> "fmt1 ^ fmt2 = \x -> fmt1 ++ fmt2 x".<br />
<br />
[[User:BobAtkey|BobAtkey]] 17:39, 9 July 2009 (UTC) Could you update the reference to my "Parameterised Notions of Computation" paper to the journal version? Thanks: Robert Atkey. Parameterised Notions of Computation. Journal of Functional Programming 19: (3 & 4), pages 355-376, July 2009.<br />
<br />
[[User:Mvanier|Mvanier]] 03:14, 3 July 2009 (UTC) The source code link seems to be dead. '''SLPJ: fixed'''<br />
<br />
<br />
-------------------------<br />
'''Stuff below here refers to [http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/typefun-v1.pdf Version 1 of the paper], now retired.'''<br />
-------------------------<br />
<br />
[[User:Oleg|Oleg]] 02:55, 3 June 2009 (UTC) <br />
<br />
Thank you indeed for all the comments and suggestions!<br />
<br />
i have dealt with all the comments and fixed all the noted problems. I<br />
have a few questions about several suggestions though. I should remark<br />
first that the complete code discussed in the paper is available,<br />
presently in our darcs repository. I guess Simon has not decided of a<br />
site to host the online version of the paper with the Appendices and<br />
the code. Incidentally, code fragments in the paper are lifted<br />
straight from the working code, using the remarkably useful<br />
\VerbatimInput.<br />
<br />
--------------------------------------<br />
<br />
[[User:Byorgey|Byorgey]] 20:07, 19 May 2009 (UTC) <br />
* p. 32:<br />
** "powerful, but the" -> "powerful, but they"<br />
* p. 33: <br />
** "commonly mentioned on Haskell mailing lists pitfall of type functions" -> "one pitfall of type functions commonly mentioned..."<br />
** "the compiler should chose" -> "should the compiler choose"<br />
<br />
[[User:bjpop|BerniePope]] 06:18, Fri 15 May 2009 (UTC) Typo in Appendix B.<br />
<br />
"GHC should noat" -> "GHC should not"<br />
<br />
[[User:Tanimoto|tanimoto]] 02:17, 15 May 2009 (UTC) Typo in references<br />
<br />
In reference [32], page 30, Oleg's last name is misspelled as "Kiselov".<br />
<br />
<br />
[[User:Ryani|Ryani]] 23:01, 14 May 2009 (UTC) Fun paper! Comments:<br />
<br />
I was writing a generic finite map a while ago and determined that the generic memoized trie was better in almost all cases; it was simpler semantically and didn't have a significant performance difference. Then you have "type Map k v = Table k (Maybe v)". Is it worth calling out this special case in its own section?<br />
<br />
Also, in respose to ChrisKuklewicz, I think the type for "cons" is correct, but perhaps one instance should be given as an example.<br />
<br />
'''To Ryan Ingram''': Just to double-check: you are saying that the<br />
implementation of generic finite maps as <br />
"type Map k v = Table k (Maybe v)" is faster that the one given in Sec<br />
3.3? That is quite interesting!<br />
<br />
<br />
<br />
[[User:Dave Menendez|Dave Menendez]] 16:52, 14 May 2009 (UTC) On page 11, you refer to a "specialised instance for Table Int that uses some custom <br />
(but innite!) tree representation for Int." Was this meant to be Integer? Surely any tree representation for Int would be large but finite. <br />
<br />
-------------------<br />
Peter Verswyvelen and I have been working on some type family fun to give us generalised partial application (even to the point of being able to cope with giving arguments, but not a function). I don't know if it really makes any interesting point that you didn't already in the paper, but it's certainly fun...<br />
<br />
<haskell><br />
{-# LANGUAGE TypeFamilies, EmptyDataDecls, TypeOperators, FlexibleInstances, FlexibleContexts #-}<br />
<br />
module Burn2 where<br />
<br />
newtype V a = V a -- A value<br />
data B a = B -- A value we don't want to provide yet<br />
<br />
-- Type level homogenous lists (well just tuples in a list-like syntax really)<br />
data Nil a = Nil<br />
data a :& b = !a :& !b<br />
<br />
infixr 5 :& <br />
<br />
class Apply funargs where<br />
type Result funargs :: *<br />
apply :: funargs -> Result funargs<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& V c :& rest) where<br />
type Result (V (a->b) :& V c :& rest) = Result (V b :& rest)<br />
apply (V f :& V a :& rest) = apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& V c :& rest) where<br />
type Result (B (a->b) :& V c :& rest) = (a->b) -> Result (V b :& rest)<br />
apply (B :& V a :& rest) = \f -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& B c :& rest) where<br />
type Result (V (a->b) :& B c :& rest) = a -> Result (V b :& rest)<br />
apply (V f :& B :& rest) = \a -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& B c :& rest) where<br />
type Result (B (a->b) :& B c :& rest) = (a->b) -> a -> Result (V b :& rest)<br />
apply (B :& B :& rest) = \f a -> apply $ V (f a) :& rest<br />
<br />
instance Apply (V a :& Nil b) where<br />
type Result (V a :& Nil b) = a<br />
apply (V a :& Nil) = a<br />
<br />
instance Apply (B a :& Nil b) where<br />
type Result (B a :& Nil b) = B a<br />
apply (B :& Nil) = B<br />
<br />
v1 = apply (V 1 :& Nil)<br />
f1 = apply (B :& Nil)<br />
v2 = apply (V negate :& V 1 :& Nil)<br />
f3 = apply (V negate :& B :& Nil)<br />
v3 = apply (V f3 :& V 1 :& Nil)<br />
</haskell><br />
<br />
[[User:Beelsebob|Beelsebob]] 13:04, 14 May 2009 (UTC)<br />
<br />
'''To Beelsebob''': I'm afraid the code does not account for the most<br />
interesting case: a function that takes a dynamic value and returns<br />
a static result. So you need to deal with functions of the type<br />
V a -> B b or B a -> V b. The literature on partial evaluation<br />
describes this issue in detail. Our tagless-final paper (Sec 4.2 of<br />
the the journal version, Delaying binding-time analysis) has a short<br />
explanation, too.<br />
<br />
--------------------------------------<br />
<br />
End of section 2.2, I think "cons :: a -> [b] -> [ResTy a b]" should be "cons :: a -> [b] -> ResTy a b"<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 15:28, 14 May 2009 (UTC)<br />
<br />
<br />
--------------------------------------<br />
<br />
End of page 19 with footnote 9. I could not simply copy and paste the URL because of a stray space after the '-' in http://okmij.org/ftp/Haskell/keyword- arguments.lhs<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 16:08, 14 May 2009 (UTC)<br />
<br />
<br />
'''To Chris Kuklewicz''', regarding the problem with footnote 9. That is an<br />
odd problem that I could not reproduce. It seems xpdf lets me cut<br />
and paste the URL in question without introducing stray spaces. BTW,<br />
the type was correct, as Ryan Ingram described. We have implemented<br />
his suggestion so to remove the confusion.<br />
<br />
--------------------------------------<br />
<br />
Typo "Mounier" --> "Monnier"<br />
<br />
[[User:Tschrijvers|Tom Schrijvers]] 11:11, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
Contrary to what the introductions say, polymorphism over type constructors was not part of Haskell from the beginning. They were only introduced after Mark Jones showed how to do it in Gofer.<br />
<br />
[[User:Augustss|Augustss]] 14:30, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
Why do you say "Obviously, we want to declare algebraic data kinds, ..."?<br />
What's obvious about that? Many of us think that's the wrong way, and you should instead provide a way to lift ordinary data type to the kind level.<br />
<br />
[[User:Augustss|Augustss]] 15:36, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
I was really fascinated by section 5.2 where you track state in the types using a parameterized monad. However, the example code you use is rather underwhelming since it can be implemented by much simpler means. If there's only a fixed number of locks then they can be tracked using a fixed tuple and the whole type functions business is a bit superfluous (albeit still nice). To really reap the benefits of the machinery you set up you ought to have a function for creating new locks dynamically. Here's an example of how it can be done:<br />
<haskell><br />
type family Length p<br />
type instance Length Nil = Zero<br />
type instance Length (Cons l p) = Succ (Length p)<br />
<br />
type family NewLock p<br />
type instance NewLock Nil = Cons Unlocked Nil<br />
type instance NewLock (Cons l p) = Cons l (NewLock p)<br />
<br />
newLock :: Nat (Length p) =><br />
LockM p (NewLock p) (Lock (Length p))<br />
newLock = LockM (return mkLock)<br />
</haskell><br />
<br />
In order for this to work nicely we need a new run function as well. I've used an ordinary type class to check that all locks are unlocked, since this really is a predicate on the state and not a function. <br />
<br />
<haskell><br />
class AllUnlocked a<br />
<br />
instance AllUnlocked Nil<br />
instance AllUnlocked p => AllUnlocked (Cons Unlocked p)<br />
<br />
runNew :: AllUnlocked locks => LockM Nil locks a -> IO a<br />
runNew = unLockM<br />
</haskell><br />
<br />
I think the section becomes more convincing if you add dynamic creation of locks. Not to mention the increased sex appeal :-)<br />
<br />
[[User:Josef|Josef]] 16:58, 25 May 2009 (UTC)<br />
<br />
'''To Josef Svenningsson''': indeed the variable number of locks would have<br />
been sexier but it creates the problem of locks `leaking' out of scope<br />
(e.g., returned as the result of runNew and then used within another<br />
runNew computation, with disastrous results). In short, we need<br />
regions. Chung-chieh Shan and I have indeed implemented such a system,<br />
with a parameterized monad to track the state of the variable number of<br />
resources (file handles in our case). Please see Sec 6 of our<br />
Lightweight Monadic Regions paper. We used functional dependencies for<br />
type functions. Replacing functional dependencies with type functions<br />
is straightforward. Yet the staggering complexity of the code in Sec 6<br />
will remain. I'm afraid this makes the example too complex for this<br />
paper; rather than attracting users to type functions we would scare<br />
all of them away.<br />
--------------------------------------<br />
<br />
It would be very nice if you published a bundle or repository somewhere containing the Haskell source from the paper. At the very least it would be nice with a comment on which version of GHC one should have and what flags are required. The reason I'm asking is that I had a bit of trouble with this. For instance, just saying {-# LANGUAGE TypeFamilies #-} didn't enable type equality constraints in the parser. I had to add ScopedTypeVariables which felt rather arbitrary.<br />
<br />
[[User:Josef|Josef]] 16:58, 25 May 2009 (UTC)</div>Tanimotohttps://wiki.haskell.org/Simonpj/Talk:FunWithTypeFunsSimonpj/Talk:FunWithTypeFuns2009-07-20T03:38:45Z<p>Tanimoto: incorrect alignment</p>
<hr />
<div>= Fun with Type Functions =<br />
<br />
Here is Version 2 of our paper:<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/typefun.pdf Fun With Type Functions (version 2)]''', Oleg Kiselyov, Ken Shan, and Simon Peyton Jones<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/FunWithTypeFuns-Apr09.pdf Slides (PDF)]'''<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/fun-with-type-funs.zip Source code]'''<br />
<br />
which will appear in the proceedings of Tony Hoare's 75th birthday celebration.<br />
<blockquote><br />
'''Abstract'''. Tony Hoare has always been a leader in writing down and proving<br />
properties of programs. To prove properties of programs automatically,<br />
the most widely used technology today is by far the ubiquitous type checker.<br />
Alas, static type systems inevitably exclude some good programs<br />
and allow some bad ones. This dilemma motivates us to describe some fun we've<br />
been having with Haskell, by making the type system more expressive<br />
without losing the benefits of automatic proof and compact expression.<br />
<p><br />
Haskell's type system extends Hindley-Milner with two distinctive<br />
features: polymorphism over type constructors and overloading<br />
using type classes. These features have been integral to Haskell<br />
since its beginning, and they are widely used and appreciated. More recently, Haskell has been enriched with<br />
''type families'', or ''associated types'', <br />
which allows functions on types to be<br />
expressed as straightforwardly as functions on values. This facility<br />
makes it easier for programmers to effectively extend the compiler by<br />
writing functional programs that execute during type-checking.<br />
</p><p><br />
This paper gives a programmer's tour of type families as they are<br />
supported in GHC today.<br />
</p></blockquote><br />
<br />
This Wiki page is a discussion page for the paper. If you are kind enough to read this paper, please help us by jotting down any thoughts it triggers off. Things to think about:<br />
* What is unclear?<br />
* What is omitted that you'd like to see?<br />
* Do you have any cool examples that are of a somewhat different character than the ones we describe? (If so, do explain the example on this page!)<br />
<br />
You can identify your entries by preceding them with four tildes. Doing so adds your name, and the date. Thus:<br />
<br />
:[[User:Simonpj|Simonpj]] 08:42, 19 April 2007 (UTC) Note from Simon<br />
<br />
If you say who you are in this way, we'll be able to acknowledge your help in a revised version of the paper.<br />
<br />
------------------------<br />
Add comments here (newest at the top):<br />
<br />
[[User:Tanimoto|tanimoto]] 03:38, 20 July 2009 (UTC) Comments not aligned correctly<br />
<br />
In Appendix A, item 1, "ILLEGAL" and "OK" could be aligned with the previous comments.<br />
<br />
In Appendix A, item 3, type T5, "OK" is not aligned with the previous comments.<br />
<br />
Some code snippets go off the right margin, I hope it's not a problem: pp. 10, 17, 18, 25, 35, 37.<br />
<br />
<br />
[[User:Bens|bens]] 01:13, 20 July 2009 (UTC) In Appendix C, "fmt1 ^ fmt2 = fmt1 ++ \x -> fmt2 x" -> "fmt1 ^ fmt2 = \x -> fmt1 ++ fmt2 x".<br />
<br />
[[User:BobAtkey|BobAtkey]] 17:39, 9 July 2009 (UTC) Could you update the reference to my "Parameterised Notions of Computation" paper to the journal version? Thanks: Robert Atkey. Parameterised Notions of Computation. Journal of Functional Programming 19: (3 & 4), pages 355-376, July 2009.<br />
<br />
[[User:Mvanier|Mvanier]] 03:14, 3 July 2009 (UTC) The source code link seems to be dead. '''SLPJ: fixed'''<br />
<br />
<br />
-------------------------<br />
'''Stuff below here refers to [http://research.microsoft.com/~simonpj/papers/assoc-types/fun-with-type-funs/typefun-v1.pdf Version 1 of the paper], now retired.'''<br />
-------------------------<br />
<br />
[[User:Oleg|Oleg]] 02:55, 3 June 2009 (UTC) <br />
<br />
Thank you indeed for all the comments and suggestions!<br />
<br />
i have dealt with all the comments and fixed all the noted problems. I<br />
have a few questions about several suggestions though. I should remark<br />
first that the complete code discussed in the paper is available,<br />
presently in our darcs repository. I guess Simon has not decided of a<br />
site to host the online version of the paper with the Appendices and<br />
the code. Incidentally, code fragments in the paper are lifted<br />
straight from the working code, using the remarkably useful<br />
\VerbatimInput.<br />
<br />
--------------------------------------<br />
<br />
[[User:Byorgey|Byorgey]] 20:07, 19 May 2009 (UTC) <br />
* p. 32:<br />
** "powerful, but the" -> "powerful, but they"<br />
* p. 33: <br />
** "commonly mentioned on Haskell mailing lists pitfall of type functions" -> "one pitfall of type functions commonly mentioned..."<br />
** "the compiler should chose" -> "should the compiler choose"<br />
<br />
[[User:bjpop|BerniePope]] 06:18, Fri 15 May 2009 (UTC) Typo in Appendix B.<br />
<br />
"GHC should noat" -> "GHC should not"<br />
<br />
[[User:Tanimoto|tanimoto]] 02:17, 15 May 2009 (UTC) Typo in references<br />
<br />
In reference [32], page 30, Oleg's last name is misspelled as "Kiselov".<br />
<br />
<br />
[[User:Ryani|Ryani]] 23:01, 14 May 2009 (UTC) Fun paper! Comments:<br />
<br />
I was writing a generic finite map a while ago and determined that the generic memoized trie was better in almost all cases; it was simpler semantically and didn't have a significant performance difference. Then you have "type Map k v = Table k (Maybe v)". Is it worth calling out this special case in its own section?<br />
<br />
Also, in respose to ChrisKuklewicz, I think the type for "cons" is correct, but perhaps one instance should be given as an example.<br />
<br />
'''To Ryan Ingram''': Just to double-check: you are saying that the<br />
implementation of generic finite maps as <br />
"type Map k v = Table k (Maybe v)" is faster that the one given in Sec<br />
3.3? That is quite interesting!<br />
<br />
<br />
<br />
[[User:Dave Menendez|Dave Menendez]] 16:52, 14 May 2009 (UTC) On page 11, you refer to a "specialised instance for Table Int that uses some custom <br />
(but innite!) tree representation for Int." Was this meant to be Integer? Surely any tree representation for Int would be large but finite. <br />
<br />
-------------------<br />
Peter Verswyvelen and I have been working on some type family fun to give us generalised partial application (even to the point of being able to cope with giving arguments, but not a function). I don't know if it really makes any interesting point that you didn't already in the paper, but it's certainly fun...<br />
<br />
<haskell><br />
{-# LANGUAGE TypeFamilies, EmptyDataDecls, TypeOperators, FlexibleInstances, FlexibleContexts #-}<br />
<br />
module Burn2 where<br />
<br />
newtype V a = V a -- A value<br />
data B a = B -- A value we don't want to provide yet<br />
<br />
-- Type level homogenous lists (well just tuples in a list-like syntax really)<br />
data Nil a = Nil<br />
data a :& b = !a :& !b<br />
<br />
infixr 5 :& <br />
<br />
class Apply funargs where<br />
type Result funargs :: *<br />
apply :: funargs -> Result funargs<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& V c :& rest) where<br />
type Result (V (a->b) :& V c :& rest) = Result (V b :& rest)<br />
apply (V f :& V a :& rest) = apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& V c :& rest) where<br />
type Result (B (a->b) :& V c :& rest) = (a->b) -> Result (V b :& rest)<br />
apply (B :& V a :& rest) = \f -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& B c :& rest) where<br />
type Result (V (a->b) :& B c :& rest) = a -> Result (V b :& rest)<br />
apply (V f :& B :& rest) = \a -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& B c :& rest) where<br />
type Result (B (a->b) :& B c :& rest) = (a->b) -> a -> Result (V b :& rest)<br />
apply (B :& B :& rest) = \f a -> apply $ V (f a) :& rest<br />
<br />
instance Apply (V a :& Nil b) where<br />
type Result (V a :& Nil b) = a<br />
apply (V a :& Nil) = a<br />
<br />
instance Apply (B a :& Nil b) where<br />
type Result (B a :& Nil b) = B a<br />
apply (B :& Nil) = B<br />
<br />
v1 = apply (V 1 :& Nil)<br />
f1 = apply (B :& Nil)<br />
v2 = apply (V negate :& V 1 :& Nil)<br />
f3 = apply (V negate :& B :& Nil)<br />
v3 = apply (V f3 :& V 1 :& Nil)<br />
</haskell><br />
<br />
[[User:Beelsebob|Beelsebob]] 13:04, 14 May 2009 (UTC)<br />
<br />
'''To Beelsebob''': I'm afraid the code does not account for the most<br />
interesting case: a function that takes a dynamic value and returns<br />
a static result. So you need to deal with functions of the type<br />
V a -> B b or B a -> V b. The literature on partial evaluation<br />
describes this issue in detail. Our tagless-final paper (Sec 4.2 of<br />
the the journal version, Delaying binding-time analysis) has a short<br />
explanation, too.<br />
<br />
--------------------------------------<br />
<br />
End of section 2.2, I think "cons :: a -> [b] -> [ResTy a b]" should be "cons :: a -> [b] -> ResTy a b"<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 15:28, 14 May 2009 (UTC)<br />
<br />
<br />
--------------------------------------<br />
<br />
End of page 19 with footnote 9. I could not simply copy and paste the URL because of a stray space after the '-' in http://okmij.org/ftp/Haskell/keyword- arguments.lhs<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 16:08, 14 May 2009 (UTC)<br />
<br />
<br />
'''To Chris Kuklewicz''', regarding the problem with footnote 9. That is an<br />
odd problem that I could not reproduce. It seems xpdf lets me cut<br />
and paste the URL in question without introducing stray spaces. BTW,<br />
the type was correct, as Ryan Ingram described. We have implemented<br />
his suggestion so to remove the confusion.<br />
<br />
--------------------------------------<br />
<br />
Typo "Mounier" --> "Monnier"<br />
<br />
[[User:Tschrijvers|Tom Schrijvers]] 11:11, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
Contrary to what the introductions say, polymorphism over type constructors was not part of Haskell from the beginning. They were only introduced after Mark Jones showed how to do it in Gofer.<br />
<br />
[[User:Augustss|Augustss]] 14:30, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
Why do you say "Obviously, we want to declare algebraic data kinds, ..."?<br />
What's obvious about that? Many of us think that's the wrong way, and you should instead provide a way to lift ordinary data type to the kind level.<br />
<br />
[[User:Augustss|Augustss]] 15:36, 15 May 2009 (UTC)<br />
<br />
--------------------------------------<br />
<br />
I was really fascinated by section 5.2 where you track state in the types using a parameterized monad. However, the example code you use is rather underwhelming since it can be implemented by much simpler means. If there's only a fixed number of locks then they can be tracked using a fixed tuple and the whole type functions business is a bit superfluous (albeit still nice). To really reap the benefits of the machinery you set up you ought to have a function for creating new locks dynamically. Here's an example of how it can be done:<br />
<haskell><br />
type family Length p<br />
type instance Length Nil = Zero<br />
type instance Length (Cons l p) = Succ (Length p)<br />
<br />
type family NewLock p<br />
type instance NewLock Nil = Cons Unlocked Nil<br />
type instance NewLock (Cons l p) = Cons l (NewLock p)<br />
<br />
newLock :: Nat (Length p) =><br />
LockM p (NewLock p) (Lock (Length p))<br />
newLock = LockM (return mkLock)<br />
</haskell><br />
<br />
In order for this to work nicely we need a new run function as well. I've used an ordinary type class to check that all locks are unlocked, since this really is a predicate on the state and not a function. <br />
<br />
<haskell><br />
class AllUnlocked a<br />
<br />
instance AllUnlocked Nil<br />
instance AllUnlocked p => AllUnlocked (Cons Unlocked p)<br />
<br />
runNew :: AllUnlocked locks => LockM Nil locks a -> IO a<br />
runNew = unLockM<br />
</haskell><br />
<br />
I think the section becomes more convincing if you add dynamic creation of locks. Not to mention the increased sex appeal :-)<br />
<br />
[[User:Josef|Josef]] 16:58, 25 May 2009 (UTC)<br />
<br />
'''To Josef Svenningsson''': indeed the variable number of locks would have<br />
been sexier but it creates the problem of locks `leaking' out of scope<br />
(e.g., returned as the result of runNew and then used within another<br />
runNew computation, with disastrous results). In short, we need<br />
regions. Chung-chieh Shan and I have indeed implemented such a system,<br />
with a parameterized monad to track the state of the variable number of<br />
resources (file handles in our case). Please see Sec 6 of our<br />
Lightweight Monadic Regions paper. We used functional dependencies for<br />
type functions. Replacing functional dependencies with type functions<br />
is straightforward. Yet the staggering complexity of the code in Sec 6<br />
will remain. I'm afraid this makes the example too complex for this<br />
paper; rather than attracting users to type functions we would scare<br />
all of them away.<br />
--------------------------------------<br />
<br />
It would be very nice if you published a bundle or repository somewhere containing the Haskell source from the paper. At the very least it would be nice with a comment on which version of GHC one should have and what flags are required. The reason I'm asking is that I had a bit of trouble with this. For instance, just saying {-# LANGUAGE TypeFamilies #-} didn't enable type equality constraints in the parser. I had to add ScopedTypeVariables which felt rather arbitrary.<br />
<br />
[[User:Josef|Josef]] 16:58, 25 May 2009 (UTC)</div>Tanimotohttps://wiki.haskell.org/Algebraic_data_typeAlgebraic data type2009-07-18T23:26:09Z<p>Tanimoto: fixed typos</p>
<hr />
<div>This is a [[type]] where we specify the shape of each of the elements.<br />
<br />
==Tree examples==<br />
<br />
Suppose we want to represent the following tree:<br />
<br />
5<br />
/ \<br />
3 7<br />
/ \<br />
1 4<br />
<br />
We may actually use a variety of Haskell data declarations that will handle this.<br />
===Binary search tree===<br />
<br />
In this example, values are stored at each node, with smaller values to the left, greater to the right.<br />
<br />
<haskell><br />
data Stree a = Tip | Node (Stree a) a (Stree a)<br />
</haskell><br />
and then our example tree would be:<br />
<haskell><br />
etree = Node (Node (Node Tip 1 Tip) 3 (Node Tip 4 Tip)) 5 (Node Tip 7 Tip)<br />
</haskell><br />
<br />
To maintain the order, such a tree structure is usually paired with a [[Smart constructors | smart constructor]].<br />
<br />
===Rose tree===<br />
Alternatively, it may be represented in what appears to be a totally different stucture.<br />
<haskell><br />
data Rose a = Rose a [Rose a]<br />
</haskell><br />
In this case, the example tree would be:<br />
<haskell><br />
retree = Rose 5 [Rose 3 [Rose 1 [], Rose 4[]], Rose 7 []]<br />
</haskell><br />
<br />
The differences between the two are that the (empty) binary search tree <hask>Tip</hask> is not representable as a <hask>Rose</hask>tree, and a Rose tree can have an arbitrary and internally varying branching factor (0,1,2, or more). <br />
<br />
==See also==<br />
*[[Abstract data type]]<br />
*[[Concrete data type]]<br />
*[[Concrete view]]<br />
*[[Indirect composite]]<br />
[[Category:Language]] [[Category:Glossary]]</div>Tanimotohttps://wiki.haskell.org/Cxx_foreign_function_interfaceCxx foreign function interface2009-06-22T02:52:20Z<p>Tanimoto: typo</p>
<hr />
<div>[[Category:Development_tools]]<br />
<br />
[To do: link here from other pages, add an FFI category?]<br />
<br />
This page outlines the challenges involved in building a foreign function interface (FFI) from Haskell to C++ libraries, beyond the usual difficulties of FFI, and then describes some (possible) solutions to the difficulties presented by C++.<br />
<br />
== FFI Background ==<br />
<br />
Understanding the FFI in general, and with respect to the C programming language in particular, is vital background for anyone wishing to build a Haskell interface to C++. The following pages provide background information:<br />
<br />
* [[FFI Introduction]]<br />
* [[Applications and libraries/Interfacing other languages]] <br />
* [[Foreign Function Interface]]<br />
<br />
== Difficulties of Interfacing to C++ ==<br />
<br />
Foreign function interfaces (FFIs) from Haskell to C are well developed,<br />
but writing an FFI to a C++ library remains a difficult undertaking.<br />
In general, the Haskell FFI apparatus specifies how to call a function<br />
(not a method) using the "ccall" calling mechanism used for C programs.<br />
The FFI specification ([[Definition#Addenda_to_the_report]]) mentions, but does not require, an alternative calling mechanism for C++; no Haskell compiler has ever implemented this. Extra complications arise in interfacing to C++ libraries: <br />
# A C++ program allows overloading, using the same function name with different argument lists. But at the binary level, each different version of the function must have its own name. The C++ compiler "mangles" the function names to differentiate them.<br />
# A C++ program may have classes with constructors, destructors, and methods. These are, obviously, not quite the same as functions, and have no obvious counterpart in Haskell.<br />
# Inheritance (maybe)<br />
# Template functions, template classes, etc.<br />
<br />
== Building Interfaces to C++ ==<br />
<br />
* [[IO inside]] describes how to interface to a C++ library using the "export C" declaration (in C++) which makes it look like a C library. This seems to be the standard technique for bridging the gap between Haskell and C++.<br />
* [[CPlusPlus from Haskell]] describes "the hard way" of interfacing to C++, using the mangled C++ names directly without using "export C". It also suggests the possibility of a more automated approach using gcc-xml.<br />
* [http://darcs.haskell.org/~lemmih/hacanon/ Hacanon] automatically generates an FFI to C++ using [[Template Haskell]], but its author has placed it "on hold" and sees some inherent flaws in using Template Haskell. (See David Himmelstrup, 2006, [http://darcs.haskell.org/~lemmih/aboutMe.html "About Lemmih"], accessed 20 June 2009)<br />
** [http://hackage.haskell.org/package/hacanon-light Hacanon-light] is a reduced form of Hacanon, but with the same problems involving Template Haskell. (See ibid.)<br />
** [http://darcs.haskell.org/%7Elemmih/zerothHead Zeroth] fixes the problems of Hacanon and Hacanon-light, but is "on hold". (See ibid.)<br />
* The [[HQK]] project reports having developed a small Haskell module, qoo, for accessing object-oriented libraries conveniently.<br />
* [http://www.swig.org/ SWIG] (Simplified Wrapper and Interface Generator) can be used to connect C and C++ with many languages, such as Python, Tcl, Java, several versions of Lisp, and OCAML), but alas, not Haskell. Or at least not directly. But with [http://hackage.haskell.org/package/MissingPy MissingPy], which provides access to the Python interpreter, it might be possible to do this indirectly: first, make the C++ library accessible to Python (already done, in many cases), then, let your Haskell program use the Python interpreter to make calls into the C++ library. Maybe this is also possible with some other scripting languages.</div>Tanimotohttps://wiki.haskell.org/User:TanimotoUser:Tanimoto2009-05-15T02:19:08Z<p>Tanimoto: </p>
<hr />
<div>Paulo Tanimoto</div>Tanimotohttps://wiki.haskell.org/Simonpj/Talk:FunWithTypeFunsSimonpj/Talk:FunWithTypeFuns2009-05-15T02:17:23Z<p>Tanimoto: typo in references</p>
<hr />
<div>= Fun with Type Functions =<br />
<br />
Oleg Kiselyov, Ken Shan, and Simon Peyton Jones have a draft paper<br />
* '''[http://research.microsoft.com/~simonpj/papers/assoc-types/typefun.pdf Fun With Type Functions]'''<br />
which will appear in the proceedings of Tony Hoare's 75th birthday celebration.<br />
<blockquote><br />
'''Abstract'''. Tony Hoare has always been a leader in writing down and proving<br />
properties of programs. To prove properties of programs automatically,<br />
the most widely used technology today is by far the ubiquitous type checker.<br />
Alas, static type systems inevitably exclude some good programs<br />
and allow some bad ones. This dilemma motivates us to describe some fun we've<br />
been having with Haskell, by making the type system more expressive<br />
without losing the benefits of automatic proof and compact expression.<br />
<p><br />
Haskell's type system extends Hindley-Milner with two distinctive<br />
features: polymorphism over type constructors and overloading<br />
using type classes. These features have been integral to Haskell<br />
since its beginning, and they are widely used and appreciated. More recently, Haskell has been enriched with<br />
''type families'', or ''associated types'', <br />
which allows functions on types to be<br />
expressed as straightforwardly as functions on values. This facility<br />
makes it easier for programmers to effectively extend the compiler by<br />
writing functional programs that execute during type-checking.<br />
</p><p><br />
This paper gives a programmer's tour of type families as they are<br />
supported in GHC today.<br />
</p></blockquote><br />
<br />
This Wiki page is a discussion page for the paper. If you are kind enough to read this paper, please help us by jotting down any thoughts it triggers off. Things to think about:<br />
* What is unclear?<br />
* What is omitted that you'd like to see?<br />
* Do you have any cool examples that are of a somewhat different character than the ones we describe? (If so, do explain the example on this page!)<br />
<br />
Deadline is sometime in June 2009.<br />
<br />
You can identify your entries by preceding them with four tildes. Doing so adds your name, and the date. Thus:<br />
<br />
:[[User:Simonpj|Simonpj]] 08:42, 19 April 2007 (UTC) Note from Simon<br />
<br />
<br />
If you say who you are in this way, we'll be able to acknowledge your help in a revised version of the paper.<br />
<br />
------------------------<br />
Add comments here (newest at the top):<br />
<br />
[[User:Tanimoto|tanimoto]] 02:17, 15 May 2009 (UTC) Typo in references<br />
<br />
In reference [32], page 30, Oleg's last name is misspelled as "Kiselov".<br />
<br />
<br />
[[User:Ryani|Ryani]] 23:01, 14 May 2009 (UTC) Fun paper! Comments:<br />
<br />
I was writing a generic finite map a while ago and determined that the generic memoized trie was better in almost all cases; it was simpler semantically and didn't have a significant performance difference. Then you have "type Map k v = Table k (Maybe v)". Is it worth calling out this special case in its own section?<br />
<br />
Also, in respose to ChrisKuklewicz, I think the type for "cons" is correct, but perhaps one instance should be given as an example.<br />
<br />
[[User:Dave Menendez|Dave Menendez]] 16:52, 14 May 2009 (UTC) On page 11, you refer to a "specialised instance for Table Int that uses some custom <br />
(but inﬁnite!) tree representation for Int." Was this meant to be Integer? Surely any tree representation for Int would be large but finite. <br />
<br />
Peter Verswyvelen and I have been working on some type family fun to give us generalised partial application (even to the point of being able to cope with giving arguments, but not a function). I don't know if it really makes any interesting point that you didn't already in the paper, but it's certainly fun...<br />
<br />
<haskell><br />
{-# LANGUAGE TypeFamilies, EmptyDataDecls, TypeOperators, FlexibleInstances, FlexibleContexts #-}<br />
<br />
module Burn2 where<br />
<br />
newtype V a = V a -- A value<br />
data B a = B -- A value we don't want to provide yet<br />
<br />
-- Type level homogenous lists (well just tuples in a list-like syntax really)<br />
data Nil a = Nil<br />
data a :& b = !a :& !b<br />
<br />
infixr 5 :& <br />
<br />
class Apply funargs where<br />
type Result funargs :: *<br />
apply :: funargs -> Result funargs<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& V c :& rest) where<br />
type Result (V (a->b) :& V c :& rest) = Result (V b :& rest)<br />
apply (V f :& V a :& rest) = apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& V c :& rest) where<br />
type Result (B (a->b) :& V c :& rest) = (a->b) -> Result (V b :& rest)<br />
apply (B :& V a :& rest) = \f -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (V (a->b) :& B c :& rest) where<br />
type Result (V (a->b) :& B c :& rest) = a -> Result (V b :& rest)<br />
apply (V f :& B :& rest) = \a -> apply $ V (f a) :& rest<br />
<br />
instance (Apply (V b :& rest), a ~ c) => Apply (B (a->b) :& B c :& rest) where<br />
type Result (B (a->b) :& B c :& rest) = (a->b) -> a -> Result (V b :& rest)<br />
apply (B :& B :& rest) = \f a -> apply $ V (f a) :& rest<br />
<br />
instance Apply (V a :& Nil b) where<br />
type Result (V a :& Nil b) = a<br />
apply (V a :& Nil) = a<br />
<br />
instance Apply (B a :& Nil b) where<br />
type Result (B a :& Nil b) = B a<br />
apply (B :& Nil) = B<br />
<br />
v1 = apply (V 1 :& Nil)<br />
f1 = apply (B :& Nil)<br />
v2 = apply (V negate :& V 1 :& Nil)<br />
f3 = apply (V negate :& B :& Nil)<br />
v3 = apply (V f3 :& V 1 :& Nil)<br />
</haskell><br />
<br />
[[User:Beelsebob|Beelsebob]] 13:04, 14 May 2009 (UTC)<br />
<br />
<br />
--------------------------------------<br />
<br />
End of section 2.2, I think "cons :: a -> [b] -> [ResTy a b]" should be "cons :: a -> [b] -> ResTy a b"<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 15:28, 14 May 2009 (UTC)<br />
<br />
<br />
--------------------------------------<br />
<br />
End of page 19 with footnote 9. I could not simply copy and paste the URL because of a stray space after the '-' in http://okmij.org/ftp/Haskell/keyword- arguments.lhs<br />
<br />
[[User:ChrisKuklewicz|ChrisKuklewicz]] 16:08, 14 May 2009 (UTC)</div>Tanimotohttps://wiki.haskell.org/Infinity_and_efficiencyInfinity and efficiency2009-04-25T18:41:24Z<p>Tanimoto: minor edit</p>
<hr />
<div>[[Category:Idioms]]<br />
<br />
In this article we demonstrate how to check the efficiency of an implementation by checking for proper results for infinite input.<br />
In general, it is harder to reason about time and memory complexity of an implementation than about its correctness.<br />
In fact, in Haskell inefficient implementations sometimes turn out to be wrong implementations.<br />
<br />
A very simple example is the function <code>reverse . reverse</code> which seems to be an inefficient implementation of <code>id</code>.<br />
In a language with [[strict semantics]], these two functions are the same.<br />
But since the [[non-strict semantics]] of Haskell allows infinite data structures, there is a subtle difference,<br />
because for an infinite input list, the function <code>reverse . reverse</code> is undefined, whereas <code>id</code> is defined.<br />
<br />
Now let's consider a more complicated example.<br />
Say we want to program a function that removes elements from the end of a list,<br />
just like <code>dropWhile</code> removes elements from the beginning of a list.<br />
We want to call it <code>dropWhileRev</code>.<br />
(As a more concrete example, imagine a function which removes trailing spaces.)<br />
A simple implementation is<br />
<haskell><br />
dropWhileRev :: (a -> Bool) -> [a] -> [a]<br />
dropWhileRev p = reverse . dropWhile p . reverse<br />
</haskell><br />
You probably have already guessed that it also does not work for infinite input lists.<br />
Incidentally, it is also inefficient, because <code>reverse</code> requires to compute all list nodes<br />
(although it does not require to compute the values stored in the nodes).<br />
Thus the full list skeleton must be held in memory.<br />
However, it is possible to implement <code>dropWhileRev</code> in a way that works for more kinds of inputs.<br />
<haskell><br />
dropWhileRev :: (a -> Bool) -> [a] -> [a]<br />
dropWhileRev p =<br />
foldr (\x xs -> if p x && null xs then [] else x:xs) []<br />
</haskell><br />
Here, <code>foldr</code> formally inspects the list from right to left,<br />
but it actually processes data from left to right.<br />
Whenever a run of elements that matches the condition <code>p</code> occurs, these elements are held until the end of the list is encountered (then they are dropped),<br />
or when a non-matching list element is found (then they are emitted).<br />
The crux is the part <code>null xs</code>, which requires to do recursive calls within <code>foldr</code>.<br />
This works in many cases, but it fails if the number of matching elements becomes too large.<br />
The maximum memory consumption depends on the length of the runs of non-matching elements,<br />
which is much more efficient than the naive implementation above.</div>Tanimotohttps://wiki.haskell.org/Infinity_and_efficiencyInfinity and efficiency2009-04-25T18:38:53Z<p>Tanimoto: grammar</p>
<hr />
<div>[[Category:Idioms]]<br />
<br />
In this article we want to demonstrate how to check the efficiency of an implementation by checking for proper results for infinite input.<br />
In general, it is harder to reason about time and memory complexity of an implementation than about its correctness.<br />
In fact, in Haskell inefficient implementations sometimes turn out to be wrong implementations.<br />
<br />
A very simple example is the function <code>reverse . reverse</code> which seems to be an inefficient implementation of <code>id</code>.<br />
In a language with [[strict semantics]], these two functions are the same.<br />
But since the [[non-strict semantics]] of Haskell allows infinite data structures, there is a subtle difference,<br />
because for an infinite input list, the function <code>reverse . reverse</code> is undefined, whereas <code>id</code> is defined.<br />
<br />
Now let's consider a more complicated example.<br />
Say we want to program a function that removes elements from the end of a list,<br />
just like <code>dropWhile</code> removes elements from the beginning of a list.<br />
We want to call it <code>dropWhileRev</code>.<br />
(As a more concrete example, imagine a function which removes trailing spaces.)<br />
A simple implementation is<br />
<haskell><br />
dropWhileRev :: (a -> Bool) -> [a] -> [a]<br />
dropWhileRev p = reverse . dropWhile p . reverse<br />
</haskell><br />
You probably have already guessed that it also does not work for infinite input lists.<br />
Incidentally, it is also inefficient, because <code>reverse</code> requires to compute all list nodes<br />
(although it does not require to compute the values stored in the nodes).<br />
Thus the full list skeleton must be held in memory.<br />
However, it is possible to implement <code>dropWhileRev</code> in a way that works for more kinds of inputs.<br />
<haskell><br />
dropWhileRev :: (a -> Bool) -> [a] -> [a]<br />
dropWhileRev p =<br />
foldr (\x xs -> if p x && null xs then [] else x:xs) []<br />
</haskell><br />
Here, <code>foldr</code> formally inspects the list from right to left,<br />
but it actually processes data from left to right.<br />
Whenever a run of elements that matches the condition <code>p</code> occurs, these elements are held until the end of the list is encountered (then they are dropped),<br />
or when a non-matching list element is found (then they are emitted).<br />
The crux is the part <code>null xs</code>, which requires to do recursive calls within <code>foldr</code>.<br />
This works in many cases, but it fails if the number of matching elements becomes too large.<br />
The maximum memory consumption depends on the length of the runs of non-matching elements,<br />
which is much more efficient than the naive implementation above.</div>Tanimotohttps://wiki.haskell.org/Talk:CookbookTalk:Cookbook2009-04-25T02:24:29Z<p>Tanimoto: re: pleac</p>
<hr />
<div>==Size and direction of page==<br />
Personally, it seems to me that this will be a very large and overwhelming page if it is filled out with all the items in the TOC. What about having it as a gathering page, pointing to other cookbook pages that are subs of this? [[User:BrettGiles|BrettGiles]] 17:44, 22 February 2007 (UTC)<br />
<br />
:I think we should definitely do this, but after the page has grown big. As long as it's not needed, we should stick with one page. The user can now still easily scroll the page. [[User:chriseidhof]].<br />
<br />
:As of now, the very short entries for the chapter give the page its very own charm. I like it very much and I think we should stick to that. It's more a cheatsheet than a cookbook, but who cares. -- [[User:Apfelmus|Apfelmus]] 19:19, 25 February 2007 (UTC)<br />
<br />
:: Makes sense. I like your thought of the page having "charm" :) [[User:BrettGiles|BrettGiles]] 22:27, 26 February 2007 (UTC)<br />
<br />
::: I've split up the page into subpages now, since saving and restructuring the content has become a pain. --[[User:Lenny222|Lenny222]] 10:54, 23 April 2009 (UTC)<br />
<br />
Do you guys know about this:<br />
http://pleac.sourceforge.net/<br />
It seems to be abandoned and it seems the Haskell part didn't go that far, but it does show up on a google search. [[User:Tanimoto|tanimoto]] 15:41, 24 April 2009 (UTC)<br />
<br />
:<strike>The haskell pleac part is a known disgrace and is not only old, but also uses horrible techniques like redefining the (.) function. It would likely be best if the pleac haskell entries be purged completely as they probably never have but certainly do not reflect current haskell best practices. --[[User:JohannesAhlmann|jethr0]] 20:30, 24 April 2009 (UTC)</strike><br />
<br />
::Seems I have to retract that as somebody went to the trouble of fixing the mess that was pleac_haskell. I wouldn't guarantee that it's the finest haskell code ever, but at least it's no longer a total disaster. Maybe we can "borrow" some ideas from the pleac set of tasks. --[[User:JohannesAhlmann|jethr0]] 20:30, 24 April 2009 (UTC)<br />
<br />
:::Actually, that was partly my point. I think it would be nice to see what we can reuse (if anything), then put a link to this Wiki entry so that people don't get confused. [[User:Tanimoto|tanimoto]] 02:24, 25 April 2009 (UTC)<br />
<br />
==Focus on Haskell concepts as well as general tasks==<br />
I like the idea of selecting typical cookbook tasks and providing haskell code snippets. Also it might be useful to provide examples of certain haskell concepts that may not be related to a specific task, like "how to use Control.Monad", "how to use list comprehensions", "how to use STM" etc,.<br />
[[User:b7j0c|b7j0c]]<br />
<br />
:As long as the focus is on practical use, yes. I think we should not provide abstract examples, but concrete examples of a practical problem. This is a bit more difficult, but way more interesting for the end-user.<br />
<br />
<br />
==Somehow use a literate Haskell Approach==<br />
to make sure that code examples actually do what they are supposed to do (i.e. with sth. like docTest)<br />
<br />
Also, I find separate pages for strings and lists superfluous. Let's have "Strings" link to "Lists" for the list functions and only describe character-specific cases for "Strings" (Unicode, upper/lowercasing, ...)<br />
--[[User:JohannesAhlmann|jethr0]] 13:17, 23 April 2009 (UTC)<br />
<br />
: You are right. We should "unify Strings and Lists", but in a way that people new to Haskell will find solutions to common programing problems. I am convinced that Strings := Lists don't come natural to most. So I am not yet sure how to do that. I also don't know how to mix literate Haskell with Wikimedia. --[[User:Lenny222|Lenny222]] 13:35, 23 April 2009 (UTC)<br />
--[[User:JohannesAhlmann|jethr0]] 20:08, 24 April 2009 (UTC)</div>Tanimotohttps://wiki.haskell.org/Cookbook/FilesCookbook/Files2009-04-24T16:47:11Z<p>Tanimoto: creating a temporary file</p>
<hr />
<div>= Reading from a file =<br />
The System.IO library contains the functions needed for file IO. The program<br />
below displays the contents of the file c:\test.txt.<br />
<br />
<haskell><br />
import System.IO<br />
<br />
main = do<br />
h <- openFile "c:\\test.txt" ReadMode<br />
contents <- hGetContents h<br />
putStrLn contents<br />
hClose h<br />
</haskell><br />
<br />
The same program, with some higher-lever functions:<br />
<br />
<haskell><br />
main = do<br />
contents <- readFile "c:\\test.txt"<br />
putStrLn contents<br />
</haskell><br />
<br />
= Writing to a file =<br />
<br />
The following program writes the first 100 squares to a file:<br />
<haskell><br />
-- generate a list of squares with length 'num' in string-format.<br />
numbers num = unlines $ take num $ map (show . \x -> x*x) [1..]<br />
<br />
main = do<br />
writeFile "test.txt" (numbers 100)<br />
putStrLn "successfully written"<br />
</haskell><br />
<br />
This will override the old contents of the file, or create a new file if the file doesn't exist yet. If you want to append to a file, you can use <hask>appendFile</hask>.<br />
<br />
= Creating a temporary file =<br />
<br />
TODO: abstract via 'withTempFile', handle exception<br />
<br />
<haskell><br />
import System.IO<br />
import System.Directory<br />
<br />
main = do<br />
tmpDir <- getTemporaryDirectory<br />
(tmpFile, h) <- openTempFile tmpDir "foo"<br />
hPutStr h "Hello world"<br />
hClose h<br />
removeFile tmpFile<br />
</haskell><br />
<br />
= Writing a filter =<br />
Using [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:interact interact], you can easily do things with stdin and stdout.<br />
<br />
A program to sum up numbers:<br />
<br />
<haskell>main = interact $ show . sum . map read . lines</haskell><br />
<br />
A program that adds line numbers to each line:<br />
<br />
<haskell><br />
main = interact numberLines<br />
numberLines = unlines . zipWith combine [1..] . lines<br />
where combine lineNumber text = concat [show lineNumber, " ", text]<br />
</haskell><br />
<br />
= Logging to a file =<br />
<br />
TODO</div>Tanimotohttps://wiki.haskell.org/Talk:CookbookTalk:Cookbook2009-04-24T15:41:45Z<p>Tanimoto: link to pleac.sourceforge.net</p>
<hr />
<div>==Size and direction of page==<br />
Personally, it seems to me that this will be a very large and overwhelming page if it is filled out with all the items in the TOC. What about having it as a gathering page, pointing to other cookbook pages that are subs of this? [[User:BrettGiles|BrettGiles]] 17:44, 22 February 2007 (UTC)<br />
<br />
:I think we should definitely do this, but after the page has grown big. As long as it's not needed, we should stick with one page. The user can now still easily scroll the page. [[User:chriseidhof]].<br />
<br />
:As of now, the very short entries for the chapter give the page its very own charm. I like it very much and I think we should stick to that. It's more a cheatsheet than a cookbook, but who cares. -- [[User:Apfelmus|Apfelmus]] 19:19, 25 February 2007 (UTC)<br />
<br />
:: Makes sense. I like your thought of the page having "charm" :) [[User:BrettGiles|BrettGiles]] 22:27, 26 February 2007 (UTC)<br />
<br />
::: I've split up the page into subpages now, since saving and restructuring the content has become a pain. --[[User:Lenny222|Lenny222]] 10:54, 23 April 2009 (UTC)<br />
<br />
Do you guys know about this:<br />
http://pleac.sourceforge.net/<br />
It seems to be abandoned and it seems the Haskell part didn't go that far, but it does show up on a google search. [[User:Tanimoto|tanimoto]] 15:41, 24 April 2009 (UTC)<br />
<br />
==Focus on Haskell concepts as well as general tasks==<br />
I like the idea of selecting typical cookbook tasks and providing haskell code snippets. Also it might be useful to provide examples of certain haskell concepts that may not be related to a specific task, like "how to use Control.Monad", "how to use list comprehensions", "how to use STM" etc,.<br />
[[User:b7j0c|b7j0c]]<br />
<br />
:As long as the focus is on practical use, yes. I think we should not provide abstract examples, but concrete examples of a practical problem. This is a bit more difficult, but way more interesting for the end-user.<br />
<br />
<br />
==Somehow use a literate Haskell Approach==<br />
to make sure that code examples actually do what they are supposed to do (i.e. with sth. like docTest)<br />
<br />
Also, I find separate pages for strings and lists superfluous. Let's have "Strings" link to "Lists" for the list functions and only describe character-specific cases for "Strings" (Unicode, upper/lowercasing, ...)<br />
--[[User:JohannesAhlmann|jethr0]] 13:17, 23 April 2009 (UTC)<br />
<br />
: You are right. We should "unify Strings and Lists", but in a way that people new to Haskell will find solutions to common programing problems. I am convinced that Strings := Lists don't come natural to most. So I am not yet sure how to do that. I also don't know how to mix literate Haskell with Wikimedia. --[[User:Lenny222|Lenny222]] 13:35, 23 April 2009 (UTC)</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-19T10:43:39Z<p>Tanimoto: comment on Sgf's logos</p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the<br />
advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit logo-sized (not overly large) versions of your logo with optional text, with a preferably white background (such as for use on haskell.org).<br />
<br />
Please submit your entries here, and attach your name to them please. To be eligible,<br />
they will need to be visible on this page (e.g. uploaded, or link to the image). The image should be freely available (a suitable freely distributable license). Entries not displayed here won't be eligible.<br />
<br />
''The deadline for submissions is December 31, 2008, after which the top few submissions will be voted on by the community to decide a winner!''<br />
<br />
<br />
----<br />
[[Image:lambdanimal.png|150px]]<br />
[[Image:lambdanimal_nomane.png|150px]]<br />
<br />
Strange Lambdanimal, with or without a mane. [[Media:lambdanimal.svg|SVG (inkscape)]].<br />
<br />
by [[User:Ripounet|Ripounet]] 22:24, 18 December 2008 (UTC)<br />
<br />
----<br />
[http://galois.com/~dons/images/logos/Haskell_logo.png http://galois.com/~dons/images/logos/Haskell_logo.png]<br />
<br />
Dana Herz @ Galois.<br />
<br />
----<br />
[[Image:Haskell-tao.png|Haskell as Taoism]]<br />
<br />
Playing off a recent Haskell-Cafe thread, in which programming languages were compared to religions, and Haskell was equated to Taoism. The slogan makes at least a ''little'' sense: it obviously goes with the logo, and 'Duals' are important to Cat theory, which influences Haskell strongly. [[Media:Haskell-tao.svg|SVG]] available. Font is Lucida Calligraphic, a less ubiquitous calligraphic font might be better.<br />
<br />
--[[User:Rgreayer|Rgreayer]] 15:16, 18 December 2008 (UTC)<br />
----<br />
[[Image:unsafeHaskell.png]]<br />
[[User:Beelsebob|Beelsebob]] 09:09, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay2.png]]<br />
[[User:Cjay|cjay]] 03:49, 18 December 2008 (UTC)<br />
<br />
<br />
<br />
[[Image:haskell-cjay2a.png]]<br />
[[User:Cjay|cjay]] 14:27, 18 December 2008 (UTC)<br />
<br />
<br />
[[Image:haskell-cjay2b.png]]<br />
[[User:Cjay|cjay]] 03:22, 19 December 2008 (UTC)<br />
<br />
Available as svg [[Media:Haskell-cjay2.svg|1]] [[Media:Haskell-cjay2a.svg|2]] [[Media:Haskell-cjay2b.svg|3]](inkscape). Fonts: FreeSerif for lambda, >> and the arrow head; Impact Label for "Haskell" (1&2), SF Alien Encounters Solid (3) (all free).<br />
<br />
----<br />
<br />
My attempt at a new Haskell logo:<br />
<br />
[[Image:Haskell_jdr.png]]<br />
<br />
So I guess the standalone version would then be:<br />
<br />
[[Image:Haskell_h_jdr.png]]<br />
<br />
[http://www.voetsjoeba.com Jeroen De Ridder]<br />
<br />
----<br />
<br />
[http://galois.com/~dons/images/logo-3-curved.png http://galois.com/~dons/images/logo-3-curved.png]<br />
<br />
[http://article.gmane.org/gmane.comp.lang.haskell.cafe/49072 George Pollard]<br />
<br />
----<br />
<br />
[[Image:Jeff-heard-1.png]]<br />
<br />
[http://thread.gmane.org/gmane.comp.lang.haskell.cafe/48892/focus=48893 Jeff Heard]. <br />
<br />
----<br />
<br />
Here's an attempt to depict the polish, elegance, and purity of Haskell by merging the H and lambda into an iconic gem.<br />
<br />
[[Image:Haskell2v3.png]]<br />
<br />
Made in Inkscape, with an SVG available.<br />
<br />
--[[User:Chromakode|Chromakode]] 03:18, 17 December 2008 (UTC)<br />
<br />
:I love that one, hope it wins. But I can't see the lambda merged in it, where is it hidden? [[User:Ripounet|Ripounet]]<br />
<br />
----<br />
<br />
All credit goes to Darrin Thompson for posting the ASCII inspiration for this to haskell-cafe. I, Jeff Wheeler, just mocked it up to look<br />
pretty. Here are two interpretations:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo1.png http://media.nokrev.com/junk/haskell-logos/logo1.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo2.png http://media.nokrev.com/junk/haskell-logos/logo2.png]<br />
<br />
Two with rounded edges:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo8.png http://media.nokrev.com/junk/haskell-logos/logo8.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo9.png http://media.nokrev.com/junk/haskell-logos/logo9.png]<br />
<br />
Here's a icon-sized version:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo4.png http://media.nokrev.com/junk/haskell-logos/logo4.png]<br />
<br />
The first two without an background:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo6.png http://media.nokrev.com/junk/haskell-logos/logo6.png] [http://media.nokrev.com/junk/haskell-logos/logo7.png http://media.nokrev.com/junk/haskell-logos/logo7.png]<br />
<br />
--[[User:Jeffwheeler|Jeffwheeler]] 02:42, 17 December 2008 (UTC)<br />
----<br />
Mix and match<br />
<br />
[http://relapse-software.net/haskell_7.png http://relapse-software.net/haskell_7.png]<br />
----<br />
More mix and match, borrowing bind-lambda icon, star/flower idea, and font/verbiage from other submissions...(Raspoutine Classic font, [[Media:Haskell-Symstar.svg|SVG]] available).<br />
[[Image:Haskell-Symstar.png|Haskell - Logo variant]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 21:39, 17 December 2008 (UTC)<br />
----<br />
I really like the logo above. Here are some variations. The font name is ModeNine.<br />
<br />
<br />
[[Image:Haskellvariations1.jpg|Haskell - Logo Variations A]]<br />
<br />
[[Image:Haskellvariations2.jpg|Haskell - Logo Variations B]]<br />
<br />
--[[User:Reified|Reified]] 14:48, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different logo idea, using toddler's letter blocks to convey the simplicity of Haskell. Exact block look and font used can be changed,<br />
but this is the basic idea.<br />
<br />
[[Image:Haskell_logo_ideas_4_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 23:29, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Stupidb123logo.jpg]]<br />
<br />
--[[User:Stupidb123|Stupidb123]] 12:40, 16 December 2008 (UTC)<br />
<br />
----<br />
"The lightbulb lady" (concept: a lady/lightbulb made out of an inverted lambda, hope it catches...).<br />
Font: Museo Sans 500 (free of charge, add to the cart [http://new.myfonts.com/fonts/exljbris/museo-sans/500/ here]).<br />
<br />
[[Image:The_lady.png]]<br />
<br />
-- [[User:eu-prleu-peupeu]]<br />
----<br />
Just another version of the initial spreadshirt variant. <br />
The black background is now part of the logo. The text should be optional.<br />
<br />
[[Image:haskell_spreadshirt_logo.png|400px]]<br />
<br />
[[User:Frosch03|Frosch03]] 11:41, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Made with Inkscape. The source in SVG is available [http://www.gburri.org/bordel/logo_haskell_gburri.svg here].<br />
<br />
Font : [http://www.dafont.com/raspoutine.font?nb_ppp=50&text=Haskell Raspoutine (free)].<br />
<br />
[[Image:haskel_logo_preview_gburri.png]]<br />
<br />
[[User:Gburri|Gburri]] 09:58, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Lambdas in a circle, forming a flower. I wanted it to be easy to draw, be subtle and look nice for haskellers and non-haskellers alike. Created in inkscape using free fonts.<br />
<br />
[[Image:Haskell-flower3.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 05:39, 19 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence<br />
operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
Update:<br />
Slight change and added letters, this time in the free Fonce Sans [http://liquisoft.deviantart.com/art/Fonce-Sans-Regular-Trial-25092730]<br />
font. I like Officina better, but if the font has to be free this is a reasonable substitute.<br />
<br />
[[Image:Haskell_logo_idea_3_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista<br />
and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of<br />
choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This<br />
one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell.<br />
Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
Update: a combination of my two logos on a t-shirt. This time with function arrows to indicate the causal relationships: because Haskell is<br />
pure, it's simple. Because it's simple, it's fun.<br />
<br />
[[Image:Haskell_logo_ideas_tshirt_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12,<br />
15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15<br />
December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[Image:HaskellLogoTDavie2.png]]<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
:: Hmm, I wonder if it's the choice of colors. Then again, with a minor alteration, we get a FreeBSD icon candidate:<br />
[[Image:HsLogoMB-BSD.png|beastie]] ;-) --[[User:GokhanSan|GokhanSan]] 08:52, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo. Although the lower lambda is rotated there is<br />
[http://poinikastas.csad.ox.ac.uk/browseGlyphs.shtml historic precedence] for other forms of the letter. The lambda takes the angle from<br />
the 'k'. Font is News Gothic. Feel free to play with the concept. [[User:Rk|Rk]] 11:13, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent<br />
font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that<br />
works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell3.png|Haskell]]<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----<br />
<br />
The general idea is that it's just "Haskell" but with w lambda instead of the a. The font here is Myriad Pro but this would work with any<br />
good sans-serif font. It's color-agnostic, so it can be easily printer, presented as white on black or changed to a different color.<br />
<br />
[[Image:Haskell_logo_bonus.png]]<br />
<br />
[[Image:Haskell_logo_bonus2.png]]<br />
<br />
--[[User:BONUS|BONUS]] 14:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Axman6-logo-1.0.png]]<br />
<br />
In black:<br />
<br />
[[Image:Axman6-logo-1.1.png]]<br />
<br />
[[Image:Axman6-logo-1.1-small.png]]<br />
<br />
--[[User:Axman6|Axman6]] 15:16, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_girl.jpg]]<br />
<br />
<br />
Oh, didn't know png's would work.<br />
--[[User:Tindrum|Tindrum]] 17:12, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_logo.png]]<br />
<br />
It is mutually recursive...<br />
Here is the [[Media:Haskell logo.svg|svg]].<br />
<br />
Second version:<br />
<br />
[[image:Haskell2_logo.png]]<br />
<br />
And the [[Media:Haskell2 logo.svg|svg]].<br />
<br />
--[[User:Trontonic|Trontonic]] 20:39, 16 December 2008 (UTC)<br />
<br />
----<br />
This is a variation on my [http://t-shirts.cafepress.com/item/lambda-revolution-fitted-tshirt/96543210 Cafepress t-shirt]. The PNG is<br />
generated from an Inkscape SVG.<br />
<br />
[[Image:Haskell-logo-revolution.png]]<br />
<br />
[[User:PaulJohnson|PaulJohnson]] 21:08, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay.png]]<br />
<br />
Available as [[Media:Haskell-cjay.svg|svg]] (inkscape). Fonts: FreeSerif for lambda and >>. Bitstream Vera and FreeMono for other (afaik<br />
all free to use)<br />
<br />
[[User:Cjay|cjay]] 22:45, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20360.png<br />
<br />
One I made with [http://conal.net/Pan/Gallery Pan] (purely functional image synthesis in Haskell) some years back. See also the<br />
[http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20720.png 720 square version]. I have a few sizes up to 2250 pixels<br />
square.<br />
<br />
[[User:Conal|Conal]] 03:40, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_lambda.png]]<br />
<br />
Just kidding :P<br />
<br />
--[[User:Trontonic|Trontonic]] 05:04, 17 December 2008 (UTC)<br />
<br />
----<br />
=== Cale Gibbard ===<br />
[[Image:Haskell-logo-6up.png]]<br />
<br />
[http://haskell.org/haskellwiki/Image:Haskell-logo-6up.svg Inkscape SVG]<br />
<br />
I originally had no specific mountain in mind, but Don Stewart pointed out that this might be representative of Mt. Hood in Portland, Oregon, where Haskell was named.<br />
<br />
Regardless, I thought a summit, bathed in the pure mountain air would be a decent symbol for Haskell, the peak of contemporary programming. :)<br />
<br />
[[User:CaleGibbard|CaleGibbard]] 05:55, 17 December 2008 (UTC)<br />
:Here's a modified version with a slightly funkier font :) I think that it matches the lines of the image better... [[User:Porges|Porges]] 03:14, 18 December 2008 (UTC)<br />
<br />
[[Image:Testhask.png]]<br />
----<br />
<br />
Probably not a good choice for a logo:<br />
<br />
[[Image:Hazard lambda cracked 2.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell_Ribbons.png]]<br />
<br />
[http://slipgate.za.net/~korpse/misc/Haskell_Ribbons.svg SVG]<br />
<br />
Simplicity.<br />
<br />
(It is possible that the font may need to be replaced with a free alternative.)<br />
<br />
[[User:Jonathanj|JonathanJ]] 16:34, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskelllogosmax.png]]<br />
<br />
Available as SVG.<br />
<br />
[[User:MaxRabkin|MaxRabkin]] 05:37, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:DoHaskell.png]]<br />
<br />
Another variation for the cognicenti:<br />
<br />
[[Image:JustHaskell.png]]<br />
<br />
--[[User:Warren|Warren]] 07:26, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
A slight variation of the ">\=" logo:<br />
<br />
[[Image:haskell-logo-doublef.png]]<br />
<br />
Not that it's worth much:). Available as [[Media:haskell-logo-doublef.svg|SVG]].<br />
<br />
[[User:Doublef|DoubleF]] 07:36, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-apankrat.png]]<br />
<br />
The idea for this [http://en.wikipedia.org/wiki/Wordmark_(graphic_identity) wordmark] is to modify ''A'' to resemble λ and through this tie together the "Haskell" to the "Lambda". Modified ''A'' also works well as a standalone logo:<br />
<br />
[[Image:haskell-symbol-apankrat.png]]<br />
<br />
Note that ''any'' logo based on the unmodified λ symbol may look ambiguous to the people outside of Haskell community. While the λ in the context of programming languages is clearly associated with functional programming, it ''is'' a lowercase Greek L and so it's reasonable for an outsider to associate it with '''L'''isp, and not Haskell.<br />
<br />
PS. I just scrolled up and saw BONUS'es entry (14:40, 16 December 2008). While its idea is close, I think using pure λ in place of an A doesn't work because it effectively turn the name into H-L-skell.<br />
<br />
[[User:Apankrat|Apankrat]] 07:38, 18 December 2008 (UTC)<br />
<br />
<br />
----<br />
A very simple logo, made with inkscape, using math fonts, with various grades (B&W, grays, fill color & gradient) and backgrounds<br />
[[Image:Simple_haskell.png]]<br />
<br />
SVG available here:<br />
[[Image:Simple haskell.svgz]]<br />
<br />
[[User:Aubanel|Aubanel]] 18:08, 18 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
[[Image:g3634.png]]<br />
<br />
Available as Inkscape [[Media:dessin.svg|SVG]]<br />
<br />
[[Image:g4441.png]]<br />
<br />
Available as Inkscape [[Media:dessin2.svg|SVG]]<br />
<br />
[[User:runrun|runrun]] 18 December 2008<br />
<br />
----<br />
<br />
[[Image:Haskell-logo2-max.png]]<br />
<br />
Contact me for SVG. Font is not currently free, but I designed it, so this can change if it becomes "the Haskell font". I think it shows some of the elegance that Haskell has. If you like the font but can put it with a better logo, go ahead. --[[User:MaxRabkin|MaxRabkin]] 04:53, 19 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:sgf.png]]<br />
<br />
I think the best way to represent the pure, functional nature of Haskell is with a pure and functional logo! Something modernist, minimalist, clean and simple. I'd prefer not to put highlights of the language's syntax in the logo - that's remarkably concrete for a language good at abstraction. Even lambdas etc. should be slightly hidden - those who know what it's about can see them, and everyone else doesn't think 'what's that funny symbol?'. For the font, again, something functional like a light Helvetica or Univers.<br />
<br />
So, I thought I'd have a go at a few variations. I'm not convinced it's worked, but there you go. I've shamelessly ripped off tanimoto's idea. [[User:Sgf|Sgf]] 08:13, 19 December 2008 (UTC)<br />
<br />
* Sgf, I really like your logos and I think you captured my idea much better than I could do. I especially like the red one, a bit Escher-esque. I wonder if we could turn the blue one into something that looks more like a snowflake than it currently does. Thanks. [[User:Tanimoto|tanimoto]] 10:43, 19 December 2008 (UTC)</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-19T05:39:26Z<p>Tanimoto: keeping only one of my logos, adding description</p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the<br />
advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit logo-sized (not overly large) versions of your logo with optional text, with a preferably white background (such as for use on haskell.org).<br />
<br />
Please submit your entries here, and attach your name to them please. To be eligible,<br />
they will need to be visible on this page (e.g. uploaded, or link to the image). The image should be freely available (a suitable freely distributable license). Entries not displayed here won't be eligible.<br />
<br />
''The deadline for submissions is December 31, 2008, after which the top few submissions will be voted on by the community to decide a winner!''<br />
<br />
<br />
----<br />
[[Image:lambdanimal.png|150px]]<br />
[[Image:lambdanimal_nomane.png|150px]]<br />
<br />
Strange Lambdanimal, with or without a mane. [[Media:lambdanimal.svg|SVG (inkscape)]].<br />
<br />
by [[User:Ripounet|Ripounet]] 22:24, 18 December 2008 (UTC)<br />
<br />
----<br />
[http://galois.com/~dons/images/logos/Haskell_logo.png http://galois.com/~dons/images/logos/Haskell_logo.png]<br />
<br />
Dana Herz @ Galois.<br />
<br />
----<br />
[[Image:Haskell-tao.png|Haskell as Taoism]]<br />
<br />
Playing off a recent Haskell-Cafe thread, in which programming languages were compared to religions, and Haskell was equated to Taoism. The slogan makes at least a ''little'' sense: it obviously goes with the logo, and 'Duals' are important to Cat theory, which influences Haskell strongly. [[Media:Haskell-tao.svg|SVG]] available. Font is Lucida Calligraphic, a less ubiquitous calligraphic font might be better.<br />
<br />
--[[User:Rgreayer|Rgreayer]] 15:16, 18 December 2008 (UTC)<br />
----<br />
[[Image:unsafeHaskell.png]]<br />
[[User:Beelsebob|Beelsebob]] 09:09, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay2.png]]<br />
[[User:Cjay|cjay]] 03:49, 18 December 2008 (UTC)<br />
<br />
<br />
<br />
[[Image:haskell-cjay2a.png]]<br />
[[User:Cjay|cjay]] 14:27, 18 December 2008 (UTC)<br />
<br />
<br />
[[Image:haskell-cjay2b.png]]<br />
[[User:Cjay|cjay]] 03:22, 19 December 2008 (UTC)<br />
<br />
Available as svg [[Media:Haskell-cjay2.svg|1]] [[Media:Haskell-cjay2a.svg|2]] [[Media:Haskell-cjay2b.svg|3]](inkscape). Fonts: FreeSerif for lambda, >> and the arrow head; Impact Label for "Haskell" (1&2), SF Alien Encounters Solid (3) (all free).<br />
<br />
----<br />
<br />
My attempt at a new Haskell logo:<br />
<br />
[[Image:Haskell_jdr.png]]<br />
<br />
So I guess the standalone version would then be:<br />
<br />
[[Image:Haskell_h_jdr.png]]<br />
<br />
[http://www.voetsjoeba.com Jeroen De Ridder]<br />
<br />
----<br />
<br />
[http://galois.com/~dons/images/logo-3-curved.png http://galois.com/~dons/images/logo-3-curved.png]<br />
<br />
[http://article.gmane.org/gmane.comp.lang.haskell.cafe/49072 George Pollard]<br />
<br />
----<br />
<br />
[[Image:Jeff-heard-1.png]]<br />
<br />
[http://thread.gmane.org/gmane.comp.lang.haskell.cafe/48892/focus=48893 Jeff Heard]. <br />
<br />
----<br />
<br />
Here's an attempt to depict the polish, elegance, and purity of Haskell by merging the H and lambda into an iconic gem.<br />
<br />
[[Image:Haskell2v3.png]]<br />
<br />
Made in Inkscape, with an SVG available.<br />
<br />
--[[User:Chromakode|Chromakode]] 03:18, 17 December 2008 (UTC)<br />
<br />
:I love that one, hope it wins. But I can't see the lambda merged in it, where is it hidden? [[User:Ripounet|Ripounet]]<br />
<br />
----<br />
<br />
All credit goes to Darrin Thompson for posting the ASCII inspiration for this to haskell-cafe. I, Jeff Wheeler, just mocked it up to look<br />
pretty. Here are two interpretations:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo1.png http://media.nokrev.com/junk/haskell-logos/logo1.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo2.png http://media.nokrev.com/junk/haskell-logos/logo2.png]<br />
<br />
Two with rounded edges:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo8.png http://media.nokrev.com/junk/haskell-logos/logo8.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo9.png http://media.nokrev.com/junk/haskell-logos/logo9.png]<br />
<br />
Here's a icon-sized version:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo4.png http://media.nokrev.com/junk/haskell-logos/logo4.png]<br />
<br />
The first two without an background:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo6.png http://media.nokrev.com/junk/haskell-logos/logo6.png] [http://media.nokrev.com/junk/haskell-logos/logo7.png http://media.nokrev.com/junk/haskell-logos/logo7.png]<br />
<br />
--[[User:Jeffwheeler|Jeffwheeler]] 02:42, 17 December 2008 (UTC)<br />
----<br />
Mix and match<br />
<br />
[http://relapse-software.net/haskell_7.png http://relapse-software.net/haskell_7.png]<br />
----<br />
More mix and match, borrowing bind-lambda icon, star/flower idea, and font/verbiage from other submissions...(Raspoutine Classic font, [[Media:Haskell-Symstar.svg|SVG]] available).<br />
[[Image:Haskell-Symstar.png|Haskell - Logo variant]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 21:39, 17 December 2008 (UTC)<br />
----<br />
I really like the logo above. Here are some variations. The font name is ModeNine.<br />
<br />
<br />
[[Image:Haskellvariations1.jpg|Haskell - Logo Variations A]]<br />
<br />
[[Image:Haskellvariations2.jpg|Haskell - Logo Variations B]]<br />
<br />
--[[User:Reified|Reified]] 14:48, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different logo idea, using toddler's letter blocks to convey the simplicity of Haskell. Exact block look and font used can be changed,<br />
but this is the basic idea.<br />
<br />
[[Image:Haskell_logo_ideas_4_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 23:29, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Stupidb123logo.jpg]]<br />
<br />
--[[User:Stupidb123|Stupidb123]] 12:40, 16 December 2008 (UTC)<br />
<br />
----<br />
"The lightbulb lady" (concept: a lady/lightbulb made out of an inverted lambda, hope it catches...).<br />
Font: Museo Sans 500 (free of charge, add to the cart [http://new.myfonts.com/fonts/exljbris/museo-sans/500/ here]).<br />
<br />
[[Image:The_lady.png]]<br />
<br />
-- [[User:eu-prleu-peupeu]]<br />
----<br />
Just another version of the initial spreadshirt variant. <br />
The black background is now part of the logo. The text should be optional.<br />
<br />
[[Image:haskell_spreadshirt_logo.png|400px]]<br />
<br />
[[User:Frosch03|Frosch03]] 11:41, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Made with Inkscape. The source in SVG is available [http://www.gburri.org/bordel/logo_haskell_gburri.svg here].<br />
The idea is to hide a lambda into a pretty logo :).<br />
<br />
Font : [http://www.dafont.com/raspoutine.font?nb_ppp=50&text=Haskell Raspoutine (free)].<br />
<br />
[[Image:haskel_logo_preview_gburri.png]]<br />
<br />
[[User:Gburri|Gburri]] 09:58, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Lambdas in a circle, forming a flower. I wanted it to be easy to draw, be subtle and look nice for haskellers and non-haskellers alike. Created in inkscape using free fonts.<br />
<br />
[[Image:Haskell-flower3.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 05:39, 19 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence<br />
operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
Update:<br />
Slight change and added letters, this time in the free Fonce Sans [http://liquisoft.deviantart.com/art/Fonce-Sans-Regular-Trial-25092730]<br />
font. I like Officina better, but if the font has to be free this is a reasonable substitute.<br />
<br />
[[Image:Haskell_logo_idea_3_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista<br />
and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of<br />
choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This<br />
one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell.<br />
Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
Update: a combination of my two logos on a t-shirt. This time with function arrows to indicate the causal relationships: because Haskell is<br />
pure, it's simple. Because it's simple, it's fun.<br />
<br />
[[Image:Haskell_logo_ideas_tshirt_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12,<br />
15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15<br />
December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[Image:HaskellLogoTDavie2.png]]<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
:: Hmm, I wonder if it's the choice of colors. Then again, with a minor alteration, we get a FreeBSD icon candidate:<br />
[[Image:HsLogoMB-BSD.png|beastie]] ;-) --[[User:GokhanSan|GokhanSan]] 08:52, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo. Although the lower lambda is rotated there is<br />
[http://poinikastas.csad.ox.ac.uk/browseGlyphs.shtml historic precedence] for other forms of the letter. The lambda takes the angle from<br />
the 'k'. Font is News Gothic. Feel free to play with the concept. [[User:Rk|Rk]] 11:13, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent<br />
font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that<br />
works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell3.png|Haskell]]<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----<br />
<br />
The general idea is that it's just "Haskell" but with w lambda instead of the a. The font here is Myriad Pro but this would work with any<br />
good sans-serif font. It's color-agnostic, so it can be easily printer, presented as white on black or changed to a different color.<br />
<br />
[[Image:Haskell_logo_bonus.png]]<br />
<br />
[[Image:Haskell_logo_bonus2.png]]<br />
<br />
--[[User:BONUS|BONUS]] 14:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Axman6-logo-1.0.png]]<br />
<br />
In black:<br />
<br />
[[Image:Axman6-logo-1.1.png]]<br />
<br />
[[Image:Axman6-logo-1.1-small.png]]<br />
<br />
--[[User:Axman6|Axman6]] 15:16, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_girl.jpg]]<br />
<br />
<br />
Oh, didn't know png's would work.<br />
--[[User:Tindrum|Tindrum]] 17:12, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_logo.png]]<br />
<br />
It is mutually recursive...<br />
Here is the [[Media:Haskell logo.svg|svg]].<br />
<br />
Second version:<br />
<br />
[[image:Haskell2_logo.png]]<br />
<br />
And the [[Media:Haskell2 logo.svg|svg]].<br />
<br />
--[[User:Trontonic|Trontonic]] 20:39, 16 December 2008 (UTC)<br />
<br />
----<br />
This is a variation on my [http://t-shirts.cafepress.com/item/lambda-revolution-fitted-tshirt/96543210 Cafepress t-shirt]. The PNG is<br />
generated from an Inkscape SVG.<br />
<br />
[[Image:Haskell-logo-revolution.png]]<br />
<br />
[[User:PaulJohnson|PaulJohnson]] 21:08, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay.png]]<br />
<br />
Available as [[Media:Haskell-cjay.svg|svg]] (inkscape). Fonts: FreeSerif for lambda and >>. Bitstream Vera and FreeMono for other (afaik<br />
all free to use)<br />
<br />
[[User:Cjay|cjay]] 22:45, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20360.png<br />
<br />
One I made with [http://conal.net/Pan/Gallery Pan] (purely functional image synthesis in Haskell) some years back. See also the<br />
[http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20720.png 720 square version]. I have a few sizes up to 2250 pixels<br />
square.<br />
<br />
[[User:Conal|Conal]] 03:40, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_lambda.png]]<br />
<br />
Just kidding :P<br />
<br />
--[[User:Trontonic|Trontonic]] 05:04, 17 December 2008 (UTC)<br />
<br />
----<br />
=== Cale Gibbard ===<br />
[[Image:Haskell-logo-6up.png]]<br />
<br />
[http://haskell.org/haskellwiki/Image:Haskell-logo-6up.svg Inkscape SVG]<br />
<br />
I originally had no specific mountain in mind, but Don Stewart pointed out that this might be representative of Mt. Hood in Portland, Oregon, where Haskell was named.<br />
<br />
Regardless, I thought a summit, bathed in the pure mountain air would be a decent symbol for Haskell, the peak of contemporary programming. :)<br />
<br />
[[User:CaleGibbard|CaleGibbard]] 05:55, 17 December 2008 (UTC)<br />
:Here's a modified version with a slightly funkier font :) I think that it matches the lines of the image better... [[User:Porges|Porges]] 03:14, 18 December 2008 (UTC)<br />
<br />
[[Image:Testhask.png]]<br />
----<br />
<br />
Probably not a good choice for a logo:<br />
<br />
[[Image:Hazard lambda cracked 2.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell_Ribbons.png]]<br />
<br />
[http://slipgate.za.net/~korpse/misc/Haskell_Ribbons.svg SVG]<br />
<br />
Simplicity.<br />
<br />
(It is possible that the font may need to be replaced with a free alternative.)<br />
<br />
[[User:Jonathanj|JonathanJ]] 16:34, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskelllogosmax.png]]<br />
<br />
Available as SVG.<br />
<br />
[[User:MaxRabkin|MaxRabkin]] 05:37, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:DoHaskell.png]]<br />
<br />
Another variation for the cognicenti:<br />
<br />
[[Image:JustHaskell.png]]<br />
<br />
--[[User:Warren|Warren]] 07:26, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
A slight variation of the ">\=" logo:<br />
<br />
[[Image:haskell-logo-doublef.png]]<br />
<br />
Not that it's worth much:). Available as [[Media:haskell-logo-doublef.svg|SVG]].<br />
<br />
[[User:Doublef|DoubleF]] 07:36, 18 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-apankrat.png]]<br />
<br />
The idea for this [http://en.wikipedia.org/wiki/Wordmark_(graphic_identity) wordmark] is to modify ''A'' to resemble λ and through this tie together the "Haskell" to the "Lambda". Modified ''A'' also works well as a standalone logo:<br />
<br />
[[Image:haskell-symbol-apankrat.png]]<br />
<br />
Note that ''any'' logo based on the unmodified λ symbol may look ambiguous to the people outside of Haskell community. While the λ in the context of programming languages is clearly associated with functional programming, it ''is'' a lowercase Greek L and so it's reasonable for an outsider to associate it with '''L'''isp, and not Haskell.<br />
<br />
PS. I just scrolled up and saw BONUS'es entry (14:40, 16 December 2008). While its idea is close, I think using pure λ in place of an A doesn't work because it effectively turn the name into H-L-skell.<br />
<br />
[[User:Apankrat|Apankrat]] 07:38, 18 December 2008 (UTC)<br />
<br />
<br />
----<br />
A very simple logo, made with inkscape, using math fonts, with various grades (B&W, grays, fill color & gradient) and backgrounds<br />
[[Image:Simple_haskell.png]]<br />
<br />
SVG available here:<br />
[[Image:Simple haskell.svgz]]<br />
<br />
[[User:Aubanel|Aubanel]] 18:08, 18 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
[[Image:g3634.png]]<br />
<br />
Available as Inkscape [[Media:dessin.svg|SVG]]<br />
<br />
[[Image:g4441.png]]<br />
<br />
Available as Inkscape [[Media:dessin2.svg|SVG]]<br />
<br />
[[User:runrun|runrun]] 18 December 2008<br />
<br />
----<br />
<br />
[[Image:Haskell-logo2-max.png]]<br />
<br />
Contact me for SVG. Font is not currently free, but I designed it, so this can change if it becomes "the Haskell font". I think it shows some of the elegance that Haskell has. If you like the font but can put it with a better logo, go ahead. --[[User:MaxRabkin|MaxRabkin]] 04:53, 19 December 2008 (UTC)</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-17T06:09:49Z<p>Tanimoto: lambdas in a circle 3</p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the<br />
advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit logo-sized (not overly large) versions of your logo with optional text, with a preferably white background (such as for use on haskell.org).<br />
<br />
Please submit your entries here, and attach your name to them please. To be eligible,<br />
you will need to upload them. Entries not displayed here won't be eligible.<br />
<br />
''The deadline for submissions is December 31, 2008, after which the top few submissions will be voted on by the community to decide a winner!''<br />
<br />
----<br />
<br />
Here's an attempt to depict the polish, elegance, and purity of Haskell by merging the H and lambda into an iconic gem.<br />
<br />
[[Image:Haskell2v3.png]]<br />
<br />
Made in Inkscape, with an SVG available.<br />
<br />
--[[User:Chromakode|Chromakode]] 03:18, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
All credit goes to Darrin Thompson for posting the ASCII inspiration for this to haskell-cafe. I, Jeff Wheeler, just mocked it up to look<br />
pretty. Here are two interpretations:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo1.png http://media.nokrev.com/junk/haskell-logos/logo1.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo2.png http://media.nokrev.com/junk/haskell-logos/logo2.png]<br />
<br />
Here's a icon-sized version:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo4.png http://media.nokrev.com/junk/haskell-logos/logo4.png]<br />
<br />
The first two without an background:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo6.png http://media.nokrev.com/junk/haskell-logos/logo6.png] [http://media.nokrev.com/junk/haskell-logos/logo7.png http://media.nokrev.com/junk/haskell-logos/logo7.png]<br />
<br />
--[[User:Jeffwheeler|Jeffwheeler]] 02:42, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different logo idea, using toddler's letter blocks to convey the simplicity of Haskell. Exact block look and font used can be changed,<br />
but this is the basic idea.<br />
<br />
[[Image:Haskell_logo_ideas_4_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 23:29, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Stupidb123logo.jpg]]<br />
<br />
--[[User:Stupidb123|Stupidb123]] 12:40, 16 December 2008 (UTC)<br />
<br />
----<br />
"The lightbulb lady" (concept: a lady/lightbulb made out of an inverted lambda, hope it catches...).<br />
Font: Museo Sans 500 (free of charge, add to the cart [http://new.myfonts.com/fonts/exljbris/museo-sans/500/ here]).<br />
<br />
[[Image:The_lady.png]]<br />
<br />
-- [[User:eu-prleu-peupeu]]<br />
----<br />
Just another version of the initial spreadshirt variant. <br />
The black background is now part of the logo. The text should be optional.<br />
<br />
[[Image:haskell_spreadshirt_logo.png|400px]]<br />
<br />
[[User:Frosch03|Frosch03]] 11:41, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Made with Inkscape (SVG). Font : Calibri.<br />
<br />
[[Image:Haskell logo v1.png]]<br />
<br />
[[Image:Haskell logo v2.png]]<br />
<br />
[[User:Gburri|Gburri]] 09:58, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Closer to what I had in mind originally:<br />
<br />
[[Image:Haskell-flower3.png]]<br />
<br />
<br />
Probably went too far:<br />
<br />
[[Image:Haskell-flower2.png]]<br />
<br />
<br />
First attempt:<br />
<br />
[[Image:Haskell-flower.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 06:09, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence<br />
operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
Update:<br />
Slight change and added letters, this time in the free Fonce Sans [http://liquisoft.deviantart.com/art/Fonce-Sans-Regular-Trial-25092730]<br />
font. I like Officina better, but if the font has to be free this is a reasonable substitute.<br />
<br />
[[Image:Haskell_logo_idea_3_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista<br />
and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of<br />
choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This<br />
one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell.<br />
Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
Update: a combination of my two logos on a t-shirt. This time with function arrows to indicate the causal relationships: because Haskell is<br />
pure, it's simple. Because it's simple, it's fun.<br />
<br />
[[Image:Haskell_logo_ideas_tshirt_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12,<br />
15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15<br />
December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
:: Hmm, I wonder if it's the choice of colors. Then again, with a minor alteration, we get a FreeBSD icon candidate:<br />
[[Image:HsLogoMB-BSD.png|beastie]] ;-) --[[User:GokhanSan|GokhanSan]] 08:52, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo. Although the lower lambda is rotated there is<br />
[http://poinikastas.csad.ox.ac.uk/browseGlyphs.shtml historic precedence] for other forms of the letter. The lambda takes the angle from<br />
the 'k'. Font is News Gothic. Feel free to play with the concept. [[User:Rk|Rk]] 11:13, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent<br />
font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that<br />
works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell3.png|Haskell]]<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----<br />
<br />
The general idea is that it's just "Haskell" but with w lambda instead of the a. The font here is Myriad Pro but this would work with any<br />
good sans-serif font. It's color-agnostic, so it can be easily printer, presented as white on black or changed to a different color.<br />
<br />
[[Image:Haskell_logo_bonus.png]]<br />
<br />
[[Image:Haskell_logo_bonus2.png]]<br />
<br />
--[[User:BONUS|BONUS]] 14:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Axman6-logo-1.0.png]]<br />
<br />
--[[User:Axman6|Axman6]] 15:16, 16 December 2008 (UTC)<br />
<br />
<br />
[[image:Haskell_girl.jpg]]<br />
<br />
<br />
Oh, didn't know png's would work.<br />
--[[User:Tindrum|Tindrum]] 17:12, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_logo.png]]<br />
<br />
It is mutually recursive...<br />
Here is the [[Media:Haskell logo.svg|svg]].<br />
<br />
Second version:<br />
<br />
[[image:Haskell2_logo.png]]<br />
<br />
And the [[Media:Haskell2 logo.svg|svg]].<br />
<br />
--[[User:Trontonic|Trontonic]] 20:39, 16 December 2008 (UTC)<br />
<br />
----<br />
This is a variation on my [http://t-shirts.cafepress.com/item/lambda-revolution-fitted-tshirt/96543210 Cafepress t-shirt]. The PNG is<br />
generated from an Inkscape SVG.<br />
<br />
[[Image:Haskell-logo-revolution.png]]<br />
<br />
[[User:PaulJohnson|PaulJohnson]] 21:08, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay.png]]<br />
<br />
Available as [[Media:Haskell-cjay.svg|svg]] (inkscape). Fonts: FreeSerif for lambda and >>. Bitstream Vera and FreeMono for other (afaik<br />
all free to use)<br />
<br />
[[User:Cjay|cjay]] 22:45, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20360.png<br />
<br />
One I made with [http://conal.net/Pan/Gallery Pan] (purely functional image synthesis in Haskell) some years back. See also the<br />
[http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20720.png 720 square version]. I have a few sizes up to 2250 pixels<br />
square.<br />
<br />
[[User:Conal|Conal]] 03:40, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_lambda.png]]<br />
<br />
Just kidding :P<br />
<br />
--[[User:Trontonic|Trontonic]] 05:04, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-logo-6up.png]]<br />
<br />
[http://haskell.org/haskellwiki/Image:Haskell-logo-6up.svg Inkscape SVG]<br />
<br />
I originally had no specific mountain in mind, but Don Stewart pointed out that this might be representative of Mt. Hood in Portland, Oregon, where Haskell was named.<br />
<br />
Regardless, I thought a summit, bathed in the pure mountain air would be a decent symbol for Haskell, the peak of contemporary programming. :)<br />
<br />
[[User:CaleGibbard|CaleGibbard]] 05:55, 17 December 2008 (UTC)</div>Tanimotohttps://wiki.haskell.org/File:Haskell-flower2.pngFile:Haskell-flower2.png2008-12-17T06:05:29Z<p>Tanimoto: lambdas in a circle</p>
<hr />
<div>lambdas in a circle</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-17T05:52:02Z<p>Tanimoto: lambdas in a circle 2</p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the<br />
advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit logo-sized (not overly large) versions of your logo with optional text, with a preferably white background (such as for use on haskell.org).<br />
<br />
Please submit your entries here, and attach your name to them please. To be eligible,<br />
you will need to upload them. Entries not displayed here won't be eligible.<br />
<br />
''The deadline for submissions is December 31, 2008, after which the top few submissions will be voted on by the community to decide a winner!''<br />
<br />
----<br />
<br />
Here's an attempt to depict the polish, elegance, and purity of Haskell by merging the H and lambda into an iconic gem.<br />
<br />
[[Image:Haskell2v3.png]]<br />
<br />
Made in Inkscape, with an SVG available.<br />
<br />
--[[User:Chromakode|Chromakode]] 03:18, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
All credit goes to Darrin Thompson for posting the ASCII inspiration for this to haskell-cafe. I, Jeff Wheeler, just mocked it up to look<br />
pretty. Here are two interpretations:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo1.png http://media.nokrev.com/junk/haskell-logos/logo1.png]<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo2.png http://media.nokrev.com/junk/haskell-logos/logo2.png]<br />
<br />
Here's a icon-sized version:<br />
<br />
[http://media.nokrev.com/junk/haskell-logos/logo4.png http://media.nokrev.com/junk/haskell-logos/logo4.png]<br />
<br />
--[[User:Jeffwheeler|Jeffwheeler]] 02:42, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different logo idea, using toddler's letter blocks to convey the simplicity of Haskell. Exact block look and font used can be changed,<br />
but this is the basic idea.<br />
<br />
[[Image:Haskell_logo_ideas_4_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 23:29, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Stupidb123logo.jpg]]<br />
<br />
--[[User:Stupidb123|Stupidb123]] 12:40, 16 December 2008 (UTC)<br />
<br />
----<br />
"The lightbulb lady" (concept: a lady/lightbulb made out of an inverted lambda, hope it catches...).<br />
Font: Museo Sans 500 (free of charge, add to the cart [http://new.myfonts.com/fonts/exljbris/museo-sans/500/ here]).<br />
<br />
[[Image:The_lady.png]]<br />
<br />
-- [[User:eu-prleu-peupeu]]<br />
----<br />
Just another version of the initial spreadshirt variant. <br />
The black background is now part of the logo. The text should be optional.<br />
<br />
[[Image:haskell_spreadshirt_logo.png|400px]]<br />
<br />
[[User:Frosch03|Frosch03]] 11:41, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Made with Inkscape (SVG). Font : Calibri.<br />
<br />
[[Image:Haskell logo v1.png]]<br />
<br />
[[Image:Haskell logo v2.png]]<br />
<br />
[[User:Gburri|Gburri]] 09:58, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
Lambdas in a circle:<br />
<br />
[[Image:Haskell-flower.png]]<br />
<br />
<br />
Closer to what I had in mind originally:<br />
<br />
[[Image:Haskell-flower3.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 07:43, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence<br />
operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
Update:<br />
Slight change and added letters, this time in the free Fonce Sans [http://liquisoft.deviantart.com/art/Fonce-Sans-Regular-Trial-25092730]<br />
font. I like Officina better, but if the font has to be free this is a reasonable substitute.<br />
<br />
[[Image:Haskell_logo_idea_3_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista<br />
and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of<br />
choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This<br />
one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell.<br />
Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
Update: a combination of my two logos on a t-shirt. This time with function arrows to indicate the causal relationships: because Haskell is<br />
pure, it's simple. Because it's simple, it's fun.<br />
<br />
[[Image:Haskell_logo_ideas_tshirt_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12,<br />
15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15<br />
December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
:: Hmm, I wonder if it's the choice of colors. Then again, with a minor alteration, we get a FreeBSD icon candidate:<br />
[[Image:HsLogoMB-BSD.png|beastie]] ;-) --[[User:GokhanSan|GokhanSan]] 08:52, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo. Although the lower lambda is rotated there is<br />
[http://poinikastas.csad.ox.ac.uk/browseGlyphs.shtml historic precedence] for other forms of the letter. The lambda takes the angle from<br />
the 'k'. Font is News Gothic. Feel free to play with the concept. [[User:Rk|Rk]] 11:13, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent<br />
font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that<br />
works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell3.png|Haskell]]<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----<br />
<br />
The general idea is that it's just "Haskell" but with w lambda instead of the a. The font here is Myriad Pro but this would work with any<br />
good sans-serif font. It's color-agnostic, so it can be easily printer, presented as white on black or changed to a different color.<br />
<br />
[[Image:Haskell_logo_bonus.png]]<br />
<br />
[[Image:Haskell_logo_bonus2.png]]<br />
<br />
--[[User:BONUS|BONUS]] 14:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Axman6-logo-1.0.png]]<br />
<br />
--[[User:Axman6|Axman6]] 15:16, 16 December 2008 (UTC)<br />
<br />
<br />
[[image:Haskell_girl.jpg]]<br />
<br />
<br />
Oh, didn't know png's would work.<br />
--[[User:Tindrum|Tindrum]] 17:12, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_logo.png]]<br />
<br />
It is mutually recursive...<br />
Here is the [[Media:Haskell logo.svg|svg]].<br />
<br />
Second version:<br />
<br />
[[image:Haskell2_logo.png]]<br />
<br />
And the [[Media:Haskell2 logo.svg|svg]].<br />
<br />
--[[User:Trontonic|Trontonic]] 20:39, 16 December 2008 (UTC)<br />
<br />
----<br />
This is a variation on my [http://t-shirts.cafepress.com/item/lambda-revolution-fitted-tshirt/96543210 Cafepress t-shirt]. The PNG is<br />
generated from an Inkscape SVG.<br />
<br />
[[Image:Haskell-logo-revolution.png]]<br />
<br />
[[User:PaulJohnson|PaulJohnson]] 21:08, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:haskell-cjay.png]]<br />
<br />
Available as [[Media:Haskell-cjay.svg|svg]] (inkscape). Fonts: FreeSerif for lambda and >>. Bitstream Vera and FreeMono for other (afaik<br />
all free to use)<br />
<br />
[[User:Cjay|cjay]] 22:45, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20360.png<br />
<br />
One I made with [http://conal.net/Pan/Gallery Pan] (purely functional image synthesis in Haskell) some years back. See also the<br />
[http://conal.net/Pan/Gallery/haskell-powered%20on%20white%20tiled%20720.png 720 square version]. I have a few sizes up to 2250 pixels<br />
square.<br />
<br />
[[User:Conal|Conal]] 03:40, 17 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[image:Haskell_lambda.png]]<br />
<br />
Just kidding :P<br />
<br />
--[[User:Trontonic|Trontonic]] 05:04, 17 December 2008 (UTC)<br />
<br />
----</div>Tanimotohttps://wiki.haskell.org/File:Haskell-flower3.pngFile:Haskell-flower3.png2008-12-17T05:49:17Z<p>Tanimoto: lambdas in a circle</p>
<hr />
<div>lambdas in a circle</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-16T07:46:52Z<p>Tanimoto: </p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit your entries here, and attach your name to them. To be eligible,<br />
you will need to upload them.<br />
<br />
----<br />
<br />
Many submissions are putting a lambda inside a circle, so I thought about reversing the idea and forming a circle using lambdas. My drawing on paper was much cooler, because it looked like a flower, but I'm terrible at inkscape.<br />
<br />
Please feel free to reuse this idea.<br />
<br />
[[Image:Haskell-flower.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 07:43, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell. Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12, 15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo.<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-16T07:46:06Z<p>Tanimoto: </p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit your entries here, and attach your name to them. To be eligible,<br />
you will need to upload them.<br />
<br />
----<br />
<br />
Many submissions are putting a lambda inside a circle, so I thought about reversing the idea and forming a circle using lambdas. My drawing on a paper was much cooler, because it looked like a flower, but I'm terrible at inkscape.<br />
<br />
Please feel free to reuse this idea.<br />
<br />
[[Image:Haskell-flower.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 07:43, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell. Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12, 15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo.<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----</div>Tanimotohttps://wiki.haskell.org/Haskell_logos/New_logo_ideasHaskell logos/New logo ideas2008-12-16T07:43:13Z<p>Tanimoto: lambdas in a circle</p>
<hr />
<div>'''The great 2009 Haskell logo contest'''<br />
<br />
The Haskell logo has [http://www.willamette.edu/~fruehr/logos/intro.html changed over time], and the current "new" logo reflects the advanced features of Haskell. However, it is looking rather dated, and doesn't necessarily reflect the mature Haskell we have now.<br />
<br />
So, time to find a new logo. Something reflecting the modern emphasis of<br />
Haskell on purity and simplicity.<br />
<br />
Please submit your entries here, and attach your name to them. To be eligible,<br />
you will need to upload them.<br />
<br />
----<br />
<br />
Many submissions are putting a lambda inside a circle, so I thought about reversing the idea and forming a circle using lambdas. My drawing on a paper was much cooler, because it looked like a flower.<br />
<br />
Please feel free to reuse this idea.<br />
<br />
[[Image:Haskell-flower.png]]<br />
<br />
--[[User:Tanimoto|tanimoto]] 07:43, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
A different take on the lambda-in-a-circle logo that looks less like the Half Life logo. Probably fits better than the monadic sequence operator in my other submission.<br />
<br />
[[Image:Haskell_logo_ideas_2_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 08:34, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Very quick attempt:<br />
<br />
[[Image:BurkeLibbey_Haskell.png]]<br />
<br />
The main font is [http://www.josbuivenga.demon.nl/diavlo.html Diavlo] (free). The lambda is in Candara, which I believe ships with Vista and/or XP. Not sure of the licensing there. If there's significant interest in this, I'll redo it as a vector graphic.<br />
<br />
-- [[User:Burke|Burke]] 02:33, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
On behalf of the Ministry of Safety and Happiness I would like to promote the meme suggesting that Haskell is the programming language of choice for the Illuminati.<br />
<br />
[[Image:Haskell proceed.png]]<br />
<br />
--[[User:CznpyHrnjwczky|CznpyHrnjwczky]] 05:31, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
More of a mascotte, though she could be used in a logo as well.<br />
<br />
This is Monica Monad, and she's a Warm Fuzzy Thing. Just giving a face to SPJ's alternative name for monads :)<br />
<br />
Her main purpose would be to present tutorials.<br />
<br />
[[Image:Monica_monad_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 00:52, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
A slightly different take on the Haskell logo, as the lambda-in-a-circle looks a bit too much like the Half Life logo for my taste. This one references monads instead of lambda calculus. Three possible slogans, emphasizing the fun that comes from programming in Haskell. Number 2 and 3 also reference function composition. Number 3 is my personal favourite.<br />
<br />
[[Image:Haskell_logo_ideas_falconnl.png]]<br />
<br />
--[[User:FalconNL|FalconNL]] 22:58, 15 December 2008 (GMT +1)<br />
<br />
: Yummy. What's the font? Is it free? [[User:Porges|Porges]] 21:59, 15 December 2008 (UTC)<br />
: Unfortunately, no. The font is called Officina Sans. Is that a problem? [[User:FalconNL|FalconNL]] 00:02, 16 December 2008 (GMT +1)<br />
<br />
----<br />
<br />
Simple, clean:<br />
<br />
[http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg http://hpsg.fu-berlin.de/~rsling/img/haskell-shirt.jpeg]<br />
<br />
I really like this t-shirt logo, by the way. Gets my vote so far. — [[User:Chrisdone|Chrisdone]] 00:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Minor tweak to the above:<br />
<br />
[[Image:HaskellLogo-v2.png]]<br />
<br />
----<br />
<br />
Minor modification of the t-shirt logo, the lambda was a bit skewed in my opinion:<br />
<br />
[[Image:tshirt-logo-mod.png]]<br />
<br />
And another modification of the same theme:<br />
<br />
[[Image:tshirt-logo-mod-inv.png]]<br />
<br />
--[[User:Sebastiaan|Sebastiaan]] 13:29, 15 December 2008 (UTC)<br />
: I really like this one. A font other than Arial would be nice ;) [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:HaskellLogoTShirtWhite.png]] -- [[User:Chrisdone|Chrisdone]] 23:19, 15 December 2008 (UTC)<br />
<br />
<br />
<br />
----<br />
<br />
Some ideas. Supposed to resemble a lambda abstraction. I realise there are no formal parameters. ---- [[User:Chrisdone|Chrisdone]] 00:12, 15 December 2008 (UTC)<br />
<br />
[http://chrisdone.com/haskell-blah.png http://chrisdone.com/haskell-blah-thumb.png]<br />
<br />
----<br />
<br />
Here's another one; lambda is Gentium SIL, Haskell is MgOpen Cosmetica, tagline is MgOpen Canonica Italic. [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
[[Image:Haskell Logo.png]]<br />
<br />
----<br />
<br />
Another take. A bit simpler, more symmetrical.<br />
<br />
[[Image:haskelllogobeshers.png]]<br />
<br />
----<br />
<br />
[[Image:Haskell-logo.png]]<br />
<br />
The logo uses Kautiva Bold as (non-free) font.<br />
<br />
--[[User:Eelco|Eelco]] 07:43, 15 December 2008 (UTC)<br />
<br />
This one is dedicated to Derek Elkins, to sooth his eyes after having them hurt on the previous logo:<br />
<br />
[[Image:Haskell-logo-funny.png]]<br />
<br />
--[[User:Eelco|Eelco]] 08:53, 15 December 2008 (UTC)<br />
: Makes sense. Comic Sans is the *Official Font of Haskell*, after all.<br />
<br />
----<br />
[[Image:HaskellLogoTDavie.png]]<br />
<br />
[[Image:HaskellLogoTDavie.pdf]] (vector pdf version)<br />
<br />
[[User:Beelsebob|Beelsebob]] 08:32, 15 December 2008 (UTC)<br />
<br />
---- <br />
<br />
[http://relapse-software.net/haskell_0.png http://relapse-software.net/haskell_0.png]<br />
<br />
[http://relapse-software.net/haskell_1.png http://relapse-software.net/haskell_1.png]<br />
<br />
----<br />
<br />
[http://relapse-software.net/haskell_5.png http://relapse-software.net/haskell_5.png]<br />
<br />
<br />
[http://relapse-software.net/haskell_2.png http://relapse-software.net/haskell_2.png]<br />
<br />
[http://relapse-software.net/haskell_3.png http://relapse-software.net/haskell_3.png]<br />
<br />
----<br />
<br />
Logo fun using Blender:<br />
<br />
[[Image:HsLogosMB.png|center|Haskell Logo idea with lambda as mascot]]<br />
<br />
I tried to give the lambda sign an ''alive'' feeling. --[[User:GokhanSan|GokhanSan]] 12:49, 15 December 2008 (UTC)<br />
: Middle one looks a bit too much like the ghostbusters logo :D [[User:Porges|Porges]] 21:25, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:HaskellLogoIdea05.gif]]<br />
<br />
Not sure about the colour. I tried to pick the purple from the current logo.<br />
<br />
----<br />
<br />
<br />
More vectorial Haskell logo concepts. Using inkscape and the popular [http://inde-graphics.deviantart.com/art/advent-font-57338302 advent font] (CC at-nc-nd).<br />
<br />
[[Image:Haskell_infinitylambda.png]]<br />
[[Image:Haskell_halfhalfinfinitylambda.png]]<br />
[[Image:Haskell_3qhalfinfinitylambda.png]]<br />
<br />
Vectorial images (svg):<br />
<br />
[http://haskell.org/sitewiki/images/8/86/Haskell_infinitylambda.svg 1]<br />
[http://haskell.org/sitewiki/images/d/df/Haskell_halfinfinitylambda.svg 2]<br />
[http://haskell.org/sitewiki/images/6/66/Haskell_3qhalfinfinitylambda.svg 3]<br />
<br />
* [[User:alvivi|alvivi]] 19:28, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell-pure.png|haskell::pure]]<br />
<br />
--[[User:Rgreayer|Rgreayer]] 20:44, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
Find a font where 'k' looks like a reverse lambda (after removing the "stalk"). For example:<br />
<br />
[[Image:Kaskell.png|Kaskell]]<br />
<br />
Note this example uses Monotype Corsiva which is not a free font. If the basic approach looks good, we can find a similar free font that works.<br />
<br />
--[[User:Orenbenkiki|OrenBenKiki]] 01:40, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
[[Image:Haskell.png|Haskellll]]<br />
<br />
Illustrator, vector art available, apologies to GokhanSan<br />
<br />
--[[User:Mpeter|Mpeter]] 10:18, 15 December 2008 (UTC)<br />
<br />
----<br />
<br />
<br />
[http://relapse-software.net/haskell_6.png http://relapse-software.net/haskell_6.png]<br />
<br />
----<br />
<br />
[[Image:Haskell4.png|Haskell]]<br />
<br />
Inkscape, vector art available.<br />
<br />
--[[User:Chromakode|Chromakode]] 07:14, 16 December 2008 (UTC)<br />
<br />
----<br />
<br />
I'll probably regret this...<br />
<br />
[[Image:NarleyYeeaaahh.jpg|Haskell - Narwals, YEEAAAAHH!!]]<br />
<br />
(Created with PAINT.NET)<br />
<br />
--[[User:Reified|Reified]] 07:20, 16 December 2008 (UTC)<br />
----</div>Tanimotohttps://wiki.haskell.org/File:Haskell-flower.pngFile:Haskell-flower.png2008-12-16T07:37:54Z<p>Tanimoto: Logo submission of lambdas arranged in a circle.</p>
<hr />
<div>Logo submission of lambdas arranged in a circle.</div>Tanimotohttps://wiki.haskell.org/Talk:Literate_programmingTalk:Literate programming2008-09-26T05:08:42Z<p>Tanimoto: bird style</p>
<hr />
<div>== Bird Style ==<br />
<br />
I just inserted a section on Bird style comments, mostly to point to the flag that relaxes the blank lines restriction. The discussion leading to this discovery can be found here [http://www.haskell.org/pipermail/haskell-cafe/2008-September/047848.html]. It may arguably be better to keep the top sections generic, and leave these types of specific hints to the bottom. [[User:Tanimoto|tanimoto]] 05:08, 26 September 2008 (UTC)</div>Tanimotohttps://wiki.haskell.org/Literate_programmingLiterate programming2008-09-26T05:04:37Z<p>Tanimoto: typos</p>
<hr />
<div>[[Category:Glossary]] [[Category:Tutorials]]<br />
Literate programming was invented / coined / started by [http://www-cs-faculty.stanford.edu/~knuth/ Dr. Donald Knuth]. In, fact if you asked Dr. Knuth what his favourite programming<br />
language was, (5th question of http://www-cs-faculty.stanford.edu/~knuth/faq.html) you would be told CWEB - which is a literate programming<br />
tool combining C and tex. <br />
<br />
What is literate programming? To quote Dr. Knuth: <br />
<blockquote>"The main idea is to regard a program as a communication to human beings rather than as a set of instructions to a computer."</blockquote><br />
<br />
==Haskell and literate programming==<br />
Haskell is one of the few languages that provides native features to support literate programming. In haskell, a literate program is one with the suffix <code>.lhs</code> rather than <code>.hs</code>. <br />
<br />
In a literate Haskell program, there are two ways to distinguish between code and non-code portions. You can either prepend all code with a <code>&gt; </code>, (bird style) or surround lines of code with <code>\begin{code}</code> and <code>\end{code}</code> pairs (latex style). For those who know, use and love latex, the latter is the suggested way to go.<br />
<br />
Note that [[Happy]] supports literate programming as well, via bird style (the <code>&gt; </code> marker) in <code>.ly</code> files. Sadly, [[Alex]] no longer does. You might consider using [http://www.eecs.harvard.edu/~nr/noweb/ noweb] with it.<br />
<br />
==Bird Style==<br />
<br />
According to the [http://www.haskell.org/onlinereport/literate.html Haskell Report], this style of comment was developed by Richard Bird (hence the name) and Philip Wadler. All lines starting with <code>></code> are interpreted as code, everything else is considered a comment. One additional requirement is that you always leave a blank line before and after the code block:<br />
<br />
<haskell><br />
In Bird-style you have to leave a blank before the code.<br />
<br />
> fact :: Integer -> Integer<br />
> fact 0 = 1<br />
> fact n = n * fact (n-1)<br />
<br />
And you have to leave a blank line after the code as well.<br />
</haskell><br />
<br />
The idea behind this restriction is capturing the mistake of not inserting the <code>></code> mark at the beginning of the line. In general this is not only good practice, but also a formatting that makes the code more readable.<br />
<br />
However, there are cases in which you might like to get around this restriction. Perhaps you're writing Haskell code within a markup language that's not Latex, and you may have to surround your code with something equivalent to <code>\begin{code}</code> and <code>\end{code}</code>. In this case, GHC provides a flag that can be used to lift the blank lines requirement:<br />
<br />
<haskell><br />
$ ghc -optL -q<br />
</haskell><br />
<br />
<br />
==Latex suggestions for literate programming ==<br />
(See also [[#lhs2TeX]] below)<br />
In the majority of these suggestions, you can simply write:<br />
<br />
<haskell><br />
\begin{code}<br />
tsort [] = []<br />
tsort (x:xs) = tsort [y | y<-xs, y>x] ++ [x] ++ tsort [y | y<-xs, y<=x]<br />
\end{code}<br />
</haskell><br />
<br />
and the code will be formatted as you requested.<br />
<br />
The advantage: Source code and documentation are consistent! The code<br />
environment is understood by Haskell compilers, so you can run your<br />
documentation files directly.<br />
<br />
===Verbatim package===<br />
One can always simply use verbatim mode which will format the <br />
code "as-is".<br />
<br />
Use verbatim:<br />
<br />
<pre><br />
\usepackage{verbatim}<br />
\newenvironment{code}{\footnotesize\verbatim}{\endverbatim\normalsize}<br />
</pre><br />
===Listings package===<br />
Another alternatative is to use the latex-package listings, which<br />
allows you to do much more customization of the output:<br />
<br />
<pre><br />
\usepackage{listings}<br />
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small}}{}<br />
</pre><br />
<br />
You can configure the appearance of the listings quite a bit! Some people find these settings to be the most satisfying:<br />
<br />
<pre><br />
\usepackage{listings}<br />
\lstloadlanguages{Haskell}<br />
\lstnewenvironment{code}<br />
{\lstset{}%<br />
\csname lst@SetFirstLabel\endcsname}<br />
{\csname lst@SaveFirstLabel\endcsname}<br />
\lstset{<br />
basicstyle=\small\ttfamily,<br />
flexiblecolumns=false,<br />
basewidth={0.5em,0.45em},<br />
literate={+}{{$+$}}1 {/}{{$/$}}1 {*}{{$*$}}1 {=}{{$=$}}1<br />
{>}{{$>$}}1 {<}{{$<$}}1 {\\}{{$\lambda$}}1<br />
{\\\\}{{\char`\\\char`\\}}1<br />
{->}{{$\rightarrow$}}2 {>=}{{$\geq$}}2 {<-}{{$\leftarrow$}}2<br />
{<=}{{$\leq$}}2 {=>}{{$\Rightarrow$}}2 <br />
{\ .}{{$\circ$}}2 {\ .\ }{{$\circ$}}2<br />
{>>}{{>>}}2 {>>=}{{>>=}}2<br />
{|}{{$\mid$}}1 <br />
}<br />
</pre><br />
You might want to consult the documentation of the "listings" package, to find out whether there's more you can tune to your likings. (Like adding line numbers, etc.) Note that the suggested "literate" option above will replace the given symbols anywhere in the text, including inside strings, which is probably not what one wants.<br />
<br />
<br />
=== Hiding code from Latex ===<br />
<br />
If you want to hide some code, you can e.g. define:<br />
<br />
<pre><br />
\long\def\ignore#1{}<br />
</pre><br />
<br />
Auxiliary functions can be hidden as follows:<br />
<pre><br />
\ignore{<br />
\begin{code}<br />
help = putStr "Help me, what is this LiterateProgramming thing??"<br />
\end{code}<br />
}<br />
</pre><br />
Thanks to Wolfram Kahl, Oliver Braun and the people of the German TeX-newsgroup.<br />
<br />
Ciao,<br />
Steffen Mazanek<br />
<br />
http://www.steffen-mazanek.de<br />
<br />
=== Hiding code from Haskell ===<br />
<br />
If you want to hide a <code>\begin{code}...\end{code}</code> block from the ''compiler'', say, if you want to show an example in the text that is not actually part of the source code, you can just add a comment right after the "\begin{code}" statement. This will cause the Haskell parser to treat this block as text, not code:<br />
<br />
<pre><br />
And the definition of the following function<br />
would totally screw up my program, so I'm not<br />
definining it:<br />
<br />
\begin{code}% this is not really code<br />
main :: IO ()<br />
main = print "just an example"<br />
\end{code}<br />
<br />
See?<br />
</pre><br />
<br />
== Transformation of .lhs-files ==<br />
<br />
Sub-pages here have scripts to convert from the demarcation via <code>&gt; </code> (called "bird style" after Dr. Richard Bird) to <code>\begin{code}</code> and <code>\end{code}</code> pairs<br />
<br />
* [[Literate programming/Bird conversion via awk]]<br />
* [[Literate programming/Bird conversion via sed]]<br />
<br />
<br />
== Editors ==<br />
=== Multi-mode support in Emacs ===<br />
<br />
Another useful tool for literate programmers is the [http://mmm-mode.sourceforge.net/ mmm-mode] for Emacs. mmm-mode switches the current major mode of the buffer between two alternatives, depending on the context the cursor is in. If you're in, say, a <code>\begin{code}...\end{code}</code> block, you'll be editing in haskell-mode, but once you leave that block, you'll be editing in latex-mode.<br />
<br />
I have managed to cook up a configuration for both literate styles, but surely some Emacs guru can enhance these. To configure mmm-mode for Haskell, add these lines to your .emacs file:<br />
<br />
<pre><br />
(add-hook 'haskell-mode-hook 'my-mmm-mode)<br />
<br />
(mmm-add-classes<br />
'((literate-haskell-bird<br />
:submode text-mode<br />
:front "^[^>]"<br />
:include-front true<br />
:back "^>\\|$"<br />
)<br />
(literate-haskell-latex<br />
:submode literate-haskell-mode<br />
:front "^\\\\begin{code}"<br />
:front-offset (end-of-line 1)<br />
:back "^\\\\end{code}"<br />
:include-back nil<br />
:back-offset (beginning-of-line -1)<br />
)))<br />
<br />
(defun my-mmm-mode ()<br />
;; go into mmm minor mode when class is given<br />
(make-local-variable 'mmm-global-mode)<br />
(setq mmm-global-mode 'true))<br />
<br />
(setq mmm-submode-decoration-level 0)<br />
</pre><br />
<br />
You can activate mmm-mode by running "M-x mmm-ify-by-class" in the buffer. Emacs will prompt you for the class to use, to which should answer literate-haskell-bird or literate-haskell-latex, respectively.<br />
<br />
If you want Emacs to activate mmm-mode automatically for certain literate Haskell files, add these lines to it at the end:<br />
<br />
<pre><br />
% ----- Configure Emacs -----<br />
%<br />
% Local Variables: ***<br />
% mode: latex ***<br />
% mmm-classes: literate-haskell-latex ***<br />
% End: ***<br />
</pre><br />
<br />
This is, what the my-mmm-mode hook does, by the way.<br />
<br />
=== Vim ===<br />
<br />
See [[Literate programming/Vim]].<br />
<br />
== lhs2TeX ==<br />
<br />
Highly recommended is '''lhs2TeX''' at [http://www.cs.uu.nl/~andres/lhs2tex/], courtesy of Andres Löh. It is designed for typesetting papers ''about'' Haskell, but '''lhs2TeX''' is easily configured and can make for a powerful preprocessor and documentation generator.<br />
<br />
Input to lhs2TeX is a slightly modified <code>.lhs</code> file. One would typically use the standard latex recommendations above, using a <code>\begin{code}</code> and <code>\end{code}</code> pair to demarcate code. Additionally, lhs2TeX provides specialized macros to control the preprocessing.<br />
<br />
Note that lhs2TeX and in-line commenting do not seem to mix well. <br />
<br />
Since it is able to typeset Haskell formulas in mathematical notation<br />
with LaTeX's math mode you can also use it to create ''testable''<br />
papers. That is the reader can play with the formulas presented in the<br />
paper if he obtains the literate Haskell source code of the paper.<br />
<br />
== Shuffle ==<br />
<br />
[http://www.cs.uu.nl/wiki/Ehc/Shuffle Shuffle] is a tool which extends the capabilities of <code>lhs2TeX</code>. It was used in documenting the [http://www.cs.uu.nl/wiki/Ehc/WebHome Essential Haskell Compiler project]. It is available as part of this project, but it is usable also independently.<br />
<br />
==See also==<br />
* [http://www.literateprogramming.com/ Daniel Mall's website for Literate Programming.]<br />
* [http://en.wikipedia.org/wiki/Literate_programming Wikipedia]<br />
* [[Textual Haskell source]] - a <code>.ths</code> processor, where text is king.</div>Tanimotohttps://wiki.haskell.org/Literate_programmingLiterate programming2008-09-26T05:02:58Z<p>Tanimoto: Section on Bird Style</p>
<hr />
<div>[[Category:Glossary]] [[Category:Tutorials]]<br />
Literate programming was invented / coined / started by [http://www-cs-faculty.stanford.edu/~knuth/ Dr. Donald Knuth]. In, fact if you asked Dr. Knuth what his favourite programming<br />
language was, (5th question of http://www-cs-faculty.stanford.edu/~knuth/faq.html) you would be told CWEB - which is a literate programming<br />
tool combining C and tex. <br />
<br />
What is literate programming? To quote Dr. Knuth: <br />
<blockquote>"The main idea is to regard a program as a communication to human beings rather than as a set of instructions to a computer."</blockquote><br />
<br />
==Haskell and literate programming==<br />
Haskell is one of the few languages that provides native features to support literate programming. In haskell, a literate program is one with the suffix <code>.lhs</code> rather than <code>.hs</code>. <br />
<br />
In a literate Haskell program, there are two ways to distinguish between code and non-code portions. You can either prepend all code with a <code>&gt; </code>, (bird style) or surround lines of code with <code>\begin{code}</code> and <code>\end{code}</code> pairs (latex style). For those who know, use and love latex, the latter is the suggested way to go.<br />
<br />
Note that [[Happy]] supports literate programming as well, via bird style (the <code>&gt; </code> marker) in <code>.ly</code> files. Sadly, [[Alex]] no longer does. You might consider using [http://www.eecs.harvard.edu/~nr/noweb/ noweb] with it.<br />
<br />
==Bird Style==<br />
<br />
According to the [http://www.haskell.org/onlinereport/literate.html Haskell Report], this style of comments was developed by Richard Bird (hence the name) and Philip Wadler. All lines starting with <code>></code> are interpreted as code, everything else is considered a comment. One additional requirement is that you always leave a blank line before and after the code block:<br />
<br />
<haskell><br />
In Bird-style you have to leave a blank before the code.<br />
<br />
> fact :: Integer -> Integer<br />
> fact 0 = 1<br />
> fact n = n * fact (n-1)<br />
<br />
And you have to leave a blank line after the code as well.<br />
</haskell><br />
<br />
The idea behind this restriction is capturing the mistake of not inserting the <code>></code> mark at the beginning of the line. In general this is not only good practice, but also a good style that makes the code more readable.<br />
<br />
However, there are cases in which you might like to get around this restriction. Perhaps you're writing Haskell code within a markup language that's not Latex, and you may have to surround your code with something equivalent to <code>\begin{code}</code> and <code>\end{code}</code>. In this case, GHC provides a flag that can be used to lift the blank lines requirement:<br />
<br />
<haskell><br />
$ ghc -optL -q<br />
</haskell><br />
<br />
<br />
==Latex suggestions for literate programming ==<br />
(See also [[#lhs2TeX]] below)<br />
In the majority of these suggestions, you can simply write:<br />
<br />
<haskell><br />
\begin{code}<br />
tsort [] = []<br />
tsort (x:xs) = tsort [y | y<-xs, y>x] ++ [x] ++ tsort [y | y<-xs, y<=x]<br />
\end{code}<br />
</haskell><br />
<br />
and the code will be formatted as you requested.<br />
<br />
The advantage: Source code and documentation are consistent! The code<br />
environment is understood by Haskell compilers, so you can run your<br />
documentation files directly.<br />
<br />
===Verbatim package===<br />
One can always simply use verbatim mode which will format the <br />
code "as-is".<br />
<br />
Use verbatim:<br />
<br />
<pre><br />
\usepackage{verbatim}<br />
\newenvironment{code}{\footnotesize\verbatim}{\endverbatim\normalsize}<br />
</pre><br />
===Listings package===<br />
Another alternatative is to use the latex-package listings, which<br />
allows you to do much more customization of the output:<br />
<br />
<pre><br />
\usepackage{listings}<br />
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small}}{}<br />
</pre><br />
<br />
You can configure the appearance of the listings quite a bit! Some people find these settings to be the most satisfying:<br />
<br />
<pre><br />
\usepackage{listings}<br />
\lstloadlanguages{Haskell}<br />
\lstnewenvironment{code}<br />
{\lstset{}%<br />
\csname lst@SetFirstLabel\endcsname}<br />
{\csname lst@SaveFirstLabel\endcsname}<br />
\lstset{<br />
basicstyle=\small\ttfamily,<br />
flexiblecolumns=false,<br />
basewidth={0.5em,0.45em},<br />
literate={+}{{$+$}}1 {/}{{$/$}}1 {*}{{$*$}}1 {=}{{$=$}}1<br />
{>}{{$>$}}1 {<}{{$<$}}1 {\\}{{$\lambda$}}1<br />
{\\\\}{{\char`\\\char`\\}}1<br />
{->}{{$\rightarrow$}}2 {>=}{{$\geq$}}2 {<-}{{$\leftarrow$}}2<br />
{<=}{{$\leq$}}2 {=>}{{$\Rightarrow$}}2 <br />
{\ .}{{$\circ$}}2 {\ .\ }{{$\circ$}}2<br />
{>>}{{>>}}2 {>>=}{{>>=}}2<br />
{|}{{$\mid$}}1 <br />
}<br />
</pre><br />
You might want to consult the documentation of the "listings" package, to find out whether there's more you can tune to your likings. (Like adding line numbers, etc.) Note that the suggested "literate" option above will replace the given symbols anywhere in the text, including inside strings, which is probably not what one wants.<br />
<br />
<br />
=== Hiding code from Latex ===<br />
<br />
If you want to hide some code, you can e.g. define:<br />
<br />
<pre><br />
\long\def\ignore#1{}<br />
</pre><br />
<br />
Auxiliary functions can be hidden as follows:<br />
<pre><br />
\ignore{<br />
\begin{code}<br />
help = putStr "Help me, what is this LiterateProgramming thing??"<br />
\end{code}<br />
}<br />
</pre><br />
Thanks to Wolfram Kahl, Oliver Braun and the people of the German TeX-newsgroup.<br />
<br />
Ciao,<br />
Steffen Mazanek<br />
<br />
http://www.steffen-mazanek.de<br />
<br />
=== Hiding code from Haskell ===<br />
<br />
If you want to hide a <code>\begin{code}...\end{code}</code> block from the ''compiler'', say, if you want to show an example in the text that is not actually part of the source code, you can just add a comment right after the "\begin{code}" statement. This will cause the Haskell parser to treat this block as text, not code:<br />
<br />
<pre><br />
And the definition of the following function<br />
would totally screw up my program, so I'm not<br />
definining it:<br />
<br />
\begin{code}% this is not really code<br />
main :: IO ()<br />
main = print "just an example"<br />
\end{code}<br />
<br />
See?<br />
</pre><br />
<br />
== Transformation of .lhs-files ==<br />
<br />
Sub-pages here have scripts to convert from the demarcation via <code>&gt; </code> (called "bird style" after Dr. Richard Bird) to <code>\begin{code}</code> and <code>\end{code}</code> pairs<br />
<br />
* [[Literate programming/Bird conversion via awk]]<br />
* [[Literate programming/Bird conversion via sed]]<br />
<br />
<br />
== Editors ==<br />
=== Multi-mode support in Emacs ===<br />
<br />
Another useful tool for literate programmers is the [http://mmm-mode.sourceforge.net/ mmm-mode] for Emacs. mmm-mode switches the current major mode of the buffer between two alternatives, depending on the context the cursor is in. If you're in, say, a <code>\begin{code}...\end{code}</code> block, you'll be editing in haskell-mode, but once you leave that block, you'll be editing in latex-mode.<br />
<br />
I have managed to cook up a configuration for both literate styles, but surely some Emacs guru can enhance these. To configure mmm-mode for Haskell, add these lines to your .emacs file:<br />
<br />
<pre><br />
(add-hook 'haskell-mode-hook 'my-mmm-mode)<br />
<br />
(mmm-add-classes<br />
'((literate-haskell-bird<br />
:submode text-mode<br />
:front "^[^>]"<br />
:include-front true<br />
:back "^>\\|$"<br />
)<br />
(literate-haskell-latex<br />
:submode literate-haskell-mode<br />
:front "^\\\\begin{code}"<br />
:front-offset (end-of-line 1)<br />
:back "^\\\\end{code}"<br />
:include-back nil<br />
:back-offset (beginning-of-line -1)<br />
)))<br />
<br />
(defun my-mmm-mode ()<br />
;; go into mmm minor mode when class is given<br />
(make-local-variable 'mmm-global-mode)<br />
(setq mmm-global-mode 'true))<br />
<br />
(setq mmm-submode-decoration-level 0)<br />
</pre><br />
<br />
You can activate mmm-mode by running "M-x mmm-ify-by-class" in the buffer. Emacs will prompt you for the class to use, to which should answer literate-haskell-bird or literate-haskell-latex, respectively.<br />
<br />
If you want Emacs to activate mmm-mode automatically for certain literate Haskell files, add these lines to it at the end:<br />
<br />
<pre><br />
% ----- Configure Emacs -----<br />
%<br />
% Local Variables: ***<br />
% mode: latex ***<br />
% mmm-classes: literate-haskell-latex ***<br />
% End: ***<br />
</pre><br />
<br />
This is, what the my-mmm-mode hook does, by the way.<br />
<br />
=== Vim ===<br />
<br />
See [[Literate programming/Vim]].<br />
<br />
== lhs2TeX ==<br />
<br />
Highly recommended is '''lhs2TeX''' at [http://www.cs.uu.nl/~andres/lhs2tex/], courtesy of Andres Löh. It is designed for typesetting papers ''about'' Haskell, but '''lhs2TeX''' is easily configured and can make for a powerful preprocessor and documentation generator.<br />
<br />
Input to lhs2TeX is a slightly modified <code>.lhs</code> file. One would typically use the standard latex recommendations above, using a <code>\begin{code}</code> and <code>\end{code}</code> pair to demarcate code. Additionally, lhs2TeX provides specialized macros to control the preprocessing.<br />
<br />
Note that lhs2TeX and in-line commenting do not seem to mix well. <br />
<br />
Since it is able to typeset Haskell formulas in mathematical notation<br />
with LaTeX's math mode you can also use it to create ''testable''<br />
papers. That is the reader can play with the formulas presented in the<br />
paper if he obtains the literate Haskell source code of the paper.<br />
<br />
== Shuffle ==<br />
<br />
[http://www.cs.uu.nl/wiki/Ehc/Shuffle Shuffle] is a tool which extends the capabilities of <code>lhs2TeX</code>. It was used in documenting the [http://www.cs.uu.nl/wiki/Ehc/WebHome Essential Haskell Compiler project]. It is available as part of this project, but it is usable also independently.<br />
<br />
==See also==<br />
* [http://www.literateprogramming.com/ Daniel Mall's website for Literate Programming.]<br />
* [http://en.wikipedia.org/wiki/Literate_programming Wikipedia]<br />
* [[Textual Haskell source]] - a <code>.ths</code> processor, where text is king.</div>Tanimotohttps://wiki.haskell.org/Talk:ImportTalk:Import2008-09-16T14:52:52Z<p>Tanimoto: No prelude</p>
<hr />
<div>=== Multiple Imports of the same Module ===<br />
<br />
Recently on Haskell-Cafe, the topic of imports came up. I noticed this page does not detail the ability to import the same module multiple times under different conditions. Here's an example:<br />
<br />
<haskell><br />
module Main where<br />
<br />
import qualified Prelude as P<br />
import Prelude ((++),show,($))<br />
<br />
main = P.putStrLn (show $ P.length $ [1] ++ [2,3])<br />
</haskell><br />
<br />
I'm not sure if this is exclusive to GHC, or whether it's H98. If it's the latter, then it should probably be on this page. If it's the former, it may still be good to have here.<br />
<br />
<br />
=== Prelude ===<br />
<br />
At the bottom of the page, we could add these links for people interested in not importing prelude or importing an alternative version of it:<br />
<br />
* [[Prelude]]<br />
* [[No_import_of_Prelude|FAQ: No import of Prelude]]<br />
<br />
[[User:Tanimoto|tanimoto]] 14:52, 16 September 2008 (UTC)</div>Tanimotohttps://wiki.haskell.org/PreludePrelude2008-09-16T14:45:53Z<p>Tanimoto: fixed typo</p>
<hr />
<div>'''Prelude''' is a module that contains a small set of standard definitions and is included automatically into all Haskell modules.<br />
<br />
==Documentation==<br />
The documentation of prelude from [[GHC]] can be found [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html here].<br />
<br />
==Avoiding Prelude==<br />
If you wish to program without a prelude or to use a custom version of it you can suppress its automatic inclusion in several ways. The problem is also tackled in a [[No import of Prelude|FAQ entry]].<br />
===Explicit import declaration ===<br />
By including an explicit import declaration of Prelude as follows<br />
<haskell><br />
import Prelude ()<br />
</haskell><br />
The empty import list in the parenthesis causes nothing to be imported while the automatic import is prevented as well.<br />
===Language option===<br />
[[GHC]] supports a [http://www.haskell.org/ghc/docs/latest/html/users_guide/ghc-language-features.html#options-language language option] -XNoImplicitPrelude (or -fno-implicit-prelude in older [[GHC]]) that makes it not import Prelude implicitly. The option can be also specified by adding:<br />
<haskell><br />
{-# LANGUAGE NoImplicitPrelude #-} <br />
</haskell><br />
on top of the module.<br />
<br />
This option makes it possible to rebind the monadic <hask>do</hask> syntax.</div>Tanimotohttps://wiki.haskell.org/List_function_suggestionsList function suggestions2008-06-23T06:24:03Z<p>Tanimoto: join was implemented as intercalate</p>
<hr />
<div>This page lists proposed extensions to the Haskell list functions, whether in the [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html Prelude] or [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-List.html Data.List].<br />
Please discuss the proposals on the Talk Page or the libraries list, and use this page to record the results of discussions.<br />
<br />
== Splitting on a separator, etc ==<br />
<br />
We need these useful functions in Data.List; I'll call them 'split' (and variants) and 'replace'. These are easily implemented but everyone always reinvents them. Various versions have been proposed, but there was no consensus on which was best, e.g.<br />
<br />
* [http://www.haskell.org/pipermail/haskell-cafe/2006-July/thread.html#16559 haskell-cafe thread July 2006]<br />
* [http://www.haskell.org/pipermail/libraries/2004-July/thread.html#2342 libraries thread July 2004]<br />
<br />
Note: a lot of good points (diverging opinions!) are covered in the mailing lists, but if we include all these various cases, split* will have 9 variants! The goal is to reach some kind of reasonable consensus, specifically on naming and semantics. Even if we need pairs of functions to satisfy various usage and algebraic needs. Failing to accommodate every possible use of these functions should not be a sufficient reason to abandon the whole project.<br />
<br />
The goal is clarity/uniformity (everyone uses them widely and recognizes them) and portability (I don't have to keep reimplementing these or copying that one file UsefulMissingFunctions.hs).<br />
<br />
Note: I (Jared Updike) am working with the belief that efficiency should not be a valid argument to bar these otherwise universally useful functions from the libraries; regexes are overkill for 'split' and 'replace' for common simple situations. Let's assume people will know (or learn) when they need heavier machinery (regexes, FPS/ByteString) and will use it when efficiency is important. We can try to facilitate this by reusing any names from FastPackedString and/or ByteString, etc.<br />
<br />
=== split (working name) ===<br />
<br />
We need a few of these:<br />
<br />
<haskell><br />
split :: Eq a => a -> [a] -> [[a]]<br />
splitWith :: (a -> Bool) -> [a] -> [[a]]<br />
tokens :: (a -> Bool) -> [a] -> [[a]]<br />
</haskell><br />
<br />
That preserve:<br />
<br />
<haskell><br />
join sep . split sep = id<br />
</haskell><br />
<br />
See below for 'join'<br />
<br />
And some that use above split but filter to remove empty elements (but do not preserve above property). Easy enough:<br />
<br />
<haskell><br />
split' :: Eq a => a -> [a] -> [[a]]<br />
splitWith' :: (a -> Bool) -> [a] -> [[a]]<br />
tokens' :: (a -> Bool) -> [a] -> [[a]]<br />
</haskell><br />
<br />
i.e.<br />
<br />
<haskell><br />
split' sep = filter (not . null) . split sep<br />
</haskell><br />
<br />
Usage would be:<br />
<br />
<haskell><br />
tokensws = tokens' (`elem` " \f\v\t\n\r\b")<br />
<br />
tokensws "Hello there\n \n Haskellers! " ==<br />
["Hello", "there", "Haskellers!"]<br />
</haskell><br />
<br />
'''TODO: add version like python with multi-element separator'''<br />
<br />
'''TODO: give code, copy-paste from threads mentioned above'''<br />
<br />
'''TODO: list names and reasons for/against'''<br />
<br />
=== replace (working name) ===<br />
<br />
<haskell><br />
replace :: [a] -> [a] -> [a] -> [a]<br />
</haskell><br />
<br />
like Python replace:<br />
<br />
<haskell><br />
replace "the" "a" "the quick brown fox jumped over the lazy black dog"<br />
===><br />
"a quick brown fox jumped over a lazy black dog"<br />
</haskell><br />
<br />
'''TODO: give code, copy-paste from threads mentioned above'''<br />
<br />
'''TODO: list names and reasons for/against'''<br />
<br />
=== join (working name) ===<br />
<br />
<haskell><br />
join :: [a] -> [[a]] -> [a]<br />
</haskell><br />
<br />
<haskell><br />
join sep = concat . intersperse sep<br />
</haskell><br />
<br />
Note: this function has been implemented as 'intercalate' in Data.List.<br />
<br />
'''TODO: copy-paste things from threads mentioned above'''<br />
<br />
'''TODO: list names and reasons for/against'''<br />
<br />
== Sorted lists ==<br />
<br />
The following are versions of standard prelude functions, but intended for sorted lists. The advantage is that they frequently reduce execution time by an O(n). The disadvantage is that the elements have to be members of Ord, and the lists have to be already sorted.<br />
<br />
<haskell><br />
-- Eliminates duplicate entries from the list, where duplication is defined<br />
-- by the 'eq' function. The last value is kept.<br />
sortedNubBy :: (a -> a -> Bool) -> [a] -> [a]<br />
sortedNubBy eq (x1 : xs@(x2 : _)) =<br />
if eq x1 x2 then sortedNubBy eq xs else x1 : sortedNubBy eq xs<br />
sortedNubBy _ xs = xs<br />
<br />
sortedNub :: (Eq a) => [a] -> [a]<br />
sortedNub = sortedNubBy (==)<br />
<br />
-- Merge two sorted lists into a new sorted list. Where elements are equal<br />
-- the element from the first list is taken first.<br />
mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]<br />
mergeBy cmp xs@(x1:xs1) ys@(y1:ys1) =<br />
if cmp x1 y1 == GT<br />
then y1 : mergeBy cmp xs ys1<br />
else x1 : mergeBy cmp xs1 ys<br />
mergeBy _ [] ys = ys<br />
mergeBy _ xs [] = xs<br />
<br />
merge :: (Ord a) => [a] -> [a] -> [a]<br />
merge = mergeBy compare<br />
</haskell><br />
<br />
== Generalize groupBy and friends ==<br />
<br />
In the Haskell 98 List library, <hask>groupBy</hask> assumes that its argument function defines an equivalence, and the reference definition returns sublists where each element is equivalent to the first. The following definition, comparing adjacent elements, does the same thing on equivalence relations:<br />
<haskell><br />
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]<br />
groupBy rel [] = []<br />
groupBy rel (x:xs) = (x:ys) : groupBy rel zs<br />
where (ys,zs) = groupByAux x xs<br />
groupByAux x0 (x:xs) | rel x0 x = (x:ys, zs)<br />
where (ys,zs) = groupByAux x xs<br />
groupByAux y xs = ([], xs)<br />
</haskell><br />
However it is also useful on other relations, e.g.<br />
* Picking out maximal ascending sublists (runs):<br />
<haskell><br />
> groupBy (<=) [7,3,5,9,6,8,3,5,4]<br />
[[7],[3,5,9],[6,8],[3,5],[4]]<br />
</haskell><br />
* Picking out contiguous sublists from an ascending sequence:<br />
<haskell><br />
> groupBy (\a b -> a+1 == b) [1,2,3,4,6]<br />
[[1,2,3,4],[6]]<br />
</haskell><br />
* Splitting a line at the start of each word:<br />
<haskell><br />
> groupBy (\ c1 c2 -> isLetter c1 || not (isLetter c2)) "This is a line"<br />
["This ","is ","a ","line"]<br />
</haskell><br />
Since this more useful definition agrees with the Haskell 98 one on its specified domain, it should be a backwards-compatible replacement.<br />
<br />
The same applies to <hask>nubBy</hask>, and possibly <hask>deleteBy</hask>, <hask>deleteFirstsBy</hask> and <hask>intersectBy</hask> (which could have more general types to make this clear).<br />
<br />
[[Category:Proposals]]<br />
[[Category:Standard libraries]]<br />
[[Category:Idioms]]<br />
<br />
== groupOn and sortOn ==<br />
<br />
Almost all uses of <hask>groupBy</hask> and <hask>sortBy</hask> actually use a specific compare function. This can (using a recent version of base) as<br />
<hask>sortBy (comparing fst)</hask><br />
or<br />
<hask>sortBy (compare `on` fst)</hask>.<br />
Since this use is so common, it might be worthwhile to add separate functions for this:<br />
<haskell><br />
sortOn :: Ord b => (a -> b) -> [a] -> [a]<br />
sortOn = sortBy . comparing<br />
</haskell><br />
The same goes for <hask>groupBy</hask><br />
<haskell><br />
groupOn :: Eq b => (a -> b) -> [a] -> [a]<br />
groupOn f = groupBy (\x y -> f x == f y)<br />
</haskell><br />
The names could be better, the idea behind 'on' comes from the 'on' function.<br />
<br />
== See also ==<br />
* [[Prelude extensions]]</div>Tanimotohttps://wiki.haskell.org/HXTHXT2007-11-12T09:10:34Z<p>Tanimoto: </p>
<hr />
<div>[[Category:Tools]] [[Category:Tutorials]]<br />
<br />
== A gentle introduction to the Haskell XML Toolbox ==<br />
<br />
The [http://www.fh-wedel.de/~si/HXmlToolbox/index.html Haskell XML Toolbox (HXT)] is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language, consisting of a set of combinators, for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace aware XML-Parser that supports almost fully the XML 1.0 Standard. Extensions are a validator for RelaxNG and an XPath evaluator.<br />
<br />
__TOC__<br />
<br />
== Background ==<br />
<br />
The Haskell XML Toolbox bases on the ideas of [http://www.cs.york.ac.uk/fp/HaXml/ HaXml] and [http://www.flightlab.com/~joe/hxml/ HXML] but introduces a more general approach for processing XML with Haskell. HXT uses a generic data model for representing XML documents, including the DTD subset, entity references, CData parts and processing instructions. This data model makes it possible to use tree transformation functions as a uniform design of XML processing steps from parsing, DTD processing, entity processing, validation, namespace propagation, content processing and output.<br />
<br />
== Resources ==<br />
<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/index.html HXT Home] :<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/HXT-7.0.tar.gz HXT-7.0.tar.gz] : lastest release<br />
; [http://darcs.fh-wedel.de/hxt/ darcs.fh-wedel.de/hxt] : darcs repository with head revision of HXT<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc_arrow/ Arrow API] : Haddock documentation of head revision with links to source files<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc/ Complete API] : Haddock documentation with arrows and old API based on filters<br />
<br />
== The basic concepts ==<br />
<br />
=== The basic data structures ===<br />
<br />
Processing of XML is a task of processing tree structures. This is can be done in Haskell in a very elegant way by defining an appropriate tree data type, a Haskell DOM (document object model) structure. The tree structure in HXT is a rose tree with a special XNode data type for storing the XML node information.<br />
<br />
The generally useful tree structure (NTree) is separated from the node type (XNode). This allows for reusing the tree structure and the tree traversal and manipulation functions in other applications.<br />
<br />
<haskell><br />
type NTree a = NTree a [NTree a] -- rose tree<br />
<br />
data XNode = XText String -- plain text node<br />
| ...<br />
| XTag QName XmlTrees -- element name and list of attributes<br />
| XAttr QName -- attribute name<br />
| ...<br />
<br />
type QName = ... -- qualified name<br />
<br />
type XmlTree = NTree XNode<br />
<br />
type XmlTrees = [XmlTree]<br />
</haskell><br />
<br />
=== The concept of filters ===<br />
<br />
Selecting, transforming and generating trees often requires routines, which compute not only a single result tree, but a (possibly empty) list of (sub-)trees. This leads to the idea of XML filters like in HaXml. Filters are functions, which take an XML tree as input and compute a list of result trees.<br />
<br />
<haskell><br />
type XmlFilter = XmlTree -> [XmlTree]<br />
</haskell><br />
<br />
More generally we can define a filter as<br />
<br />
<haskell><br />
type Filter a b = a -> [b]<br />
</haskell><br />
<br />
We will do this abstraction later, when introducing arrows. Many of the functions in the following motivating examples can be generalised this way. But for getting the idea, the <hask>XmlFilter</hask> is sufficient.<br />
<br />
The filter functions are used so frequently, that the idea of defining a domain specific language with filters as the basic processing units comes up. In such a DSL the basic filters are predicates, selectors, constructors and transformers, all working on the HXT DOM tree structure. For a DSL it becomes necessary to define an appropriate set of combinators for building more complex functions from simpler ones. Of course filter composition, like (.) becomes one of the most frequently used combinators. there are more complex filters for traversal of a whole tree and selection or transformation of several nodes. We will see a few first examples in the following part.<br />
<br />
The first task is to build filters from pure functions, to define a lift operator. Pure functions are lifted to filters in the following way:<br />
<br />
Predicates are lifted by mapping False to the empty list and True to the single element list, containing the input tree.<br />
<br />
<haskell><br />
p :: XmlTree -> Bool -- pure function<br />
p t = ...<br />
<br />
pf :: XmlTree -> [XmlTree] -- or XmlFilter<br />
pf t<br />
| p t = [t]<br />
| otherwise = []<br />
</haskell><br />
<br />
The combinator for this type of lifting is called <hask>isA</hask>, it works on any type and is defined as<br />
<br />
<haskell><br />
isA :: (a -> Bool) -> (a -> [a])<br />
isA p x<br />
| p x = [x]<br />
| otherwise = []<br />
</haskell><br />
<br />
A predicate for filtering text nodes looks like this<br />
<br />
<haskell><br />
isXText :: XmlFilter -- XmlTree -> [XmlTrees]<br />
isXText t@(NTree (XText _) _) = [t]<br />
isXText _ = []<br />
</haskell><br />
<br />
Transformers, function that map a tree into another tree, are lifted in a trivial way:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t = exp(t)<br />
<br />
ff :: XmlTree -> [XmlTree]<br />
ff t = [exp(t)]<br />
</haskell><br />
<br />
This basic function is called <hask>arr</hask>, it comes from the Control.Arrow module of the basic library package of ghc.<br />
<br />
Partial functions, functions that can't always compute a result, are usually lifted to totally defined filters:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t<br />
| p t = expr(t)<br />
| otherwise = error "f not defined"<br />
<br />
ff :: XmlFilter<br />
ff t<br />
| p t = [expr(t)]<br />
| otherwise = []<br />
</haskell><br />
<br />
This is a rather comfortable situation, with these filters we don't have to deal with illegal argument errors. Illegal arguments are just mapped to the empty list.<br />
<br />
When processing trees, there's often the case, that no, exactly one, or more than one result is possible. These functions, returning a set of results are often a bit imprecisely called ''nondeterministic'' functions. These functions, e.g. selecting all children of a node or all grandchildren, are exactly our filters. In this context lists instead of sets of values are the appropriate result type, because the ordering in XML is important and duplicates are possible.<br />
<br />
Working with filters is rather similar to working with binary relations, and working with relations is rather natural and comfortable, database people do know this very well.<br />
<br />
Two first examples for working with ''nondeterministic'' functions are selecting the children and the grandchildren of an XmlTree which can be implemented by<br />
<br />
<haskell><br />
getChildren :: XmlFilter<br />
getChildren (NTree n cs)<br />
= cs<br />
<br />
getGrandChildren :: XmlFilter<br />
getGrandChildren (NTree n cs)<br />
= concat [ getChildren c | c <- cs ]<br />
</haskell><br />
<br />
=== Filter combinators ===<br />
<br />
Composition of filters (like function composition) is the most important combinator. We will use the infix operator <hask>(>>>)</hask> for filter composition and reverse the arguments, so we can read composition sequences from left to right, like with pipes in Unix. Composition is defined as follows:<br />
<br />
<haskell><br />
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f >>> g) t = concat [g t' | t' <- f t]<br />
</haskell><br />
<br />
This definition corresponds 1-1 to the composition of binary relations. With help of the <hask>(>>>)</hask> operator the definition of <hask>getGrandChildren</hask> becomes rather simple:<br />
<br />
<haskell><br />
getGrandChildren :: XmlFilter<br />
getGrandChildren = getChildren >>> getChildren<br />
</haskell><br />
<br />
Selecting all text nodes of the children of an element can also be formulated very easily with the help of <hask>(>>>)</hask><br />
<br />
<haskell><br />
getTextChildren :: XmlFilter<br />
getTextChildren = getChildren >>> isXText<br />
</haskell><br />
<br />
In case of predicate filter the <hask>(>>>)</hask> serves as a logical and operator, or from the relational view as an intersection operator: <hask>isA p1 >>> isA p2</hask> selects all values for which p1 and p2 both hold.<br />
<br />
The dual operator to <hask>(>>>)</hask> is the logical or, (thinking in sets: The union operator). For this we define a sum operator <hask>(<+>)</hask>. The sum of two filters is defined as follows:<br />
<br />
<haskell><br />
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f <+> g) t = f t ++ g t<br />
</haskell><br />
<br />
Example: <hask>isA p1 <+> isA p2</hask> is the locical or for filter.<br />
<br />
Combining elementary filters with (>>>) and (<+>) leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulated with:<br />
<br />
<haskell><br />
getTextChildren2 :: XmlFilter<br />
getTextChildren2 = getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
</haskell><br />
<br />
'''Exercise:''' Are these filters equivalent or what's the difference between the two filters?<br />
<br />
<haskell><br />
getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
<br />
( getChildren >>> isXText ) <+> ( getChildren >>> getChildren >>> isXText )<br />
</haskell><br />
<br />
Of course we need choice combinators. The first idea is an if-then-else filter, <br />
built up from three simpler filters. But often it's easier and more elegant to work with simpler binary combinators for choice. So we will introduce the simpler ones first.<br />
<br />
One of these choice combinators is called <hask>orElse</hask> and is defined as<br />
follows:<br />
<br />
<haskell><br />
orElse :: XmlFilter -> XmlFilter -> XmlFilter<br />
orElse f g t<br />
| null res1 = g t<br />
| otherwise = res1<br />
where<br />
res1 = f t<br />
</haskell><br />
<br />
The meaning is the following: If f computes a none empty list as result, f succeeds and this list is the result, else g is applied to the input and this yields the result. There are two other simple choice combinators usually written in infix notation, <hask> g `guards` f</hask> and <hask>f `when` g</hask>:<br />
<br />
<haskell><br />
guards :: XmlFilter -> XmlFilter -> XmlFilter<br />
guards g f t<br />
| null (g t) = []<br />
| otherwise = f t<br />
<br />
when :: XmlFilter -> XmlFilter -> XmlFilter<br />
when f g t<br />
| null (g t) = [t]<br />
| otherwise = f t<br />
</haskell><br />
<br />
These choice operators become useful when transforming and manipulation trees.<br />
<br />
=== Tree traversal filter ===<br />
<br />
A very basic operation on tree structures is the traversal of all nodes and the selection and/or transformation of nodes. Theses traversal filters serve as control structures for processing whole trees. They correspond to the map and fold combinators for lists.<br />
<br />
The simplest traversal filter does a top down search of all nodes with a special feature. This filter, called <hask>deep</hask>, is defined as follows:<br />
<br />
<haskell><br />
deep :: XmlFilter -> XmlFilter<br />
deep f = f `orElse` (getChildren >>> deep f)<br />
</haskell><br />
<br />
When a predicate filter is applied to <hask>deep</hask>, a top down search is done and all subtrees satisfying the predicate are collected. The descent into the tree stops, when a subtree is found because of the use of <hask>orElse</hask>.<br />
<br />
'''Example:''' Selecting all plain text nodes of a document can be formulated with:<br />
<br />
<haskell><br />
deep isXText<br />
</haskell><br />
<br />
'''Example:''' Selecting all "top level" tables in a HTML documents looks like<br />
this:<br />
<br />
<haskell><br />
deep (isElem >>> hasName "table")<br />
</haskell><br />
<br />
A variant of <hask>deep</hask>, called <hask>multi</hask>, performs a complete search, where the tree traversal does not stop, when a node is found.<br />
<br />
<haskell><br />
multi :: XmlFilter -> XmlFilter<br />
multi f = f <+> (getChildren >>> multi f)<br />
</haskell><br />
<br />
'''Example:''' Selecting all tables in a HTML document, even nested ones, <hask>multi</hask> has to be used instead of <hask>deep</hask>:<br />
<br />
<hask>multi (isElem >>> hasName "table")</hask><br />
<br />
=== Arrows ===<br />
<br />
We've already seen, that the filters <hask>a -> [b]</hask> are a very<br />
powerful and sometimes a more elegant way to process XML than pure<br />
function. This is the good news. The bad news is, that filter are not<br />
general enough. Of course we sometimes want to do some I/O and we want<br />
to stay in the filter level. So we need something like<br />
<br />
<haskell><br />
type XmlIOFilter = XmlTree -> IO [XmlTree]<br />
</haskell><br />
<br />
for working in the IO monad.<br />
<br />
Sometimes it's appropriate to thread some state through the computation<br />
like in state monads. This leads to a type like<br />
<br />
<haskell><br />
type XmlStateFilter state = state -> XmlTree -> (state, [XmlTree])<br />
</haskell><br />
<br />
And in real world applications we need both extensions at the same<br />
time. Of course I/O is necessary but usually there are also some<br />
global options and variables for controlling the computations. In HXT,<br />
for instance there are variables for controlling trace output, options<br />
for setting the default encoding scheme for input data and a base URI<br />
for accessing documents, which are addressed in a content or in a DTD<br />
part by relative URIs. So we need something like<br />
<br />
<haskell><br />
type XmlIOStateFilter state = state -> XmlTree -> IO (state, [XmlTree])<br />
</haskell><br />
<br />
We want to work with all four filter variants, and in the future<br />
perhaps with even more general filters, but of course not with four<br />
sets of filter names, e.g. <hask>deep, deepST, deepIO, deepIOST</hask>.<br />
<br />
This is the point where <hask>newtype</hask>s and <hask>class</hask>es<br />
come in. Classes are needed for overloading names and<br />
<hask>newtype</hask>s are needed to declare instances. Further the<br />
restriction of <hask>XmlTree</hask> as argument and result type is<br />
not neccessary and hinders reuse in many cases.<br />
<br />
A filter discussed above has all features of an arrow. Arrows are<br />
introduced for generalising the concept of functions and function<br />
combination to more general kinds of computation than pure functions.<br />
<br />
A basic set of combinators for arrows is defined in the classes in the<br />
<hask>Control.Arrow</hask> module, containing the above mentioned <hask>(>>>), (<+>), arr</hask>.<br />
<br />
In HXT the additional classes for filters working with lists as result type are<br />
defined in <hask>Control.Arrow.ArrowList</hask>. The choice operators are<br />
in <hask>Control.Arrow.ArrowIf</hask>, tree filters, like <hask>getChildren, deep, multi, ...</hask> in<br />
<hask>Control.Arrow.ArrowTree</hask> and the elementary XML specific<br />
filters in <hask>Text.XML.HXT.XmlArrow</hask>.<br />
<br />
In HXT there are four types instantiated with these classes for<br />
pure list arrows, list arrows with a state, list arrows with IO<br />
and list arrows with a state and IO.<br />
<br />
<haskell><br />
newtype LA a b = LA { runLA :: (a -> [b]) }<br />
<br />
newtype SLA s a b = SLA { runSLA :: (s -> a -> (s, [b])) }<br />
<br />
newtype IOLA a b = IOLA { runIOLA :: (a -> IO [b]) }<br />
<br />
newtype IOSLA s a b = IOSLA { runIOSLA :: (s -> a -> IO (s, [b])) }<br />
</haskell><br />
<br />
The first one and the last one are those used most frequently in the<br />
toolbox, and of course there are lifting functions for converting the<br />
special arrows into the more general ones.<br />
<br />
Don't worry about all these conceptional details. Let's have a look into some<br />
''Hello world'' examples.<br />
<br />
== Getting started: Hello world examples ==<br />
<br />
=== copyXML ===<br />
<br />
The first complete example is a program for<br />
copying an XML document<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
import System.Environment<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
[src, dst] <- getArgs<br />
runX ( readDocument [(a_validate, v_0)] src<br />
>>><br />
writeDocument [] dst<br />
)<br />
return ()<br />
</haskell><br />
<br />
The interesting part of this example is<br />
the call of <hask>runX</hask>. <hask>runX</hask> executes an<br />
arrow. This arrow is one of the more powerful list arrows with IO and<br />
a HXT system state.<br />
<br />
The arrow itself is a composition of <hask>readDocument</hask> and<br />
<hask>writeDocument</hask>.<br />
<hask>readDocument</hask> is an arrow for reading, DTD processing and<br />
validation of documents. Its behaviour can be controlled by a list of<br />
options. Here we turn off the validation step. The <hask>src</hask>, a file<br />
name or an URI is read and parsed and a document tree is built. This<br />
tree is ''piped'' into the output arrow. This one also is<br />
controlled by a set of options. Here all the defaults are used.<br />
<hask>writeDocument</hask> converts the tree into a string and writes<br />
it to the <hask>dst</hask>.<br />
<br />
We've omitted here the boring stuff of option parsing and error<br />
handling.<br />
<br />
Compilation and a test run looks like this:<br />
<br />
<pre><br />
hobel > ghc -o copyXml -package hxt CopyXML.hs<br />
hobel > cat hello.xml<br />
<hello>world</hello><br />
hobel > copyXml hello.xml -<br />
<?xml version="1.0" encoding="UTF-8"?><br />
<hello>world</hello><br />
hobel ><br />
</pre><br />
<br />
The mini XML document in file <tt>hello.xml</tt> is read and<br />
a document tree is built. Then this tree is converted into a string<br />
and written to standard output (filename: <tt>-</tt>). It is decorated<br />
with an XML declaration containing the version and the output<br />
encoding.<br />
<br />
For processing HTML documents there is a HTML parser, which tries to<br />
parse and interprete rather anything as HTML. The HTML parser can be<br />
selected by calling<br />
<br />
<hask>readDocument [(a_parse_html, v_1), ...]</hask><br />
<br />
with the apropriate option.<br />
<br />
=== Pattern for a main program ===<br />
<br />
A more realistic pattern for a simple Unix filter like program has<br />
the following structure:<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
<br />
import System.IO<br />
import System.Environment<br />
import System.Console.GetOpt<br />
import System.Exit<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
argv <- getArgs<br />
(al, src, dst) <- cmdlineOpts argv<br />
[rc] <- runX (application al src dst)<br />
if rc >= c_err<br />
then exitWith (ExitFailure (0-1))<br />
else exitWith ExitSuccess<br />
<br />
-- | the dummy for the boring stuff of option evaluation,<br />
-- usually done with 'System.Console.GetOpt'<br />
<br />
cmdlineOpts :: [String] -> IO (Attributes, String, String)<br />
cmdlineOpts argv<br />
= return ([(a_validate, v_0)], argv!!0, argv!!1)<br />
<br />
-- | the main arrow<br />
<br />
application :: Attributes -> String -> String -> IOSArrow b Int<br />
application al src dst<br />
= readDocument al src<br />
>>><br />
processChildren (processDocumentRootElement `when` isElem) -- (1)<br />
>>><br />
writeDocument al dst<br />
>>><br />
getErrStatus<br />
<br />
<br />
-- | the dummy for the real processing: the identity filter<br />
<br />
processDocumentRootElement :: IOSArrow XmlTree XmlTree<br />
processDocumentRootElement<br />
= this -- substitute this by the real application<br />
</haskell><br />
<br />
This program has the same functionality as our first example,<br />
but it separates the arrow from the boring option evaluation and<br />
return code computation.<br />
<br />
The interesing line is (1).<br />
<hask>readDocument</hask> generates a tree structure with a so called extra<br />
root node. This root node is a node above the XML document root<br />
element. The node above the XML document root element is neccessary<br />
because of possible other elements on the same tree level as the XML<br />
root, for instance comments, processing instructions or whitespace.<br />
<br />
Furthermore the artificial root node serves for storing meta<br />
information about the document in the attribute list, like the<br />
document name, the encoding scheme, the HTTP transfer headers and<br />
other information.<br />
<br />
To process the real XML root element, we have to take the children of<br />
the root node, select the XML root element and process this, but<br />
remain all other children unchanged. This is done with<br />
<hask>processChildren</hask> and the <hask>when</hask> choice<br />
operator. <hask>processChildren</hask> applies a filter elementwise to<br />
all children of a node. All results form processing the list of children from<br />
the result node.<br />
<br />
The structure of internal document tree can be made visible<br />
e.g. by adding the option pair <hask>(a_show_tree, v_1)</hask> to the<br />
<hask>writeDocument</hask> arrow. This will emit the tree in a readable<br />
text representation instead of the real document.<br />
<br />
In the next section we will give examples for the<br />
<hask>processDocumentRootElement</hask> arrow.<br />
<br />
== Selection examples ==<br />
<br />
=== Selecting text from an HTML document ===<br />
<br />
Selecting all the plain text of an XML/HTML document<br />
can be formulated with<br />
<br />
<haskell><br />
selectAllText :: ArrowXml a => a XmlTree XmlTree<br />
selectAllText<br />
= deep isXText<br />
</haskell><br />
<br />
<hask>deep</hask> traverses the whole tree, stops the traversal when<br />
a node is a text node (<hask>isXText</hask>) and returns all the text nodes.<br />
There are two other traversal operators <hask>deepest</hask> and <hask>multi</hask>,<br />
In this case, where the selected nodes are all leaves, these would give the same result.<br />
<br />
=== Selecting text and ALT attribute values ===<br />
<br />
Let's take a bit more complex task: We want to select all text, but also the values of the <tt>alt</tt> attributes<br />
of image tags.<br />
<br />
<haskell><br />
selectAllTextAndAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndAltValues<br />
= deep<br />
( isXText -- (1)<br />
<+><br />
( isElem >>> hasName "img" -- (2)<br />
>>><br />
getAttrValue "alt" -- (3)<br />
>>><br />
mkText -- (4)<br />
)<br />
)<br />
</haskell><br />
<br />
The whole tree is searched for text nodes (1) and for image elements (2), from the image elements<br />
the alt attribute values are selected as plain text (3), this text is transformed into a text node (4).<br />
<br />
=== Selecting text and ALT attributes values (2) ===<br />
<br />
Let's refine the above filter one step further. The text from the alt attributes shall be marked in the output<br />
by surrounding double square brackets. Empty alt values shall be ignored.<br />
<br />
<haskell><br />
selectAllTextAndRealAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndRealAltValues<br />
= deep<br />
( isXText<br />
<+><br />
( isElem >>> hasName "img"<br />
>>><br />
getAttrValue "alt"<br />
>>><br />
isA significant -- (1)<br />
>>><br />
arr addBrackets -- (2)<br />
>>><br />
mkText<br />
)<br />
)<br />
where<br />
significant :: String -> Bool<br />
significant = not . all (`elem` " \n\r\t")<br />
<br />
addBrackets :: String -> String<br />
addBrackets s<br />
= " [[ " ++ s ++ " ]] "<br />
</haskell><br />
<br />
This example shows two combinators for building arrows from pure functions.<br />
The first one <hask>isA</hask> removes all empty or whitespace values from alt attributes (1),<br />
the other <hask>arr</hask> lifts the editing function to the arrow level (2).<br />
<br />
== Document construction examples ==<br />
<br />
=== The ''Hello World'' document ===<br />
<br />
The first document, of course, is a ''Hello World'' document:<br />
<br />
<haskell><br />
helloWorld :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld<br />
= mkelem "html" [] -- (1)<br />
[ mkelem "head" []<br />
[ mkelem "title" []<br />
[ txt "Hello World" ] -- (2)<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ] -- (3)<br />
[ mkelem "h1" []<br />
[ txt "Hello World" ] -- (4)<br />
]<br />
]<br />
</haskell><br />
<br />
The main arrows for document construction are <hask>mkelem</hask><br />
and it's variants (<hask>selem, aelem, eelem</hask>) for element creation, <hask>attr</hask> and <hask>sattr</hask> for attributes and <hask>mktext</hask><br />
and <hask>txt</hask> for text nodes. <hask>mkelem</hask> takes three arguments, the element name (or tag name), a list of arrows for the construction of attributes, not empty in (3), and a list of arrows for the contents. Text content is generated in (2) and (4).<br />
<br />
To write this document to a file use the following arrow<br />
<br />
<haskell><br />
root [] [helloWorld] -- (1)<br />
>>><br />
writeDocument [(a_indent, v_1)] "hello.xml" -- (2)<br />
</haskell><br />
<br />
When this arrow is executed, the <hask>helloWorld</hask><br />
document is wrapped into a so called root node (1). This complete<br />
document is written to "hello.xml" (2).<br />
<hask>writeDocument</hask> and its variants always expect<br />
a whole document tree with such a root node. Before writing, the document is<br />
indented (<hask>(a_indent, v_1)</hask>)) by inserting extra whitespace<br />
text nodes, and an XML declaration with version and encoding is added. If the indent option is not given, the whole document would appears on a single line:<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8"?><br />
<html><br />
<head><br />
<title>Hello World</title><br />
</head><br />
<body class="haskell"><br />
<h1>Hello World</h1><br />
</body><br />
</html><br />
</pre><br />
<br />
The code can be shortened a bit by using some of the<br />
convenient functions:<br />
<br />
<haskell><br />
helloWorld2 :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld2<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Hello World" ]<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ]<br />
[ selem "h1"<br />
[ txt "Hello World" ]<br />
]<br />
]<br />
</haskell><br />
<br />
In the above two examples the arrow input is totally ignored, because<br />
of the use of the constant arrow <hask>txt "..."</hask>.<br />
<br />
=== A page about all images within a HTML page ===<br />
<br />
A bit more interesting task is the construction of a page<br />
containg a table of all images within a page inclusive image URLs, geometry and ALT attributes.<br />
<br />
The program for this has a frame similar to the <hask>helloWorld</hask> program,<br />
but the rows of the table must be filled in from the input document.<br />
In the first step we will generate a table with a single column containing<br />
the URL of the image.<br />
<br />
<haskell><br />
imageTable :: ArrowXml a => a XmlTree XmlTree<br />
imageTable<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Images in Page" ]<br />
]<br />
, selem "body"<br />
[ selem "h1"<br />
[ txt "Images in Page" ]<br />
, selem "table"<br />
[ collectImages -- (1)<br />
>>><br />
genTableRows -- (2)<br />
]<br />
]<br />
]<br />
where<br />
collectImages -- (1)<br />
= deep ( isElem<br />
>>><br />
hasName "img"<br />
)<br />
genTableRows -- (2)<br />
= selem "tr"<br />
[ selem "td"<br />
[ getAttrValue "src" >>> mkText ]<br />
]<br />
</haskell><br />
<br />
With (1) the image elements are collected, and with (2)<br />
the HTML code for an image element is built.<br />
<br />
Applied to <tt>http://www.haskell.org/</tt> we get the following result<br />
(at the time writing this page):<br />
<br />
<pre><br />
<html><br />
<head><br />
<title>Images in Page</title><br />
</head><br />
<body><br />
<h1>Images in Page</h1><br />
<table><br />
<tr><br />
<td>/haskellwiki_logo.png</td><br />
</tr><br />
<tr><br />
<td>/sitewiki/images/1/10/Haskelllogo-small.jpg</td><br />
</tr><br />
<tr><br />
<td>/haskellwiki_logo_small.png</td><br />
</tr><br />
</table><br />
</body><br />
</html><br />
</pre><br />
<br />
When generating HTML, often there are constant parts within the page,<br />
in the example e.g. the page header. It's possible to write these<br />
parts as a string containing plain HTML and then read this with<br />
a simple XML contents parser called <hask>xread</hask>.<br />
<br />
The example above could then be rewritten as<br />
<br />
<haskell><br />
imageTable<br />
= selem "html"<br />
[ pageHeader<br />
, ...<br />
]<br />
where<br />
pageHeader<br />
= constA "<head><title>Images in Page</title></head>"<br />
>>><br />
xread<br />
...<br />
</haskell><br />
<br />
<hask>xread</hask> is a very primitive arrow. It does not run in the<br />
IO monad, so it can be used in any context, but therefore the error handling<br />
is very limited. <hask>xread</hask> parses an XML element content.<br />
<br />
=== A page about all images within a HTML page: 1. Refinement ===<br />
<br />
The next refinement step is the extension of the table such that<br />
it contains four columns, one for the image itself, one for the URL,<br />
the geometry and the ALT text. The extended <hask>getTableRows</hask><br />
has the following form:<br />
<br />
<haskell><br />
genTableRows<br />
= selem "tr"<br />
[ selem "td" -- (1)<br />
[ this -- (1.1)<br />
]<br />
, selem "td" -- (2)<br />
[ getAttrValue "src"<br />
>>><br />
mkText<br />
>>><br />
mkelem "a" -- (2.1)<br />
[ attr "href" this ]<br />
[ this ]<br />
]<br />
, selem "td" -- (3)<br />
[ ( getAttrValue "width"<br />
&&& -- (3.1)<br />
getAttrValue "height"<br />
)<br />
>>><br />
arr2 geometry -- (3.2)<br />
>>><br />
mkText<br />
]<br />
, selem "td" -- (4)<br />
[ getAttrValue "alt"<br />
>>><br />
mkText<br />
]<br />
]<br />
where<br />
geometry :: String -> String -> String<br />
geometry "" ""<br />
= ""<br />
geometry w h<br />
= w ++ "x" ++ h<br />
</haskell><br />
<br />
In (1) the identity arrow <hask>this</hask> is used for<br />
inserting the whole image element (<hask>this</hask> value) into the first column.<br />
(2) is the column from the previous example but the URL has been made active<br />
by embedding the URL in an A-element (2.1). In (3) there are two<br />
new combinators, <hask>(&&&)</hask> (3.1) is an arrow for applying two<br />
arrows to the same input and combine the results into a pair. <hask>arr2</hask><br />
works like <hask>arr</hask> but it lifts a binary function into an arrow<br />
accepting a pair of values. <hask>arr2 f</hask> is a shortcut for<br />
<hask>arr (uncurry f)</hask>. So width and height are combined into an X11 like<br />
geometry spec. (4) adds the ALT-text.<br />
<br />
=== A page about all images within a HTML page: 2. Refinement ===<br />
<br />
The generated HTML page is not yet very useful, because it usually<br />
contains relativ HREFs to the images, so the links do not work.<br />
We have to transform the SRC attribute values into absolute URLs.<br />
This can be done with the following code:<br />
<br />
<haskell><br />
imageTable2 :: IOStateArrow s XmlTree XmlTree<br />
imageTable2<br />
= ...<br />
...<br />
, selem "table"<br />
[ collectImages<br />
>>><br />
mkAbsImageRef -- (1)<br />
>>><br />
genTableRows<br />
]<br />
...<br />
<br />
mkAbsImageRef :: IOStateArrow s XmlTree XmlTree -- (1)<br />
mkAbsImageRef<br />
= processAttrl ( mkAbsRef -- (2)<br />
`when`<br />
hasName "src" -- (3)<br />
)<br />
where<br />
mkAbsRef -- (4)<br />
= replaceChildren<br />
( xshow getChildren -- (5)<br />
>>><br />
( mkAbsURI `orElse` this ) -- (6)<br />
>>><br />
mkText -- (7)<br />
)<br />
</haskell><br />
<br />
The <hask>imageTable2</hask> is extended by an arrow <hask>mkAbsImageRef</hask><br />
(1). This arrow uses the global system state of HXT, in which the base URL<br />
of a document is stored. For editing the SRC attribute value, the attribute list<br />
of the image elements is processed with <hask>processAttrl</hask>.<br />
With the <hask>`when` hasName "src"</hask> only SRC attributes are manipulated (3). The real work is done in (4): The URL is selected with <hask>getChildren</hask>, a text node, and converted into a string (<hask>xshow</hask>), the URL is transformed into an absolute URL<br />
with <hask>mkAbsURI</hask> (6). This arrow may fail, e.g. in case of illegal<br />
URLs. In this case the URL remains unchanged (<hask>`orElse` this</hask>).<br />
The resulting String value is converted into a text node forming the new<br />
attribute value node (7).<br />
<br />
Because of the use of the use of the global HXT state in <hask>mkAbsURI</hask><br />
<hask>mkAbsRef</hask> and <hask>imageTable2</hask> need to have the more specialized signature <hask>IOStateArrow s XmlTree XmlTree</hask>.<br />
<br />
== Transformation examples ==<br />
<br />
=== Decorating external references of an HTML document ===<br />
<br />
In the following examples, we want to decorate the external references<br />
in an HTML page by a small icon, like it's done in many wikis.<br />
For this task the document tree has to be traversed, all parts<br />
except the intersting A-Elements remain unchanged. At the end of the list of children of an A-Element we add an image element.<br />
<br />
Here is the first version:<br />
<br />
<haskell><br />
addRefIcon :: ArrowXml a => a XmlTree XmlTree<br />
addRefIcon<br />
= processTopDown -- (1)<br />
( addImg -- (2)<br />
`when`<br />
isExternalRef -- (3)<br />
)<br />
where<br />
isExternalRef -- (4)<br />
= isElem<br />
>>><br />
hasName "a"<br />
>>><br />
hasAttr "href"<br />
>>><br />
getAttrValue "href"<br />
>>><br />
isA isExtRef<br />
where<br />
isExtRef -- (4.1)<br />
= isPrefixOf "http:" -- or something more precise<br />
<br />
addImg<br />
= replaceChildren -- (5)<br />
( getChildren -- (6)<br />
<+><br />
imgElement -- (7)<br />
)<br />
<br />
imgElement<br />
= mkelem "img" -- (8)<br />
[ sattr "src" "/icons/ref.png" -- (9)<br />
, sattr "alt" "external ref"<br />
] [] -- (10)<br />
</haskell><br />
<br />
The traversal is done with <hask>processTopDown</hask> (1).<br />
This arrow applies an arrow to all nodes of the whole document tree.<br />
The transformation arrow applies the <hask>addImg</hask> (2) to<br />
all A-elements (3),(4). This arrow uses a bit simplified test (4.1)<br />
for external URLs.<br />
<hask>addImg</hask> manipulates all children (5) of the A-elements by<br />
selecting the current children (6) and adding an image element (7).<br />
The image element is constructed with <hask>mkelem</hask> (8). This takes<br />
an element name, a list of arrows for computing the attributes and a<br />
list of arrows for computing the contents. The content of the image element is<br />
empty (10). The attributes are constructed with <hask>sattr</hask> (9).<br />
<hask>sattr</hask> ignores the arrow input and builds an attribute form<br />
the name value pair of arguments.<br />
<br />
=== Transform external references into absolute references ===<br />
<br />
In the following example we will develop a program for<br />
editing a HTML page such that all references to external documents<br />
(images, hypertext refs, style refs, ...) become absolute references.<br />
We will see some new, but very useful combinators in the solution.<br />
<br />
The task seems to be rather trivial. In a tree travaersal<br />
all references are edited with respect to the document base.<br />
But in HTML there is a BASE element, allowed in the content of HEAD<br />
with a HREF attribute, which defines the document base. Again this<br />
href can be a relative URL.<br />
<br />
We start the development with the editing arrow. This gets<br />
the real document base as argument.<br />
<br />
<haskell><br />
mkAbsHRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsHRefs base<br />
= processTopDown editHRef -- (1)<br />
where<br />
editHRef<br />
= processAttrl -- (3)<br />
( changeAttrValue (absHRef base) -- (5)<br />
`when`<br />
hasName "href" -- (4)<br />
)<br />
`when`<br />
( isElem >>> hasName "a" ) -- (2)<br />
where<br />
<br />
absHRef :: String -> String -> String -- (5)<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
The tree is traversed (1) and for every A element the attribute<br />
list is processed (2). All HREF attribute values (4) are manipulated<br />
by <hask>changeAttrValue</hask> called with a string function (5).<br />
<hask>expandURIString</hask> is a pure function defined in HXT for computing<br />
an absolut URI.<br />
In this first step we only edit A-HREF attribute values. We will refine this<br />
later.<br />
<br />
The second step is the complete computation of the base URL.<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( isElem >>> hasName "html" -- (0)<br />
>>><br />
getChildren -- (1)<br />
>>><br />
isElem >>> hasName "head" -- (2)<br />
>>><br />
getChildren -- (3)<br />
>>><br />
isElem >>> hasName "base" -- (4)<br />
>>><br />
getAttrValue "href" -- (5)<br />
)<br />
&&&<br />
getBaseURI -- (6)<br />
)<br />
>>> expandURI -- (7)<br />
)<br />
`orElse` getBaseURI -- (8)<br />
</haskell><br />
<br />
Input to this arrow is the HTML element, (0) to (5) is the arrow for selecting<br />
the BASE elements HREF value, parallel to this the system base URL is read<br />
with <hask>getBaseURI</hask> (6) like in examples above. The resulting <br />
pair of strings is piped into <hask>expandURI</hask> (7), the arrow version of<br />
<hask>expandURIString</hask>. This arrow ((1) to (7)) fails in the absense<br />
of a BASE element. in this case we take the plain document base (8).<br />
The selection of the BASE elements is not yet very handy. We will define<br />
a more general and elegant function later, allowing an element path as selection argument.<br />
<br />
In the third step, we will combine the to arrows. For this we will use<br />
a new combinator <hask>($<)</hask>. The need for this new combinator<br />
is the following: We need the arrow input (the document) two times,<br />
once for computing the document base, and second for editing the<br />
whole document, and we want to compute the extra string parameter<br />
for editing of course with the above defined arrow.<br />
<br />
The combined arrow, our main arrow, looks like this<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= mkAbsHRefs $< computeBaseRef -- (1)<br />
</haskell><br />
<br />
In (1) first the arrow input is piped into <hask>computeBaseRef</hask>,<br />
this result is used in <hask>mkAbsHRefs</hask> as extra string parameter<br />
when processing the document. Internally the <hask>($<)</hask> combinator<br />
is defined by the basic combinators <hask>(&&&), (>>>)</hask> and <hask>app</hask>, but in a bit more complex computations,<br />
this pattern occurs rather frequently, so ($<) becomes very useful.<br />
<br />
Programming with arrows is one style of point free programming. Point free<br />
programming often becomes unhandy when values are used more than once.<br />
One solution is the special arrow syntax supported by ghc and others, similar to the do notation for monads. But for many simple cases the <hask>($<)</hask> combinator and it's variants <hask>($<<), ($<<<), ($<<<<), ($<$)</hask><br />
is sufficient.<br />
<br />
To complete the development of the example, a last step is neccessary:<br />
The removal of the redundant BASE element.<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= ( mkAbsHRefs $< computeBaseRef )<br />
>>><br />
removeBaseElement<br />
<br />
removeBaseElement :: ArrowXml a => a XmlTree XmlTree<br />
removeBaseElement<br />
= processChildren<br />
( processChildren<br />
( none -- (1)<br />
`when`<br />
( isElem >>> hasName "base" )<br />
)<br />
`when`<br />
( isElem >>> hasName "head" )<br />
)<br />
</haskell><br />
<br />
In this function the children of the HEAD element are searched for<br />
a BASE element. This is removed by aplying the null arrow <hask>none</hask><br />
to the input, returning always the empty list.<br />
<hask>none `when` ...</hask> is the pattern for deleting nodes from a tree.<br />
<br />
The <hask>computeBaseRef</hask> function defined above contains an arrow pattern<br />
for selecting the right subtree that is rather common in HXT applications<br />
<br />
<haskell><br />
isElem >>> hasName n1<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName n2<br />
...<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName nm<br />
</haskell><br />
<br />
For this pattern we will define a convenient function creating the<br />
arrow for selection<br />
<br />
<haskell><br />
getDescendents :: ArrowXml a => [String] -> a XmlTree XmlTree<br />
getDescendents<br />
= foldl1 (\ x y -> x >>> getChildren >>> y) -- (1)<br />
.<br />
map (\ n -> isElem >>> hasName n) -- (2)<br />
</haskell><br />
<br />
The name list is mapped to the element checking arrow (2),<br />
the resulting list of arrows is folded with <hask>getChildren</hask><br />
into a single arrow. <hask>computeBaseRef</hask> can then be simplified<br />
and becomes more readable:<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( getDescendents ["html","head","base"] -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
...<br />
</haskell><br />
<br />
An even more general and flexible technic are the XPath expressions<br />
available for selection of document parts defined in the module<br />
<hask>Text.XML.HXT.Arrow.XmlNodeSet</hask>.<br />
<br />
With XPath <hask>computeBaseRef</hask> can be simplified to<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( ( getXPathTrees "/html/head/base" -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
</haskell><br />
<br />
Even the attribute selection can be expressed by XPath,<br />
so (1) and (2) can be combined into<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( xshow (getXPathTrees "/html/head/base@href")<br />
...<br />
</haskell><br />
<br />
The extra <hask>xshow</hask> is here required to convert the<br />
XPath result, an XmlTree, into a string.<br />
<br />
XPath defines a<br />
full language for selecting parts of an XML document.<br />
Sometimes it's rather comfortable to make selections of this<br />
type, but the XPath evaluation in general is more expensive<br />
in time and space than a simple combination of arrows, like we've<br />
seen it in <hask>getDescendends</hask>.<br />
<br />
=== Transform external references into absolute references: Refinement ===<br />
<br />
In the above example only A-HREF URLs are edited. Now we extend this<br />
to other element-attribute combinations.<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown ( editRef "a" "href" -- (2)<br />
>>><br />
editRef "img" "src" -- (3)<br />
>>><br />
editRef "link" "href" -- (4)<br />
>>><br />
editRef "script" "src" -- (5)<br />
)<br />
where<br />
editRef en an -- (1)<br />
= processAttrl ( changeAttrValue (absHRef base)<br />
`when`<br />
hasName an<br />
)<br />
`when`<br />
( isElem >>> hasName en )<br />
where<br />
absHRef :: String -> String -> String<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
<hask>editRef</hask> is parameterized by the element and attribute names.<br />
The arrow applied to every element is extended to a sequence of<br />
<hask>editRef</hask>'s ((2)-(5)). Notice that the document is still traversed only once.<br />
To process all possible HTML elements,<br />
this sequence should be extended by further element-attribute pairs.<br />
<br />
This can further be simplified into<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= foldl (>>>) this<br />
.<br />
map (\ (en, an) -> editRef en an)<br />
$<br />
[ ("a", "href")<br />
, ("img", "src")<br />
, ("link", "href")<br />
, ("script", "src") -- and more<br />
]<br />
editRef<br />
= ...<br />
</haskell><br />
<br />
The <hask>foldl (>>>) this</hask> is defined in HXT as <hask>seqA</hask>,<br />
so the above code can be simplified to<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= seqA . map (uncurry editRef)<br />
$<br />
...<br />
</haskell><br />
<br />
== More complex examples ==<br />
<br />
''' to be done '''<br />
<br />
=== Automatic read/writing between xml and Haskell data types ===<br />
<br />
'''Question''': is there any way to write/read Haskell types to/from XML in HXT? HaXml has readXml and showXml, but I can't find any similar mechanism in HXT. Help! -- AlsonKemp<br />
<br />
==== Serializing to Xml ====<br />
<br />
We can create an HXT tree from a single-layer data class as follows:<br />
<br />
<haskell><br />
import IO<br />
import Char<br />
import Text.XML.HXT.Arrow<br />
import Data.Generics<br />
<br />
-- our data class we'll convert into xml<br />
data Config = <br />
Config { username :: String,<br />
logNumDays :: Int,<br />
oleDbString :: String }<br />
deriving (Show, Typeable,Data)<br />
<br />
-- helper function adapted from http://www.defmacro.org/ramblings/haskell-web.html<br />
-- (gshow replaced by gshow')<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- function to create HXT tree arrow from single-layer Haskell data type:<br />
createHxtArrow object = runLA( constA ( xmlSerialize object ) >>> xread)<br />
<br />
-- create a config object to serialize:<br />
<br />
createConfig = Config { username = "test", logNumDays = 3, oleDbString = "qsdf" }<br />
<br />
-- test function, using our Config data type<br />
testConversion = createHxtArrow( createConfig ) ()<br />
</haskell><br />
<br />
-- hughperkins<br />
<br />
==== Deserializing from Xml ====<br />
<br />
Here's a solution to deserialize a simple haskell data type containing Strings and Ints.<br />
<br />
It's not really pretty, but it works.<br />
<br />
Basically, we just convert the incoming xml into gread-compatible format, then use gread :-D<br />
<br />
Currently it works for a simple single-layer Haskell data type containing Ints and Strings. You can add new child data types by adding to the case statement in xmlToGShowFormat.<br />
<br />
If someone has a more elegant solution, please let me know ( hughperkins@gmail.com )<br />
<br />
<haskell><br />
module ParseXml<br />
where<br />
<br />
import IO<br />
import Char<br />
import List<br />
import Maybe<br />
import Data.Generics hiding (Unit)<br />
import Text.XML.HXT.Arrow hiding (when)<br />
<br />
data Config = Config{ name :: String, age :: Int } <br />
--data Config = Config{ age :: Int } <br />
deriving( Data, Show, Typeable, Ord, Eq, Read )<br />
<br />
createConfig = Config "qsdfqsdf" 3<br />
--createConfig = Config 3<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- helper function from http://www.defmacro.org/ramblings/haskell-web.html<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- parse xml to HXT tree, and obtain the value of node "fieldname"<br />
-- returns a string<br />
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)<br />
| otherwise = Nothing<br />
where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName fieldname ) >>> getChildren >>> getText ))[]<br />
<br />
-- parse templateobject to get list of field names<br />
-- apply these to xml to get list of values<br />
-- return (fieldnames list, value list)<br />
xmlToGShowFormat :: Data a => String -> a -> String<br />
xmlToGShowFormat xml templateobject = <br />
go<br />
where mainconstructorname = (showConstr $ toConstr templateobject)<br />
fields = constrFields $ toConstr templateobject<br />
values = map ( \fieldname -> getValue xml fieldname ) fields<br />
datatypes = gmapQ (dataTypeOf) templateobject<br />
constrs = gmapQ (toConstr) templateobject<br />
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject<br />
fieldtogshowformat (value,datatyperep) = case datatyperep of<br />
IntRep -> "(" ++ fromJust value ++ ")"<br />
_ -> show(fromJust value)<br />
formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps)<br />
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")"<br />
<br />
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject)<br />
<br />
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config<br />
dotest' = xmlDeserialize ("<Config><age>12</age><name>test name!</name></Config>") createConfig :: Config<br />
</haskell><br />
<br />
-- hughperkins</div>Tanimotohttps://wiki.haskell.org/HXTHXT2007-11-12T09:03:49Z<p>Tanimoto: typos</p>
<hr />
<div>[[Category:Tools]] [[Category:Tutorials]]<br />
<br />
== A gentle introduction to the Haskell XML Toolbox ==<br />
<br />
The [http://www.fh-wedel.de/~si/HXmlToolbox/index.html Haskell XML Toolbox (HXT)] is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language, consisting of a set of combinators, for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace aware XML-Parser that supports almost fully the XML 1.0 Standard. Extensions are a validator for RelaxNG and an XPath evaluator.<br />
<br />
__TOC__<br />
<br />
== Background ==<br />
<br />
The Haskell XML Toolbox bases on the ideas of [http://www.cs.york.ac.uk/fp/HaXml/ HaXml] and [http://www.flightlab.com/~joe/hxml/ HXML] but introduces a more general approach for processing XML with Haskell. HXT uses a generic data model for representing XML documents, including the DTD subset, entity references, CData parts and processing instructions. This data model makes it possible to use tree transformation functions as a uniform design of XML processing steps from parsing, DTD processing, entity processing, validation, namespace propagation, content processing and output.<br />
<br />
== Resources ==<br />
<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/index.html HXT Home] :<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/HXT-7.0.tar.gz HXT-7.0.tar.gz] : lastest release<br />
; [http://darcs.fh-wedel.de/hxt/ darcs.fh-wedel.de/hxt] : darcs repository with head revision of HXT<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc_arrow/ Arrow API] : Haddock documentation of head revision with links to source files<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc/ Complete API] : Haddock documentation with arrows and old API based on filters<br />
<br />
== The basic concepts ==<br />
<br />
=== The basic data structures ===<br />
<br />
Processing of XML is a task of processing tree structures. This is can be done in Haskell in a very elegant way by defining an appropriate tree data type, a Haskell DOM (document object model) structure. The tree structure in HXT is a rose tree with a special XNode data type for storing the XML node information.<br />
<br />
The generally useful tree structure (NTree) is separated from the node type (XNode). This allows for reusing the tree structure and the tree traversal and manipulation functions in other applications.<br />
<br />
<haskell><br />
type NTree a = NTree a [NTree a] -- rose tree<br />
<br />
data XNode = XText String -- plain text node<br />
| ...<br />
| XTag QName XmlTrees -- element name and list of attributes<br />
| XAttr QName -- attribute name<br />
| ...<br />
<br />
type QName = ... -- qualified name<br />
<br />
type XmlTree = NTree XNode<br />
<br />
type XmlTrees = [XmlTree]<br />
</haskell><br />
<br />
=== The concept of filters ===<br />
<br />
Selecting, transforming and generating trees often requires routines, which compute not only a single result tree, but a (possibly empty) list of (sub-)trees. This leads to the idea of XML filters like in HaXml. Filters are functions, which take an XML tree as input and compute a list of result trees.<br />
<br />
<haskell><br />
type XmlFilter = XmlTree -> [XmlTree]<br />
</haskell><br />
<br />
More generally we can define a filter as<br />
<br />
<haskell><br />
type Filter a b = a -> [b]<br />
</haskell><br />
<br />
We will do this abstraction later, when introducing arrows. Many of the functions in the following motivating examples can be generalised this way. But for getting the idea, the <hask>XmlFilter</hask> is sufficient.<br />
<br />
The filter functions are used so frequently, that the idea of defining a domain specific language with filters as the basic processing units comes up. In such a DSL the basic filters are predicates, selectors, constructors and transformers, all working on the HXT DOM tree structure. For a DSL it becomes necessary to define an appropriate set of combinators for building more complex functions from simpler ones. Of course filter composition, like (.) becomes one of the most frequently used combinators. there are more complex filters for traversal of a whole tree and selection or transformation of several nodes. We will see a few first examples in the following part.<br />
<br />
The first task is to build filters from pure functions, to define a lift operator. Pure functions are lifted to filters in the following way:<br />
<br />
Predicates are lifted by mapping False to the empty list and True to the single element list, containing the input tree.<br />
<br />
<haskell><br />
p :: XmlTree -> Bool -- pure function<br />
p t = ...<br />
<br />
pf :: XmlTree -> [XmlTree] -- or XmlFilter<br />
pf t<br />
| p t = [t]<br />
| otherwise = []<br />
</haskell><br />
<br />
The combinator for this type of lifting is called <hask>isA</hask>, it works on any type and is defined as<br />
<br />
<haskell><br />
isA :: (a -> Bool) -> (a -> [a])<br />
isA p x<br />
| p x = [x]<br />
| otherwise = []<br />
</haskell><br />
<br />
A predicate for filtering text nodes looks like this<br />
<br />
<haskell><br />
isXText :: XmlFilter -- XmlTree -> [XmlTrees]<br />
isXText t@(NTree (XText _) _) = [t]<br />
isXText _ = []<br />
</haskell><br />
<br />
Transformers, function that map a tree into another tree, are lifted in a trivial way:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t = exp(t)<br />
<br />
ff :: XmlTree -> [XmlTree]<br />
ff t = [exp(t)]<br />
</haskell><br />
<br />
This basic function is called <hask>arr</hask>, it comes from the Control.Arrow module of the basic library package of ghc.<br />
<br />
Partial functions, functions that can't always compute a result, are usually lifted to totally defined filters:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t<br />
| p t = expr(t)<br />
| otherwise = error "f not defined"<br />
<br />
ff :: XmlFilter<br />
ff t<br />
| p t = [expr(t)]<br />
| otherwise = []<br />
</haskell><br />
<br />
This is a rather comfortable situation, with these filters we don't have to deal with illegal argument errors. Illegal arguments are just mapped to the empty list.<br />
<br />
When processing trees, there's often the case, that no, exactly one, or more than one result is possible. These functions, returning a set of results are often a bit imprecisely called ''nondeterministic'' functions. These functions, e.g. selecting all children of a node or all grandchildren, are exactly our filters. In this context lists instead of sets of values are the appropriate result type, because the ordering in XML is important and duplicates are possible.<br />
<br />
Working with filters is rather similar to working with binary relations, and working with relations is rather natural and comfortable, database people do know this very well.<br />
<br />
Two first examples for working with ''nondeterministic'' functions are selecting the children and the grandchildren of an XmlTree which can be implemented by<br />
<br />
<haskell><br />
getChildren :: XmlFilter<br />
getChildren (NTree n cs)<br />
= cs<br />
<br />
getGrandChildren :: XmlFilter<br />
getGrandChildren (NTree n cs)<br />
= concat [ getChildren c | c <- cs ]<br />
</haskell><br />
<br />
=== Filter combinators ===<br />
<br />
Composition of filters (like function composition) is the most important combinator. We will use the infix operator <hask>(>>>)</hask> for filter composition and reverse the arguments, so we can read composition sequences from left to right, like with pipes in Unix. Composition is defined as follows:<br />
<br />
<haskell><br />
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f >>> g) t = concat [g t' | t' <- f t]<br />
</haskell><br />
<br />
This definition corresponds 1-1 to the composition of binary relations. With help of the <hask>(>>>)</hask> operator the definition of <hask>getGrandChildren</hask> becomes rather simple:<br />
<br />
<haskell><br />
getGrandChildren :: XmlFilter<br />
getGrandChildren = getChildren >>> getChildren<br />
</haskell><br />
<br />
Selecting all text nodes of the children of an element can also be formulated very easily with the help of <hask>(>>>)</hask><br />
<br />
<haskell><br />
getTextChildren :: XmlFilter<br />
getTextChildren = getChildren >>> isXText<br />
</haskell><br />
<br />
In case of predicate filter the <hask>(>>>)</hask> serves as a logical and operator, or from the relational view as an intersection operator: <hask>isA p1 >>> isA p2</hask> selects all values for which p1 and p2 both hold.<br />
<br />
The dual operator to <hask>(>>>)</hask> is the logical or, (thinking in sets: The union operator). For this we define a sum operator <hask>(<+>)</hask>. The sum of two filters is defined as follows:<br />
<br />
<haskell><br />
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f <+> g) t = f t ++ g t<br />
</haskell><br />
<br />
Example: <hask>isA p1 <+> isA p2</hask> is the locical or for filter.<br />
<br />
Combining elementary filters with (>>>) and (<+>) leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulated with:<br />
<br />
<haskell><br />
getTextChildren2 :: XmlFilter<br />
getTextChildren2 = getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
</haskell><br />
<br />
'''Exercise:''' Are these filters equivalent or what's the difference between the two filters?<br />
<br />
<haskell><br />
getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
<br />
( getChildren >>> isXText ) <+> ( getChildren >>> getChildren >>> isXText )<br />
</haskell><br />
<br />
Of course we need choice combinators. The first idea is an if-then-else filter, <br />
built up from three simpler filters. But often it's easier and more elegant to work with simpler binary combinators for choice. So we will introduce the simpler ones first.<br />
<br />
One of these choice combinators is called <hask>orElse</hask> and is defined as<br />
follows:<br />
<br />
<haskell><br />
orElse :: XmlFilter -> XmlFilter -> XmlFilter<br />
orElse f g t<br />
| null res1 = g t<br />
| otherwise = res1<br />
where<br />
res1 = f t<br />
</haskell><br />
<br />
The meaning is the following: If f computes a none empty list as result, f succeeds and this list is the result, else g is applied to the input and this yields the result. There are two other simple choice combinators usually written in infix notation, <hask> g `guards` f</hask> and <hask>f `when` g</hask>:<br />
<br />
<haskell><br />
guards :: XmlFilter -> XmlFilter -> XmlFilter<br />
guards g f t<br />
| null (g t) = []<br />
| otherwise = f t<br />
<br />
when :: XmlFilter -> XmlFilter -> XmlFilter<br />
when f g t<br />
| null (g t) = [t]<br />
| otherwise = f t<br />
</haskell><br />
<br />
These choice operators become useful when transforming and manipulation trees.<br />
<br />
=== Tree traversal filter ===<br />
<br />
A very basic operation on tree structures is the traversal of all nodes and the selection and/or transformation of nodes. Theses traversal filters serve as control structures for processing whole trees. They correspond to the map and fold combinators for lists.<br />
<br />
The simplest traversal filter does a top down search of all nodes with a special feature. This filter, called <hask>deep</hask>, is defined as follows:<br />
<br />
<haskell><br />
deep :: XmlFilter -> XmlFilter<br />
deep f = f `orElse` (getChildren >>> deep f)<br />
</haskell><br />
<br />
When a predicate filter is applied to <hask>deep</hask>, a top down search is done and all subtrees satisfying the predicate are collected. The descent into the tree stops, when a subtree is found because of the use of <hask>orElse</hask>.<br />
<br />
'''Example:''' Selecting all plain text nodes of a document can be formulated with:<br />
<br />
<haskell><br />
deep isXText<br />
</haskell><br />
<br />
'''Example:''' Selecting all "top level" tables in a HTML documents looks like<br />
this:<br />
<br />
<haskell><br />
deep (isElem >>> hasName "table")<br />
</haskell><br />
<br />
A variant of <hask>deep</hask>, called <hask>multi</hask>, performs a complete search, where the tree traversal does not stop, when a node is found.<br />
<br />
<haskell><br />
multi :: XmlFilter -> XmlFilter<br />
multi f = f <+> (getChildren >>> multi f)<br />
</haskell><br />
<br />
'''Example:''' Selecting all tables in a HTML document, even nested ones, <hask>multi</hask> has to be used instead of <hask>deep</hask>:<br />
<br />
<hask>multi (isElem >>> hasName "table")</hask><br />
<br />
=== Arrows ===<br />
<br />
We've already seen, that the filters <hask>a -> [b]</hask> are a very<br />
powerful and sometimes a more elgant way to process XML than pure<br />
function. This is the good news. The bad news is, that filter are not<br />
general enough. Of course we sometimes want to do some I/O and we want<br />
to stay in the filter level. So we need something like<br />
<br />
<haskell><br />
type XmlIOFilter = XmlTree -> IO [XmlTree]<br />
</haskell><br />
<br />
for working in the IO monad.<br />
<br />
Sometimes it's apropriate to thread some state through the computation<br />
like in state monads. This leads to a type like<br />
<br />
<haskell><br />
type XmlStateFilter state = state -> XmlTree -> (state, [XmlTree])<br />
</haskell><br />
<br />
And in real world applications we need both extensions at the same<br />
time. Of course I/O is necessary but usually there are also some<br />
global options and variables for controlling the computations. In HXT,<br />
for instance there are variables for controlling trace output, options<br />
for setting the default encoding scheme for input data and a base URI<br />
for accessing documents, which are addressed in a content or in a DTD<br />
part by relative URIs. So we need something like<br />
<br />
<haskell><br />
type XmlIOStateFilter state = state -> XmlTree -> IO (state, [XmlTree])<br />
</haskell><br />
<br />
We want to work with all four filter variants, and in the future<br />
perhaps with even more general filters, but of course not with four<br />
sets of filter names, e.g. <hask>deep, deepST, deepIO, deepIOST</hask>.<br />
<br />
This is the point where <hask>newtype</hask>s and <hask>class</hask>es<br />
come in. Classes are needed for overloading names and<br />
<hask>newtype</hask>s are needed to declare instances. Further the<br />
restriction of <hask>XmlTree</hask> as argument and result type is<br />
not neccessary and hinders reuse in many cases.<br />
<br />
A filter discussed above has all features of an arrow. Arrows are<br />
introduced for generalising the concept of functions and function<br />
combination to more general kinds of computation than pure functions.<br />
<br />
A basic set of combinators for arrows is defined in the classes in the<br />
<hask>Control.Arrow</hask> module, containing the above mentioned <hask>(>>>), (<+>), arr</hask>.<br />
<br />
In HXT the additional classes for filters working with lists as result type are<br />
defined in <hask>Control.Arrow.ArrowList</hask>. The choice operators are<br />
in <hask>Control.Arrow.ArrowIf</hask>, tree filters, like <hask>getChildren, deep, multi, ...</hask> in<br />
<hask>Control.Arrow.ArrowTree</hask> and the elementary XML specific<br />
filters in <hask>Text.XML.HXT.XmlArrow</hask>.<br />
<br />
In HXT there are four types instantiated with these classes for<br />
pure list arrows, list arrows with a state, list arrows with IO<br />
and list arrows with a state and IO.<br />
<br />
<haskell><br />
newtype LA a b = LA { runLA :: (a -> [b]) }<br />
<br />
newtype SLA s a b = SLA { runSLA :: (s -> a -> (s, [b])) }<br />
<br />
newtype IOLA a b = IOLA { runIOLA :: (a -> IO [b]) }<br />
<br />
newtype IOSLA s a b = IOSLA { runIOSLA :: (s -> a -> IO (s, [b])) }<br />
</haskell><br />
<br />
The first one and the last one are those used most frequently in the<br />
toolbox, and of course there are lifting functions for converting the<br />
special arrows into the more general ones.<br />
<br />
Don't worry about all these conceptional details. Let's have a look into some<br />
''Hello world'' examples.<br />
<br />
== Getting started: Hello world examples ==<br />
<br />
=== copyXML ===<br />
<br />
The first complete example is a program for<br />
copying an XML document<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
import System.Environment<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
[src, dst] <- getArgs<br />
runX ( readDocument [(a_validate, v_0)] src<br />
>>><br />
writeDocument [] dst<br />
)<br />
return ()<br />
</haskell><br />
<br />
The interesting part of this example is<br />
the call of <hask>runX</hask>. <hask>runX</hask> executes an<br />
arrow. This arrow is one of the more powerful list arrows with IO and<br />
a HXT system state.<br />
<br />
The arrow itself is a composition of <hask>readDocument</hask> and<br />
<hask>writeDocument</hask>.<br />
<hask>readDocument</hask> is an arrow for reading, DTD processing and<br />
validation of documents. Its behaviour can be controlled by a list of<br />
options. Here we turn off the validation step. The <hask>src</hask>, a file<br />
name or an URI is read and parsed and a document tree is built. This<br />
tree is ''piped'' into the output arrow. This one also is<br />
controlled by a set of options. Here all the defaults are used.<br />
<hask>writeDocument</hask> converts the tree into a string and writes<br />
it to the <hask>dst</hask>.<br />
<br />
We've omitted here the boring stuff of option parsing and error<br />
handling.<br />
<br />
Compilation and a test run looks like this:<br />
<br />
<pre><br />
hobel > ghc -o copyXml -package hxt CopyXML.hs<br />
hobel > cat hello.xml<br />
<hello>world</hello><br />
hobel > copyXml hello.xml -<br />
<?xml version="1.0" encoding="UTF-8"?><br />
<hello>world</hello><br />
hobel ><br />
</pre><br />
<br />
The mini XML document in file <tt>hello.xml</tt> is read and<br />
a document tree is built. Then this tree is converted into a string<br />
and written to standard output (filename: <tt>-</tt>). It is decorated<br />
with an XML declaration containing the version and the output<br />
encoding.<br />
<br />
For processing HTML documents there is a HTML parser, which tries to<br />
parse and interprete rather anything as HTML. The HTML parser can be<br />
selected by calling<br />
<br />
<hask>readDocument [(a_parse_html, v_1), ...]</hask><br />
<br />
with the apropriate option.<br />
<br />
=== Pattern for a main program ===<br />
<br />
A more realistic pattern for a simple Unix filter like program has<br />
the following structure:<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
<br />
import System.IO<br />
import System.Environment<br />
import System.Console.GetOpt<br />
import System.Exit<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
argv <- getArgs<br />
(al, src, dst) <- cmdlineOpts argv<br />
[rc] <- runX (application al src dst)<br />
if rc >= c_err<br />
then exitWith (ExitFailure (0-1))<br />
else exitWith ExitSuccess<br />
<br />
-- | the dummy for the boring stuff of option evaluation,<br />
-- usually done with 'System.Console.GetOpt'<br />
<br />
cmdlineOpts :: [String] -> IO (Attributes, String, String)<br />
cmdlineOpts argv<br />
= return ([(a_validate, v_0)], argv!!0, argv!!1)<br />
<br />
-- | the main arrow<br />
<br />
application :: Attributes -> String -> String -> IOSArrow b Int<br />
application al src dst<br />
= readDocument al src<br />
>>><br />
processChildren (processDocumentRootElement `when` isElem) -- (1)<br />
>>><br />
writeDocument al dst<br />
>>><br />
getErrStatus<br />
<br />
<br />
-- | the dummy for the real processing: the identity filter<br />
<br />
processDocumentRootElement :: IOSArrow XmlTree XmlTree<br />
processDocumentRootElement<br />
= this -- substitute this by the real application<br />
</haskell><br />
<br />
This program has the same functionality as our first example,<br />
but it separates the arrow from the boring option evaluation and<br />
return code computation.<br />
<br />
The interesing line is (1).<br />
<hask>readDocument</hask> generates a tree structure with a so called extra<br />
root node. This root node is a node above the XML document root<br />
element. The node above the XML document root element is neccessary<br />
because of possible other elements on the same tree level as the XML<br />
root, for instance comments, processing instructions or whitespace.<br />
<br />
Furthermore the artificial root node serves for storing meta<br />
information about the document in the attribute list, like the<br />
document name, the encoding scheme, the HTTP transfer headers and<br />
other information.<br />
<br />
To process the real XML root element, we have to take the children of<br />
the root node, select the XML root element and process this, but<br />
remain all other children unchanged. This is done with<br />
<hask>processChildren</hask> and the <hask>when</hask> choice<br />
operator. <hask>processChildren</hask> applies a filter elementwise to<br />
all children of a node. All results form processing the list of children from<br />
the result node.<br />
<br />
The structure of internal document tree can be made visible<br />
e.g. by adding the option pair <hask>(a_show_tree, v_1)</hask> to the<br />
<hask>writeDocument</hask> arrow. This will emit the tree in a readable<br />
text representation instead of the real document.<br />
<br />
In the next section we will give examples for the<br />
<hask>processDocumentRootElement</hask> arrow.<br />
<br />
== Selection examples ==<br />
<br />
=== Selecting text from an HTML document ===<br />
<br />
Selecting all the plain text of an XML/HTML document<br />
can be formulated with<br />
<br />
<haskell><br />
selectAllText :: ArrowXml a => a XmlTree XmlTree<br />
selectAllText<br />
= deep isXText<br />
</haskell><br />
<br />
<hask>deep</hask> traverses the whole tree, stops the traversal when<br />
a node is a text node (<hask>isXText</hask>) and returns all the text nodes.<br />
There are two other traversal operators <hask>deepest</hask> and <hask>multi</hask>,<br />
In this case, where the selected nodes are all leaves, these would give the same result.<br />
<br />
=== Selecting text and ALT attribute values ===<br />
<br />
Let's take a bit more complex task: We want to select all text, but also the values of the <tt>alt</tt> attributes<br />
of image tags.<br />
<br />
<haskell><br />
selectAllTextAndAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndAltValues<br />
= deep<br />
( isXText -- (1)<br />
<+><br />
( isElem >>> hasName "img" -- (2)<br />
>>><br />
getAttrValue "alt" -- (3)<br />
>>><br />
mkText -- (4)<br />
)<br />
)<br />
</haskell><br />
<br />
The whole tree is searched for text nodes (1) and for image elements (2), from the image elements<br />
the alt attribute values are selected as plain text (3), this text is transformed into a text node (4).<br />
<br />
=== Selecting text and ALT attributes values (2) ===<br />
<br />
Let's refine the above filter one step further. The text from the alt attributes shall be marked in the output<br />
by surrounding double square brackets. Empty alt values shall be ignored.<br />
<br />
<haskell><br />
selectAllTextAndRealAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndRealAltValues<br />
= deep<br />
( isXText<br />
<+><br />
( isElem >>> hasName "img"<br />
>>><br />
getAttrValue "alt"<br />
>>><br />
isA significant -- (1)<br />
>>><br />
arr addBrackets -- (2)<br />
>>><br />
mkText<br />
)<br />
)<br />
where<br />
significant :: String -> Bool<br />
significant = not . all (`elem` " \n\r\t")<br />
<br />
addBrackets :: String -> String<br />
addBrackets s<br />
= " [[ " ++ s ++ " ]] "<br />
</haskell><br />
<br />
This example shows two combinators for building arrows from pure functions.<br />
The first one <hask>isA</hask> removes all empty or whitespace values from alt attributes (1),<br />
the other <hask>arr</hask> lifts the editing function to the arrow level (2).<br />
<br />
== Document construction examples ==<br />
<br />
=== The ''Hello World'' document ===<br />
<br />
The first document, of course, is a ''Hello World'' document:<br />
<br />
<haskell><br />
helloWorld :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld<br />
= mkelem "html" [] -- (1)<br />
[ mkelem "head" []<br />
[ mkelem "title" []<br />
[ txt "Hello World" ] -- (2)<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ] -- (3)<br />
[ mkelem "h1" []<br />
[ txt "Hello World" ] -- (4)<br />
]<br />
]<br />
</haskell><br />
<br />
The main arrows for document construction are <hask>mkelem</hask><br />
and it's variants (<hask>selem, aelem, eelem</hask>) for element creation, <hask>attr</hask> and <hask>sattr</hask> for attributes and <hask>mktext</hask><br />
and <hask>txt</hask> for text nodes. <hask>mkelem</hask> takes three arguments, the element name (or tag name), a list of arrows for the construction of attributes, not empty in (3), and a list of arrows for the contents. Text content is generated in (2) and (4).<br />
<br />
To write this document to a file use the following arrow<br />
<br />
<haskell><br />
root [] [helloWorld] -- (1)<br />
>>><br />
writeDocument [(a_indent, v_1)] "hello.xml" -- (2)<br />
</haskell><br />
<br />
When this arrow is executed, the <hask>helloWorld</hask><br />
document is wrapped into a so called root node (1). This complete<br />
document is written to "hello.xml" (2).<br />
<hask>writeDocument</hask> and its variants always expect<br />
a whole document tree with such a root node. Before writing, the document is<br />
indented (<hask>(a_indent, v_1)</hask>)) by inserting extra whitespace<br />
text nodes, and an XML declaration with version and encoding is added. If the indent option is not given, the whole document would appears on a single line:<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8"?><br />
<html><br />
<head><br />
<title>Hello World</title><br />
</head><br />
<body class="haskell"><br />
<h1>Hello World</h1><br />
</body><br />
</html><br />
</pre><br />
<br />
The code can be shortened a bit by using some of the<br />
convenient functions:<br />
<br />
<haskell><br />
helloWorld2 :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld2<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Hello World" ]<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ]<br />
[ selem "h1"<br />
[ txt "Hello World" ]<br />
]<br />
]<br />
</haskell><br />
<br />
In the above two examples the arrow input is totally ignored, because<br />
of the use of the constant arrow <hask>txt "..."</hask>.<br />
<br />
=== A page about all images within a HTML page ===<br />
<br />
A bit more interesting task is the construction of a page<br />
containg a table of all images within a page inclusive image URLs, geometry and ALT attributes.<br />
<br />
The program for this has a frame similar to the <hask>helloWorld</hask> program,<br />
but the rows of the table must be filled in from the input document.<br />
In the first step we will generate a table with a single column containing<br />
the URL of the image.<br />
<br />
<haskell><br />
imageTable :: ArrowXml a => a XmlTree XmlTree<br />
imageTable<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Images in Page" ]<br />
]<br />
, selem "body"<br />
[ selem "h1"<br />
[ txt "Images in Page" ]<br />
, selem "table"<br />
[ collectImages -- (1)<br />
>>><br />
genTableRows -- (2)<br />
]<br />
]<br />
]<br />
where<br />
collectImages -- (1)<br />
= deep ( isElem<br />
>>><br />
hasName "img"<br />
)<br />
genTableRows -- (2)<br />
= selem "tr"<br />
[ selem "td"<br />
[ getAttrValue "src" >>> mkText ]<br />
]<br />
</haskell><br />
<br />
With (1) the image elements are collected, and with (2)<br />
the HTML code for an image element is built.<br />
<br />
Applied to <tt>http://www.haskell.org/</tt> we get the following result<br />
(at the time writing this page):<br />
<br />
<pre><br />
<html><br />
<head><br />
<title>Images in Page</title><br />
</head><br />
<body><br />
<h1>Images in Page</h1><br />
<table><br />
<tr><br />
<td>/haskellwiki_logo.png</td><br />
</tr><br />
<tr><br />
<td>/sitewiki/images/1/10/Haskelllogo-small.jpg</td><br />
</tr><br />
<tr><br />
<td>/haskellwiki_logo_small.png</td><br />
</tr><br />
</table><br />
</body><br />
</html><br />
</pre><br />
<br />
When generating HTML, often there are constant parts within the page,<br />
in the example e.g. the page header. It's possible to write these<br />
parts as a string containing plain HTML and then read this with<br />
a simple XML contents parser called <hask>xread</hask>.<br />
<br />
The example above could then be rewritten as<br />
<br />
<haskell><br />
imageTable<br />
= selem "html"<br />
[ pageHeader<br />
, ...<br />
]<br />
where<br />
pageHeader<br />
= constA "<head><title>Images in Page</title></head>"<br />
>>><br />
xread<br />
...<br />
</haskell><br />
<br />
<hask>xread</hask> is a very primitive arrow. It does not run in the<br />
IO monad, so it can be used in any context, but therefore the error handling<br />
is very limited. <hask>xread</hask> parses an XML element content.<br />
<br />
=== A page about all images within a HTML page: 1. Refinement ===<br />
<br />
The next refinement step is the extension of the table such that<br />
it contains four columns, one for the image itself, one for the URL,<br />
the geometry and the ALT text. The extended <hask>getTableRows</hask><br />
has the following form:<br />
<br />
<haskell><br />
genTableRows<br />
= selem "tr"<br />
[ selem "td" -- (1)<br />
[ this -- (1.1)<br />
]<br />
, selem "td" -- (2)<br />
[ getAttrValue "src"<br />
>>><br />
mkText<br />
>>><br />
mkelem "a" -- (2.1)<br />
[ attr "href" this ]<br />
[ this ]<br />
]<br />
, selem "td" -- (3)<br />
[ ( getAttrValue "width"<br />
&&& -- (3.1)<br />
getAttrValue "height"<br />
)<br />
>>><br />
arr2 geometry -- (3.2)<br />
>>><br />
mkText<br />
]<br />
, selem "td" -- (4)<br />
[ getAttrValue "alt"<br />
>>><br />
mkText<br />
]<br />
]<br />
where<br />
geometry :: String -> String -> String<br />
geometry "" ""<br />
= ""<br />
geometry w h<br />
= w ++ "x" ++ h<br />
</haskell><br />
<br />
In (1) the identity arrow <hask>this</hask> is used for<br />
inserting the whole image element (<hask>this</hask> value) into the first column.<br />
(2) is the column from the previous example but the URL has been made active<br />
by embedding the URL in an A-element (2.1). In (3) there are two<br />
new combinators, <hask>(&&&)</hask> (3.1) is an arrow for applying two<br />
arrows to the same input and combine the results into a pair. <hask>arr2</hask><br />
works like <hask>arr</hask> but it lifts a binary function into an arrow<br />
accepting a pair of values. <hask>arr2 f</hask> is a shortcut for<br />
<hask>arr (uncurry f)</hask>. So width and height are combined into an X11 like<br />
geometry spec. (4) adds the ALT-text.<br />
<br />
=== A page about all images within a HTML page: 2. Refinement ===<br />
<br />
The generated HTML page is not yet very useful, because it usually<br />
contains relativ HREFs to the images, so the links do not work.<br />
We have to transform the SRC attribute values into absolute URLs.<br />
This can be done with the following code:<br />
<br />
<haskell><br />
imageTable2 :: IOStateArrow s XmlTree XmlTree<br />
imageTable2<br />
= ...<br />
...<br />
, selem "table"<br />
[ collectImages<br />
>>><br />
mkAbsImageRef -- (1)<br />
>>><br />
genTableRows<br />
]<br />
...<br />
<br />
mkAbsImageRef :: IOStateArrow s XmlTree XmlTree -- (1)<br />
mkAbsImageRef<br />
= processAttrl ( mkAbsRef -- (2)<br />
`when`<br />
hasName "src" -- (3)<br />
)<br />
where<br />
mkAbsRef -- (4)<br />
= replaceChildren<br />
( xshow getChildren -- (5)<br />
>>><br />
( mkAbsURI `orElse` this ) -- (6)<br />
>>><br />
mkText -- (7)<br />
)<br />
</haskell><br />
<br />
The <hask>imageTable2</hask> is extended by an arrow <hask>mkAbsImageRef</hask><br />
(1). This arrow uses the global system state of HXT, in which the base URL<br />
of a document is stored. For editing the SRC attribute value, the attribute list<br />
of the image elements is processed with <hask>processAttrl</hask>.<br />
With the <hask>`when` hasName "src"</hask> only SRC attributes are manipulated (3). The real work is done in (4): The URL is selected with <hask>getChildren</hask>, a text node, and converted into a string (<hask>xshow</hask>), the URL is transformed into an absolute URL<br />
with <hask>mkAbsURI</hask> (6). This arrow may fail, e.g. in case of illegal<br />
URLs. In this case the URL remains unchanged (<hask>`orElse` this</hask>).<br />
The resulting String value is converted into a text node forming the new<br />
attribute value node (7).<br />
<br />
Because of the use of the use of the global HXT state in <hask>mkAbsURI</hask><br />
<hask>mkAbsRef</hask> and <hask>imageTable2</hask> need to have the more specialized signature <hask>IOStateArrow s XmlTree XmlTree</hask>.<br />
<br />
== Transformation examples ==<br />
<br />
=== Decorating external references of an HTML document ===<br />
<br />
In the following examples, we want to decorate the external references<br />
in an HTML page by a small icon, like it's done in many wikis.<br />
For this task the document tree has to be traversed, all parts<br />
except the intersting A-Elements remain unchanged. At the end of the list of children of an A-Element we add an image element.<br />
<br />
Here is the first version:<br />
<br />
<haskell><br />
addRefIcon :: ArrowXml a => a XmlTree XmlTree<br />
addRefIcon<br />
= processTopDown -- (1)<br />
( addImg -- (2)<br />
`when`<br />
isExternalRef -- (3)<br />
)<br />
where<br />
isExternalRef -- (4)<br />
= isElem<br />
>>><br />
hasName "a"<br />
>>><br />
hasAttr "href"<br />
>>><br />
getAttrValue "href"<br />
>>><br />
isA isExtRef<br />
where<br />
isExtRef -- (4.1)<br />
= isPrefixOf "http:" -- or something more precise<br />
<br />
addImg<br />
= replaceChildren -- (5)<br />
( getChildren -- (6)<br />
<+><br />
imgElement -- (7)<br />
)<br />
<br />
imgElement<br />
= mkelem "img" -- (8)<br />
[ sattr "src" "/icons/ref.png" -- (9)<br />
, sattr "alt" "external ref"<br />
] [] -- (10)<br />
</haskell><br />
<br />
The traversal is done with <hask>processTopDown</hask> (1).<br />
This arrow applies an arrow to all nodes of the whole document tree.<br />
The transformation arrow applies the <hask>addImg</hask> (2) to<br />
all A-elements (3),(4). This arrow uses a bit simplified test (4.1)<br />
for external URLs.<br />
<hask>addImg</hask> manipulates all children (5) of the A-elements by<br />
selecting the current children (6) and adding an image element (7).<br />
The image element is constructed with <hask>mkelem</hask> (8). This takes<br />
an element name, a list of arrows for computing the attributes and a<br />
list of arrows for computing the contents. The content of the image element is<br />
empty (10). The attributes are constructed with <hask>sattr</hask> (9).<br />
<hask>sattr</hask> ignores the arrow input and builds an attribute form<br />
the name value pair of arguments.<br />
<br />
=== Transform external references into absolute references ===<br />
<br />
In the following example we will develop a program for<br />
editing a HTML page such that all references to external documents<br />
(images, hypertext refs, style refs, ...) become absolute references.<br />
We will see some new, but very useful combinators in the solution.<br />
<br />
The task seems to be rather trivial. In a tree travaersal<br />
all references are edited with respect to the document base.<br />
But in HTML there is a BASE element, allowed in the content of HEAD<br />
with a HREF attribute, which defines the document base. Again this<br />
href can be a relative URL.<br />
<br />
We start the development with the editing arrow. This gets<br />
the real document base as argument.<br />
<br />
<haskell><br />
mkAbsHRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsHRefs base<br />
= processTopDown editHRef -- (1)<br />
where<br />
editHRef<br />
= processAttrl -- (3)<br />
( changeAttrValue (absHRef base) -- (5)<br />
`when`<br />
hasName "href" -- (4)<br />
)<br />
`when`<br />
( isElem >>> hasName "a" ) -- (2)<br />
where<br />
<br />
absHRef :: String -> String -> String -- (5)<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
The tree is traversed (1) and for every A element the attribute<br />
list is processed (2). All HREF attribute values (4) are manipulated<br />
by <hask>changeAttrValue</hask> called with a string function (5).<br />
<hask>expandURIString</hask> is a pure function defined in HXT for computing<br />
an absolut URI.<br />
In this first step we only edit A-HREF attribute values. We will refine this<br />
later.<br />
<br />
The second step is the complete computation of the base URL.<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( isElem >>> hasName "html" -- (0)<br />
>>><br />
getChildren -- (1)<br />
>>><br />
isElem >>> hasName "head" -- (2)<br />
>>><br />
getChildren -- (3)<br />
>>><br />
isElem >>> hasName "base" -- (4)<br />
>>><br />
getAttrValue "href" -- (5)<br />
)<br />
&&&<br />
getBaseURI -- (6)<br />
)<br />
>>> expandURI -- (7)<br />
)<br />
`orElse` getBaseURI -- (8)<br />
</haskell><br />
<br />
Input to this arrow is the HTML element, (0) to (5) is the arrow for selecting<br />
the BASE elements HREF value, parallel to this the system base URL is read<br />
with <hask>getBaseURI</hask> (6) like in examples above. The resulting <br />
pair of strings is piped into <hask>expandURI</hask> (7), the arrow version of<br />
<hask>expandURIString</hask>. This arrow ((1) to (7)) fails in the absense<br />
of a BASE element. in this case we take the plain document base (8).<br />
The selection of the BASE elements is not yet very handy. We will define<br />
a more general and elegant function later, allowing an element path as selection argument.<br />
<br />
In the third step, we will combine the to arrows. For this we will use<br />
a new combinator <hask>($<)</hask>. The need for this new combinator<br />
is the following: We need the arrow input (the document) two times,<br />
once for computing the document base, and second for editing the<br />
whole document, and we want to compute the extra string parameter<br />
for editing of course with the above defined arrow.<br />
<br />
The combined arrow, our main arrow, looks like this<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= mkAbsHRefs $< computeBaseRef -- (1)<br />
</haskell><br />
<br />
In (1) first the arrow input is piped into <hask>computeBaseRef</hask>,<br />
this result is used in <hask>mkAbsHRefs</hask> as extra string parameter<br />
when processing the document. Internally the <hask>($<)</hask> combinator<br />
is defined by the basic combinators <hask>(&&&), (>>>)</hask> and <hask>app</hask>, but in a bit more complex computations,<br />
this pattern occurs rather frequently, so ($<) becomes very useful.<br />
<br />
Programming with arrows is one style of point free programming. Point free<br />
programming often becomes unhandy when values are used more than once.<br />
One solution is the special arrow syntax supported by ghc and others, similar to the do notation for monads. But for many simple cases the <hask>($<)</hask> combinator and it's variants <hask>($<<), ($<<<), ($<<<<), ($<$)</hask><br />
is sufficient.<br />
<br />
To complete the development of the example, a last step is neccessary:<br />
The removal of the redundant BASE element.<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= ( mkAbsHRefs $< computeBaseRef )<br />
>>><br />
removeBaseElement<br />
<br />
removeBaseElement :: ArrowXml a => a XmlTree XmlTree<br />
removeBaseElement<br />
= processChildren<br />
( processChildren<br />
( none -- (1)<br />
`when`<br />
( isElem >>> hasName "base" )<br />
)<br />
`when`<br />
( isElem >>> hasName "head" )<br />
)<br />
</haskell><br />
<br />
In this function the children of the HEAD element are searched for<br />
a BASE element. This is removed by aplying the null arrow <hask>none</hask><br />
to the input, returning always the empty list.<br />
<hask>none `when` ...</hask> is the pattern for deleting nodes from a tree.<br />
<br />
The <hask>computeBaseRef</hask> function defined above contains an arrow pattern<br />
for selecting the right subtree that is rather common in HXT applications<br />
<br />
<haskell><br />
isElem >>> hasName n1<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName n2<br />
...<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName nm<br />
</haskell><br />
<br />
For this pattern we will define a convenient function creating the<br />
arrow for selection<br />
<br />
<haskell><br />
getDescendents :: ArrowXml a => [String] -> a XmlTree XmlTree<br />
getDescendents<br />
= foldl1 (\ x y -> x >>> getChildren >>> y) -- (1)<br />
.<br />
map (\ n -> isElem >>> hasName n) -- (2)<br />
</haskell><br />
<br />
The name list is mapped to the element checking arrow (2),<br />
the resulting list of arrows is folded with <hask>getChildren</hask><br />
into a single arrow. <hask>computeBaseRef</hask> can then be simplified<br />
and becomes more readable:<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( getDescendents ["html","head","base"] -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
...<br />
</haskell><br />
<br />
An even more general and flexible technic are the XPath expressions<br />
available for selection of document parts defined in the module<br />
<hask>Text.XML.HXT.Arrow.XmlNodeSet</hask>.<br />
<br />
With XPath <hask>computeBaseRef</hask> can be simplified to<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( ( getXPathTrees "/html/head/base" -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
</haskell><br />
<br />
Even the attribute selection can be expressed by XPath,<br />
so (1) and (2) can be combined into<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( xshow (getXPathTrees "/html/head/base@href")<br />
...<br />
</haskell><br />
<br />
The extra <hask>xshow</hask> is here required to convert the<br />
XPath result, an XmlTree, into a string.<br />
<br />
XPath defines a<br />
full language for selecting parts of an XML document.<br />
Sometimes it's rather comfortable to make selections of this<br />
type, but the XPath evaluation in general is more expensive<br />
in time and space than a simple combination of arrows, like we've<br />
seen it in <hask>getDescendends</hask>.<br />
<br />
=== Transform external references into absolute references: Refinement ===<br />
<br />
In the above example only A-HREF URLs are edited. Now we extend this<br />
to other element-attribute combinations.<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown ( editRef "a" "href" -- (2)<br />
>>><br />
editRef "img" "src" -- (3)<br />
>>><br />
editRef "link" "href" -- (4)<br />
>>><br />
editRef "script" "src" -- (5)<br />
)<br />
where<br />
editRef en an -- (1)<br />
= processAttrl ( changeAttrValue (absHRef base)<br />
`when`<br />
hasName an<br />
)<br />
`when`<br />
( isElem >>> hasName en )<br />
where<br />
absHRef :: String -> String -> String<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
<hask>editRef</hask> is parameterized by the element and attribute names.<br />
The arrow applied to every element is extended to a sequence of<br />
<hask>editRef</hask>'s ((2)-(5)). Notice that the document is still traversed only once.<br />
To process all possible HTML elements,<br />
this sequence should be extended by further element-attribute pairs.<br />
<br />
This can further be simplified into<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= foldl (>>>) this<br />
.<br />
map (\ (en, an) -> editRef en an)<br />
$<br />
[ ("a", "href")<br />
, ("img", "src")<br />
, ("link", "href")<br />
, ("script", "src") -- and more<br />
]<br />
editRef<br />
= ...<br />
</haskell><br />
<br />
The <hask>foldl (>>>) this</hask> is defined in HXT as <hask>seqA</hask>,<br />
so the above code can be simplified to<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= seqA . map (uncurry editRef)<br />
$<br />
...<br />
</haskell><br />
<br />
== More complex examples ==<br />
<br />
''' to be done '''<br />
<br />
=== Automatic read/writing between xml and Haskell data types ===<br />
<br />
'''Question''': is there any way to write/read Haskell types to/from XML in HXT? HaXml has readXml and showXml, but I can't find any similar mechanism in HXT. Help! -- AlsonKemp<br />
<br />
==== Serializing to Xml ====<br />
<br />
We can create an HXT tree from a single-layer data class as follows:<br />
<br />
<haskell><br />
import IO<br />
import Char<br />
import Text.XML.HXT.Arrow<br />
import Data.Generics<br />
<br />
-- our data class we'll convert into xml<br />
data Config = <br />
Config { username :: String,<br />
logNumDays :: Int,<br />
oleDbString :: String }<br />
deriving (Show, Typeable,Data)<br />
<br />
-- helper function adapted from http://www.defmacro.org/ramblings/haskell-web.html<br />
-- (gshow replaced by gshow')<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- function to create HXT tree arrow from single-layer Haskell data type:<br />
createHxtArrow object = runLA( constA ( xmlSerialize object ) >>> xread)<br />
<br />
-- create a config object to serialize:<br />
<br />
createConfig = Config { username = "test", logNumDays = 3, oleDbString = "qsdf" }<br />
<br />
-- test function, using our Config data type<br />
testConversion = createHxtArrow( createConfig ) ()<br />
</haskell><br />
<br />
-- hughperkins<br />
<br />
==== Deserializing from Xml ====<br />
<br />
Here's a solution to deserialize a simple haskell data type containing Strings and Ints.<br />
<br />
It's not really pretty, but it works.<br />
<br />
Basically, we just convert the incoming xml into gread-compatible format, then use gread :-D<br />
<br />
Currently it works for a simple single-layer Haskell data type containing Ints and Strings. You can add new child data types by adding to the case statement in xmlToGShowFormat.<br />
<br />
If someone has a more elegant solution, please let me know ( hughperkins@gmail.com )<br />
<br />
<haskell><br />
module ParseXml<br />
where<br />
<br />
import IO<br />
import Char<br />
import List<br />
import Maybe<br />
import Data.Generics hiding (Unit)<br />
import Text.XML.HXT.Arrow hiding (when)<br />
<br />
data Config = Config{ name :: String, age :: Int } <br />
--data Config = Config{ age :: Int } <br />
deriving( Data, Show, Typeable, Ord, Eq, Read )<br />
<br />
createConfig = Config "qsdfqsdf" 3<br />
--createConfig = Config 3<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- helper function from http://www.defmacro.org/ramblings/haskell-web.html<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- parse xml to HXT tree, and obtain the value of node "fieldname"<br />
-- returns a string<br />
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)<br />
| otherwise = Nothing<br />
where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName fieldname ) >>> getChildren >>> getText ))[]<br />
<br />
-- parse templateobject to get list of field names<br />
-- apply these to xml to get list of values<br />
-- return (fieldnames list, value list)<br />
xmlToGShowFormat :: Data a => String -> a -> String<br />
xmlToGShowFormat xml templateobject = <br />
go<br />
where mainconstructorname = (showConstr $ toConstr templateobject)<br />
fields = constrFields $ toConstr templateobject<br />
values = map ( \fieldname -> getValue xml fieldname ) fields<br />
datatypes = gmapQ (dataTypeOf) templateobject<br />
constrs = gmapQ (toConstr) templateobject<br />
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject<br />
fieldtogshowformat (value,datatyperep) = case datatyperep of<br />
IntRep -> "(" ++ fromJust value ++ ")"<br />
_ -> show(fromJust value)<br />
formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps)<br />
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")"<br />
<br />
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject)<br />
<br />
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config<br />
dotest' = xmlDeserialize ("<Config><age>12</age><name>test name!</name></Config>") createConfig :: Config<br />
</haskell><br />
<br />
-- hughperkins</div>Tanimotohttps://wiki.haskell.org/HXTHXT2007-11-12T00:28:49Z<p>Tanimoto: More typos.</p>
<hr />
<div>[[Category:Tools]] [[Category:Tutorials]]<br />
<br />
== A gentle introduction to the Haskell XML Toolbox ==<br />
<br />
The [http://www.fh-wedel.de/~si/HXmlToolbox/index.html Haskell XML Toolbox (HXT)] is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language, consisting of a set of combinators, for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace aware XML-Parser that supports almost fully the XML 1.0 Standard. Extensions are a validator for RelaxNG and an XPath evaluator.<br />
<br />
__TOC__<br />
<br />
== Background ==<br />
<br />
The Haskell XML Toolbox bases on the ideas of [http://www.cs.york.ac.uk/fp/HaXml/ HaXml] and [http://www.flightlab.com/~joe/hxml/ HXML] but introduces a more general approach for processing XML with Haskell. HXT uses a generic data model for representing XML documents, including the DTD subset, entity references, CData parts and processing instructions. This data model makes it possible to use tree transformation functions as a uniform design of XML processing steps from parsing, DTD processing, entity processing, validation, namespace propagation, content processing and output.<br />
<br />
== Resources ==<br />
<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/index.html HXT Home] :<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/HXT-7.0.tar.gz HXT-7.0.tar.gz] : lastest release<br />
; [http://darcs.fh-wedel.de/hxt/ darcs.fh-wedel.de/hxt] : darcs repository with head revision of HXT<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc_arrow/ Arrow API] : Haddock documentation of head revision with links to source files<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc/ Complete API] : Haddock documentation with arrows and old API based on filters<br />
<br />
== The basic concepts ==<br />
<br />
=== The basic data structures ===<br />
<br />
Processing of XML is a task of processing tree structures. This is can be done in Haskell in a very elegant way by defining an appropriate tree data type, a Haskell DOM (document object model) structure. The tree structure in HXT is a rose tree with a special XNode data type for storing the XML node information.<br />
<br />
The generally useful tree structure (NTree) is separated from the node type (XNode). This allows for reusing the tree structure and the tree traversal and manipulation functions in other applications.<br />
<br />
<haskell><br />
type NTree a = NTree a [NTree a] -- rose tree<br />
<br />
data XNode = XText String -- plain text node<br />
| ...<br />
| XTag QName XmlTrees -- element name and list of attributes<br />
| XAttr QName -- attribute name<br />
| ...<br />
<br />
type QName = ... -- qualified name<br />
<br />
type XmlTree = NTree XNode<br />
<br />
type XmlTrees = [XmlTree]<br />
</haskell><br />
<br />
=== The concept of filters ===<br />
<br />
Selecting, transforming and generating trees often requires routines, which compute not only a single result tree, but a (possibly empty) list of (sub-)trees. This leads to the idea of XML filters like in HaXml. Filters are functions, which take an XML tree as input and compute a list of result trees.<br />
<br />
<haskell><br />
type XmlFilter = XmlTree -> [XmlTree]<br />
</haskell><br />
<br />
More generally we can define a filter as<br />
<br />
<haskell><br />
type Filter a b = a -> [b]<br />
</haskell><br />
<br />
We will do this abstraction later, when introducing arrows. Many of the functions in the following motivating examples can be generalised this way. But for getting the idea, the <hask>XmlFilter</hask> is sufficient.<br />
<br />
The filter functions are used so frequently, that the idea of defining a domain specific language with filters as the basic processing units comes up. In such a DSL the basic filters are predicates, selectors, constructors and transformers, all working on the HXT DOM tree structure. For a DSL it becomes necessary to define an appropriate set of combinators for building more complex functions from simpler ones. Of course filter composition, like (.) becomes one of the most frequently used combinators. there are more complex filters for traversal of a whole tree and selection or transformation of several nodes. We will see a few first examples in the following part.<br />
<br />
The first task is to build filters from pure functions, to define a lift operator. Pure functions are lifted to filters in the following way:<br />
<br />
Predicates are lifted by mapping False to the empty list and True to the single element list, containing the input tree.<br />
<br />
<haskell><br />
p :: XmlTree -> Bool -- pure function<br />
p t = ...<br />
<br />
pf :: XmlTree -> [XmlTree] -- or XmlFilter<br />
pf t<br />
| p t = [t]<br />
| otherwise = []<br />
</haskell><br />
<br />
The combinator for this type of lifting is called <hask>isA</hask>, it works on any type and is defined as<br />
<br />
<haskell><br />
isA :: (a -> Bool) -> (a -> [a])<br />
isA p x<br />
| p x = [x]<br />
| otherwise = []<br />
</haskell><br />
<br />
A predicate for filtering text nodes looks like this<br />
<br />
<haskell><br />
isXText :: XmlFilter -- XmlTree -> [XmlTrees]<br />
isXText t@(NTree (XText _) _) = [t]<br />
isXText _ = []<br />
</haskell><br />
<br />
Transformers, function that map a tree into another tree, are lifted in a trivial way:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t = exp(t)<br />
<br />
ff :: XmlTree -> [XmlTree]<br />
ff t = [exp(t)]<br />
</haskell><br />
<br />
This basic function is called <hask>arr</hask>, it comes from the Control.Arrow module of the basic library package of ghc.<br />
<br />
Partial functions, functions that can't always compute a result, are usually lifted to totally defined filters:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t<br />
| p t = expr(t)<br />
| otherwise = error "f not defined"<br />
<br />
ff :: XmlFilter<br />
ff t<br />
| p t = [expr(t)]<br />
| otherwise = []<br />
</haskell><br />
<br />
This is a rather comfortable situation, with these filters we don't have to deal with illegal argument errors. Illegal arguments are just mapped to the empty list.<br />
<br />
When processing trees, there's often the case, that no, exactly one, or more than one result is possible. These functions, returning a set of results are often a bit imprecisely called ''nondeterministic'' functions. These functions, e.g. selecting all children of a node or all grandchildren, are exactly our filters. In this context lists instead of sets of values are the appropriate result type, because the ordering in XML is important and duplicates are possible.<br />
<br />
Working with filters is rather similar to working with binary relations, and working with relations is rather natural and comfortable, database people do know this very well.<br />
<br />
Two first examples for working with ''nondeterministic'' functions are selecting the children and the grandchildren of an XmlTree which can be implemented by<br />
<br />
<haskell><br />
getChildren :: XmlFilter<br />
getChildren (NTree n cs)<br />
= cs<br />
<br />
getGrandChildren :: XmlFilter<br />
getGrandChildren (NTree n cs)<br />
= concat [ getChildren c | c <- cs ]<br />
</haskell><br />
<br />
=== Filter combinators ===<br />
<br />
Composition of filters (like function composition) is the most important combinator. We will use the infix operator <hask>(>>>)</hask> for filter composition and reverse the arguments, so we can read composition sequences from left to right, like with pipes in Unix. Composition is defined as follows:<br />
<br />
<haskell><br />
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f >>> g) t = concat [g t' | t' <- f t]<br />
</haskell><br />
<br />
This definition corresponds 1-1 to the composition of binary relations. With help of the <hask>(>>>)</hask> operator the definition of <hask>getGrandChildren</hask> becomes rather simple:<br />
<br />
<haskell><br />
getGrandChildren :: XmlFilter<br />
getGrandChildren = getChildren >>> getChildren<br />
</haskell><br />
<br />
Selecting all text nodes of the children of an element can also be formulated very easily with the help of <hask>(>>>)</hask><br />
<br />
<haskell><br />
getTextChildren :: XmlFilter<br />
getTextChildren = getChildren >>> isXText<br />
</haskell><br />
<br />
In case of predicate filter the <hask>(>>>)</hask> serves as a logical and operator, or from the relational view as an intersection operator: <hask>isA p1 >>> isA p2</hask> selects all values for which p1 and p2 both hold.<br />
<br />
The dual operator to <hask>(>>>)</hask> is the locical or, (thinking in sets: The union operator). For this we define a sum operator <hask>(<+>)</hask>. The sum of two filters is defined as follows:<br />
<br />
<haskell><br />
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f <+> g) t = f t ++ g t<br />
</haskell><br />
<br />
Example: <hask>isA p1 <+> isA p2</hask> is the locical or for filter.<br />
<br />
Combining elementary filters with (>>>) and (<+>) leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulated with:<br />
<br />
<haskell><br />
getTextChildren2 :: XmlFilter<br />
getTextChildren2 = getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
</haskell><br />
<br />
'''Exercise:''' Are these filters equivalent or what's the difference between the two filters?<br />
<br />
<haskell><br />
getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
<br />
( getChildren >>> isXText ) <+> ( getChildren >>> getChildren >>> isXText )<br />
</haskell><br />
<br />
Of course we need choice combinators. The first idea is an if-then-else filter, <br />
built up from three simpler filters. But often it's easier and more elegant to work with simpler binary combinators for choice. So we will introduce the simpler ones first.<br />
<br />
One of these choice combinators is called <hask>orElse</hask> and is defined as<br />
follows:<br />
<br />
<haskell><br />
orElse :: XmlFilter -> XmlFilter -> XmlFilter<br />
orElse f g t<br />
| null res1 = g t<br />
| otherwise = res1<br />
where<br />
res1 = f t<br />
</haskell><br />
<br />
The meaning is the following: If f computes a none empty list as result, f succeeds and this list is the result, else g is applied to the input and this yields the result. There are two other simple choice combinators usually written in infix notation, <hask> g `guards` f</hask> and <hask>f `when` g</hask>:<br />
<br />
<haskell><br />
guards :: XmlFilter -> XmlFilter -> XmlFilter<br />
guards g f t<br />
| null (g t) = []<br />
| otherwise = f t<br />
<br />
when :: XmlFilter -> XmlFilter -> XmlFilter<br />
when f g t<br />
| null (g t) = [t]<br />
| otherwise = f t<br />
</haskell><br />
<br />
These choice operators become useful when transforming and manipulation trees.<br />
<br />
=== Tree traversal filter ===<br />
<br />
A very basic operation on tree structures is the traversal of all nodes and the selection and/or transformation of nodes. Theses traversal filters serve as control structures for processing whole trees. They correspond to the map and fold combinators for lists.<br />
<br />
The simplest traversal filter does a top down search of all nodes with a special feature. This filter, called <hask>deep</hask>, is defined as follows:<br />
<br />
<haskell><br />
deep :: XmlFilter -> XmlFilter<br />
deep f = f `orElse` (getChildren >>> deep f)<br />
</haskell><br />
<br />
When a predicate filter is applied to <hask>deep</hask>, a top down search is done and all subtrees satisfying the predicate are collected. The descent into the tree stops, when a subtree is found because of the use of <hask>orElse</hask>.<br />
<br />
'''Example:''' Selecting all plain text nodes of a document can be formulated with:<br />
<br />
<haskell><br />
deep isXText<br />
</haskell><br />
<br />
'''Example:''' Selecting all "top level" tables in a HTML documents looks like<br />
this:<br />
<br />
<haskell><br />
deep (isElem >>> hasName "table")<br />
</haskell><br />
<br />
A variant of <hask>deep</hask>, called <hask>multi</hask>, performs a complete search, where the tree traversal does not stop, when a node is found.<br />
<br />
<haskell><br />
multi :: XmlFilter -> XmlFilter<br />
multi f = f <+> (getChildren >>> multi f)<br />
</haskell><br />
<br />
'''Example:''' Selecting all tables in a HTML document, even nested ones, <hask>multi</hask> has to be used instead of <hask>deep</hask>:<br />
<br />
<hask>multi (isElem >>> hasName "table")</hask><br />
<br />
=== Arrows ===<br />
<br />
We've already seen, that the filters <hask>a -> [b]</hask> are a very<br />
powerful and sometimes a more elgant way to process XML than pure<br />
function. This is the good news. The bad news is, that filter are not<br />
general enough. Of course we sometimes want to do some I/O and we want<br />
to stay in the filter level. So we need something like<br />
<br />
<haskell><br />
type XmlIOFilter = XmlTree -> IO [XmlTree]<br />
</haskell><br />
<br />
for working in the IO monad.<br />
<br />
Sometimes it's apropriate to thread some state through the computation<br />
like in state monads. This leads to a type like<br />
<br />
<haskell><br />
type XmlStateFilter state = state -> XmlTree -> (state, [XmlTree])<br />
</haskell><br />
<br />
And in real world applications we need both extensions at the same<br />
time. Of course I/O is necessary but usually there are also some<br />
global options and variables for controlling the computations. In HXT,<br />
for instance there are variables for controlling trace output, options<br />
for setting the default encoding scheme for input data and a base URI<br />
for accessing documents, which are addressed in a content or in a DTD<br />
part by relative URIs. So we need something like<br />
<br />
<haskell><br />
type XmlIOStateFilter state = state -> XmlTree -> IO (state, [XmlTree])<br />
</haskell><br />
<br />
We want to work with all four filter variants, and in the future<br />
perhaps with even more general filters, but of course not with four<br />
sets of filter names, e.g. <hask>deep, deepST, deepIO, deepIOST</hask>.<br />
<br />
This is the point where <hask>newtype</hask>s and <hask>class</hask>es<br />
come in. Classes are needed for overloading names and<br />
<hask>newtype</hask>s are needed to declare instances. Further the<br />
restriction of <hask>XmlTree</hask> as argument and result type is<br />
not neccessary and hinders reuse in many cases.<br />
<br />
A filter discussed above has all features of an arrow. Arrows are<br />
introduced for generalising the concept of functions and function<br />
combination to more general kinds of computation than pure functions.<br />
<br />
A basic set of combinators for arrows is defined in the classes in the<br />
<hask>Control.Arrow</hask> module, containing the above mentioned <hask>(>>>), (<+>), arr</hask>.<br />
<br />
In HXT the additional classes for filters working with lists as result type are<br />
defined in <hask>Control.Arrow.ArrowList</hask>. The choice operators are<br />
in <hask>Control.Arrow.ArrowIf</hask>, tree filters, like <hask>getChildren, deep, multi, ...</hask> in<br />
<hask>Control.Arrow.ArrowTree</hask> and the elementary XML specific<br />
filters in <hask>Text.XML.HXT.XmlArrow</hask>.<br />
<br />
In HXT there are four types instantiated with these classes for<br />
pure list arrows, list arrows with a state, list arrows with IO<br />
and list arrows with a state and IO.<br />
<br />
<haskell><br />
newtype LA a b = LA { runLA :: (a -> [b]) }<br />
<br />
newtype SLA s a b = SLA { runSLA :: (s -> a -> (s, [b])) }<br />
<br />
newtype IOLA a b = IOLA { runIOLA :: (a -> IO [b]) }<br />
<br />
newtype IOSLA s a b = IOSLA { runIOSLA :: (s -> a -> IO (s, [b])) }<br />
</haskell><br />
<br />
The first one and the last one are those used most frequently in the<br />
toolbox, and of course there are lifting functions for converting the<br />
special arrows into the more general ones.<br />
<br />
Don't worry about all these conceptional details. Let's have a look into some<br />
''Hello world'' examples.<br />
<br />
== Getting started: Hello world examples ==<br />
<br />
=== copyXML ===<br />
<br />
The first complete example is a program for<br />
copying an XML document<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
import System.Environment<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
[src, dst] <- getArgs<br />
runX ( readDocument [(a_validate, v_0)] src<br />
>>><br />
writeDocument [] dst<br />
)<br />
return ()<br />
</haskell><br />
<br />
The interesting part of this example is<br />
the call of <hask>runX</hask>. <hask>runX</hask> executes an<br />
arrow. This arrow is one of the more powerful list arrows with IO and<br />
a HXT system state.<br />
<br />
The arrow itself is a composition of <hask>readDocument</hask> and<br />
<hask>writeDocument</hask>.<br />
<hask>readDocument</hask> is an arrow for reading, DTD processing and<br />
validation of documents. Its behaviour can be controlled by a list of<br />
options. Here we turn off the validation step. The <hask>src</hask>, a file<br />
name or an URI is read and parsed and a document tree is built. This<br />
tree is ''piped'' into the output arrow. This one also is<br />
controlled by a set of options. Here all the defaults are used.<br />
<hask>writeDocument</hask> converts the tree into a string and writes<br />
it to the <hask>dst</hask>.<br />
<br />
We've omitted here the boring stuff of option parsing and error<br />
handling.<br />
<br />
Compilation and a test run looks like this:<br />
<br />
<pre><br />
hobel > ghc -o copyXml -package hxt CopyXML.hs<br />
hobel > cat hello.xml<br />
<hello>world</hello><br />
hobel > copyXml hello.xml -<br />
<?xml version="1.0" encoding="UTF-8"?><br />
<hello>world</hello><br />
hobel ><br />
</pre><br />
<br />
The mini XML document in file <tt>hello.xml</tt> is read and<br />
a document tree is built. Then this tree is converted into a string<br />
and written to standard output (filename: <tt>-</tt>). It is decorated<br />
with an XML declaration containing the version and the output<br />
encoding.<br />
<br />
For processing HTML documents there is a HTML parser, which tries to<br />
parse and interprete rather anything as HTML. The HTML parser can be<br />
selected by calling<br />
<br />
<hask>readDocument [(a_parse_html, v_1), ...]</hask><br />
<br />
with the apropriate option.<br />
<br />
=== Pattern for a main program ===<br />
<br />
A more realistic pattern for a simple Unix filter like program has<br />
the following structure:<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
<br />
import System.IO<br />
import System.Environment<br />
import System.Console.GetOpt<br />
import System.Exit<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
argv <- getArgs<br />
(al, src, dst) <- cmdlineOpts argv<br />
[rc] <- runX (application al src dst)<br />
if rc >= c_err<br />
then exitWith (ExitFailure (0-1))<br />
else exitWith ExitSuccess<br />
<br />
-- | the dummy for the boring stuff of option evaluation,<br />
-- usually done with 'System.Console.GetOpt'<br />
<br />
cmdlineOpts :: [String] -> IO (Attributes, String, String)<br />
cmdlineOpts argv<br />
= return ([(a_validate, v_0)], argv!!0, argv!!1)<br />
<br />
-- | the main arrow<br />
<br />
application :: Attributes -> String -> String -> IOSArrow b Int<br />
application al src dst<br />
= readDocument al src<br />
>>><br />
processChildren (processDocumentRootElement `when` isElem) -- (1)<br />
>>><br />
writeDocument al dst<br />
>>><br />
getErrStatus<br />
<br />
<br />
-- | the dummy for the real processing: the identity filter<br />
<br />
processDocumentRootElement :: IOSArrow XmlTree XmlTree<br />
processDocumentRootElement<br />
= this -- substitute this by the real application<br />
</haskell><br />
<br />
This program has the same functionality as our first example,<br />
but it separates the arrow from the boring option evaluation and<br />
return code computation.<br />
<br />
The interesing line is (1).<br />
<hask>readDocument</hask> generates a tree structure with a so called extra<br />
root node. This root node is a node above the XML document root<br />
element. The node above the XML document root element is neccessary<br />
because of possible other elements on the same tree level as the XML<br />
root, for instance comments, processing instructions or whitespace.<br />
<br />
Furthermore the artificial root node serves for storing meta<br />
information about the document in the attribute list, like the<br />
document name, the encoding scheme, the HTTP transfer headers and<br />
other information.<br />
<br />
To process the real XML root element, we have to take the children of<br />
the root node, select the XML root element and process this, but<br />
remain all other children unchanged. This is done with<br />
<hask>processChildren</hask> and the <hask>when</hask> choice<br />
operator. <hask>processChildren</hask> applies a filter elementwise to<br />
all children of a node. All results form processing the list of children from<br />
the result node.<br />
<br />
The structure of internal document tree can be made visible<br />
e.g. by adding the option pair <hask>(a_show_tree, v_1)</hask> to the<br />
<hask>writeDocument</hask> arrow. This will emit the tree in a readable<br />
text representation instead of the real document.<br />
<br />
In the next section we will give examples for the<br />
<hask>processDocumentRootElement</hask> arrow.<br />
<br />
== Selection examples ==<br />
<br />
=== Selecting text from an HTML document ===<br />
<br />
Selecting all the plain text of an XML/HTML document<br />
can be formulated with<br />
<br />
<haskell><br />
selectAllText :: ArrowXml a => a XmlTree XmlTree<br />
selectAllText<br />
= deep isXText<br />
</haskell><br />
<br />
<hask>deep</hask> traverses the whole tree, stops the traversal when<br />
a node is a text node (<hask>isXText</hask>) and returns all the text nodes.<br />
There are two other traversal operators <hask>deepest</hask> and <hask>multi</hask>,<br />
In this case, where the selected nodes are all leaves, these would give the same result.<br />
<br />
=== Selecting text and ALT attribute values ===<br />
<br />
Let's take a bit more complex task: We want to select all text, but also the values of the <tt>alt</tt> attributes<br />
of image tags.<br />
<br />
<haskell><br />
selectAllTextAndAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndAltValues<br />
= deep<br />
( isXText -- (1)<br />
<+><br />
( isElem >>> hasName "img" -- (2)<br />
>>><br />
getAttrValue "alt" -- (3)<br />
>>><br />
mkText -- (4)<br />
)<br />
)<br />
</haskell><br />
<br />
The whole tree is searched for text nodes (1) and for image elements (2), from the image elements<br />
the alt attribute values are selected as plain text (3), this text is transformed into a text node (4).<br />
<br />
=== Selecting text and ALT attributes values (2) ===<br />
<br />
Let's refine the above filter one step further. The text from the alt attributes shall be marked in the output<br />
by surrounding double square brackets. Empty alt values shall be ignored.<br />
<br />
<haskell><br />
selectAllTextAndRealAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndRealAltValues<br />
= deep<br />
( isXText<br />
<+><br />
( isElem >>> hasName "img"<br />
>>><br />
getAttrValue "alt"<br />
>>><br />
isA significant -- (1)<br />
>>><br />
arr addBrackets -- (2)<br />
>>><br />
mkText<br />
)<br />
)<br />
where<br />
significant :: String -> Bool<br />
significant = not . all (`elem` " \n\r\t")<br />
<br />
addBrackets :: String -> String<br />
addBrackets s<br />
= " [[ " ++ s ++ " ]] "<br />
</haskell><br />
<br />
This example shows two combinators for building arrows from pure functions.<br />
The first one <hask>isA</hask> removes all empty or whitespace values from alt attributes (1),<br />
the other <hask>arr</hask> lifts the editing function to the arrow level (2).<br />
<br />
== Document construction examples ==<br />
<br />
=== The ''Hello World'' document ===<br />
<br />
The first document, of course, is a ''Hello World'' document:<br />
<br />
<haskell><br />
helloWorld :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld<br />
= mkelem "html" [] -- (1)<br />
[ mkelem "head" []<br />
[ mkelem "title" []<br />
[ txt "Hello World" ] -- (2)<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ] -- (3)<br />
[ mkelem "h1" []<br />
[ txt "Hello World" ] -- (4)<br />
]<br />
]<br />
</haskell><br />
<br />
The main arrows for document construction are <hask>mkelem</hask><br />
and it's variants (<hask>selem, aelem, eelem</hask>) for element creation, <hask>attr</hask> and <hask>sattr</hask> for attributes and <hask>mktext</hask><br />
and <hask>txt</hask> for text nodes. <hask>mkelem</hask> takes three arguments, the element name (or tag name), a list of arrows for the construction of attributes, not empty in (3), and a list of arrows for the contents. Text content is generated in (2) and (4).<br />
<br />
To write this document to a file use the following arrow<br />
<br />
<haskell><br />
root [] [helloWorld] -- (1)<br />
>>><br />
writeDocument [(a_indent, v_1)] "hello.xml" -- (2)<br />
</haskell><br />
<br />
When this arrow is executed, the <hask>helloWorld</hask><br />
document is wrapped into a so called root node (1). This complete<br />
document is written to "hello.xml" (2).<br />
<hask>writeDocument</hask> and its variants always expect<br />
a whole document tree with such a root node. Before writing, the document is<br />
indented (<hask>(a_indent, v_1)</hask>)) by inserting extra whitespace<br />
text nodes, and an XML declaration with version and encoding is added. If the indent option is not given, the whole document would appears on a single line:<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8"?><br />
<html><br />
<head><br />
<title>Hello World</title><br />
</head><br />
<body class="haskell"><br />
<h1>Hello World</h1><br />
</body><br />
</html><br />
</pre><br />
<br />
The code can be shortened a bit by using some of the<br />
convenient functions:<br />
<br />
<haskell><br />
helloWorld2 :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld2<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Hello World" ]<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ]<br />
[ selem "h1"<br />
[ txt "Hello World" ]<br />
]<br />
]<br />
</haskell><br />
<br />
In the above two examples the arrow input is totally ignored, because<br />
of the use of the constant arrow <hask>txt "..."</hask>.<br />
<br />
=== A page about all images within a HTML page ===<br />
<br />
A bit more interesting task is the construction of a page<br />
containg a table of all images within a page inclusive image URLs, geometry and ALT attributes.<br />
<br />
The program for this has a frame similar to the <hask>helloWorld</hask> program,<br />
but the rows of the table must be filled in from the input document.<br />
In the first step we will generate a table with a single column containing<br />
the URL of the image.<br />
<br />
<haskell><br />
imageTable :: ArrowXml a => a XmlTree XmlTree<br />
imageTable<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Images in Page" ]<br />
]<br />
, selem "body"<br />
[ selem "h1"<br />
[ txt "Images in Page" ]<br />
, selem "table"<br />
[ collectImages -- (1)<br />
>>><br />
genTableRows -- (2)<br />
]<br />
]<br />
]<br />
where<br />
collectImages -- (1)<br />
= deep ( isElem<br />
>>><br />
hasName "img"<br />
)<br />
genTableRows -- (2)<br />
= selem "tr"<br />
[ selem "td"<br />
[ getAttrValue "src" >>> mkText ]<br />
]<br />
</haskell><br />
<br />
With (1) the image elements are collected, and with (2)<br />
the HTML code for an image element is built.<br />
<br />
Applied to <tt>http://www.haskell.org/</tt> we get the following result<br />
(at the time writing this page):<br />
<br />
<pre><br />
<html><br />
<head><br />
<title>Images in Page</title><br />
</head><br />
<body><br />
<h1>Images in Page</h1><br />
<table><br />
<tr><br />
<td>/haskellwiki_logo.png</td><br />
</tr><br />
<tr><br />
<td>/sitewiki/images/1/10/Haskelllogo-small.jpg</td><br />
</tr><br />
<tr><br />
<td>/haskellwiki_logo_small.png</td><br />
</tr><br />
</table><br />
</body><br />
</html><br />
</pre><br />
<br />
When generating HTML, often there are constant parts within the page,<br />
in the example e.g. the page header. It's possible to write these<br />
parts as a string containing plain HTML and then read this with<br />
a simple XML contents parser called <hask>xread</hask>.<br />
<br />
The example above could then be rewritten as<br />
<br />
<haskell><br />
imageTable<br />
= selem "html"<br />
[ pageHeader<br />
, ...<br />
]<br />
where<br />
pageHeader<br />
= constA "<head><title>Images in Page</title></head>"<br />
>>><br />
xread<br />
...<br />
</haskell><br />
<br />
<hask>xread</hask> is a very primitive arrow. It does not run in the<br />
IO monad, so it can be used in any context, but therefore the error handling<br />
is very limited. <hask>xread</hask> parses an XML element content.<br />
<br />
=== A page about all images within a HTML page: 1. Refinement ===<br />
<br />
The next refinement step is the extension of the table such that<br />
it contains four columns, one for the image itself, one for the URL,<br />
the geometry and the ALT text. The extended <hask>getTableRows</hask><br />
has the following form:<br />
<br />
<haskell><br />
genTableRows<br />
= selem "tr"<br />
[ selem "td" -- (1)<br />
[ this -- (1.1)<br />
]<br />
, selem "td" -- (2)<br />
[ getAttrValue "src"<br />
>>><br />
mkText<br />
>>><br />
mkelem "a" -- (2.1)<br />
[ attr "href" this ]<br />
[ this ]<br />
]<br />
, selem "td" -- (3)<br />
[ ( getAttrValue "width"<br />
&&& -- (3.1)<br />
getAttrValue "height"<br />
)<br />
>>><br />
arr2 geometry -- (3.2)<br />
>>><br />
mkText<br />
]<br />
, selem "td" -- (4)<br />
[ getAttrValue "alt"<br />
>>><br />
mkText<br />
]<br />
]<br />
where<br />
geometry :: String -> String -> String<br />
geometry "" ""<br />
= ""<br />
geometry w h<br />
= w ++ "x" ++ h<br />
</haskell><br />
<br />
In (1) the identity arrow <hask>this</hask> is used for<br />
inserting the whole image element (<hask>this</hask> value) into the first column.<br />
(2) is the column from the previous example but the URL has been made active<br />
by embedding the URL in an A-element (2.1). In (3) there are two<br />
new combinators, <hask>(&&&)</hask> (3.1) is an arrow for applying two<br />
arrows to the same input and combine the results into a pair. <hask>arr2</hask><br />
works like <hask>arr</hask> but it lifts a binary function into an arrow<br />
accepting a pair of values. <hask>arr2 f</hask> is a shortcut for<br />
<hask>arr (uncurry f)</hask>. So width and height are combined into an X11 like<br />
geometry spec. (4) adds the ALT-text.<br />
<br />
=== A page about all images within a HTML page: 2. Refinement ===<br />
<br />
The generated HTML page is not yet very useful, because it usually<br />
contains relativ HREFs to the images, so the links do not work.<br />
We have to transform the SRC attribute values into absolute URLs.<br />
This can be done with the following code:<br />
<br />
<haskell><br />
imageTable2 :: IOStateArrow s XmlTree XmlTree<br />
imageTable2<br />
= ...<br />
...<br />
, selem "table"<br />
[ collectImages<br />
>>><br />
mkAbsImageRef -- (1)<br />
>>><br />
genTableRows<br />
]<br />
...<br />
<br />
mkAbsImageRef :: IOStateArrow s XmlTree XmlTree -- (1)<br />
mkAbsImageRef<br />
= processAttrl ( mkAbsRef -- (2)<br />
`when`<br />
hasName "src" -- (3)<br />
)<br />
where<br />
mkAbsRef -- (4)<br />
= replaceChildren<br />
( xshow getChildren -- (5)<br />
>>><br />
( mkAbsURI `orElse` this ) -- (6)<br />
>>><br />
mkText -- (7)<br />
)<br />
</haskell><br />
<br />
The <hask>imageTable2</hask> is extended by an arrow <hask>mkAbsImageRef</hask><br />
(1). This arrow uses the global system state of HXT, in which the base URL<br />
of a document is stored. For editing the SRC attribute value, the attribute list<br />
of the image elements is processed with <hask>processAttrl</hask>.<br />
With the <hask>`when` hasName "src"</hask> only SRC attributes are manipulated (3). The real work is done in (4): The URL is selected with <hask>getChildren</hask>, a text node, and converted into a string (<hask>xshow</hask>), the URL is transformed into an absolute URL<br />
with <hask>mkAbsURI</hask> (6). This arrow may fail, e.g. in case of illegal<br />
URLs. In this case the URL remains unchanged (<hask>`orElse` this</hask>).<br />
The resulting String value is converted into a text node forming the new<br />
attribute value node (7).<br />
<br />
Because of the use of the use of the global HXT state in <hask>mkAbsURI</hask><br />
<hask>mkAbsRef</hask> and <hask>imageTable2</hask> need to have the more specialized signature <hask>IOStateArrow s XmlTree XmlTree</hask>.<br />
<br />
== Transformation examples ==<br />
<br />
=== Decorating external references of an HTML document ===<br />
<br />
In the following examples, we want to decorate the external references<br />
in an HTML page by a small icon, like it's done in many wikis.<br />
For this task the document tree has to be traversed, all parts<br />
except the intersting A-Elements remain unchanged. At the end of the list of children of an A-Element we add an image element.<br />
<br />
Here is the first version:<br />
<br />
<haskell><br />
addRefIcon :: ArrowXml a => a XmlTree XmlTree<br />
addRefIcon<br />
= processTopDown -- (1)<br />
( addImg -- (2)<br />
`when`<br />
isExternalRef -- (3)<br />
)<br />
where<br />
isExternalRef -- (4)<br />
= isElem<br />
>>><br />
hasName "a"<br />
>>><br />
hasAttr "href"<br />
>>><br />
getAttrValue "href"<br />
>>><br />
isA isExtRef<br />
where<br />
isExtRef -- (4.1)<br />
= isPrefixOf "http:" -- or something more precise<br />
<br />
addImg<br />
= replaceChildren -- (5)<br />
( getChildren -- (6)<br />
<+><br />
imgElement -- (7)<br />
)<br />
<br />
imgElement<br />
= mkelem "img" -- (8)<br />
[ sattr "src" "/icons/ref.png" -- (9)<br />
, sattr "alt" "external ref"<br />
] [] -- (10)<br />
</haskell><br />
<br />
The traversal is done with <hask>processTopDown</hask> (1).<br />
This arrow applies an arrow to all nodes of the whole document tree.<br />
The transformation arrow applies the <hask>addImg</hask> (2) to<br />
all A-elements (3),(4). This arrow uses a bit simplified test (4.1)<br />
for external URLs.<br />
<hask>addImg</hask> manipulates all children (5) of the A-elements by<br />
selecting the current children (6) and adding an image element (7).<br />
The image element is constructed with <hask>mkelem</hask> (8). This takes<br />
an element name, a list of arrows for computing the attributes and a<br />
list of arrows for computing the contents. The content of the image element is<br />
empty (10). The attributes are constructed with <hask>sattr</hask> (9).<br />
<hask>sattr</hask> ignores the arrow input and builds an attribute form<br />
the name value pair of arguments.<br />
<br />
=== Transform external references into absolute references ===<br />
<br />
In the following example we will develop a program for<br />
editing a HTML page such that all references to external documents<br />
(images, hypertext refs, style refs, ...) become absolute references.<br />
We will see some new, but very useful combinators in the solution.<br />
<br />
The task seems to be rather trivial. In a tree travaersal<br />
all references are edited with respect to the document base.<br />
But in HTML there is a BASE element, allowed in the content of HEAD<br />
with a HREF attribute, which defines the document base. Again this<br />
href can be a relative URL.<br />
<br />
We start the development with the editing arrow. This gets<br />
the real document base as argument.<br />
<br />
<haskell><br />
mkAbsHRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsHRefs base<br />
= processTopDown editHRef -- (1)<br />
where<br />
editHRef<br />
= processAttrl -- (3)<br />
( changeAttrValue (absHRef base) -- (5)<br />
`when`<br />
hasName "href" -- (4)<br />
)<br />
`when`<br />
( isElem >>> hasName "a" ) -- (2)<br />
where<br />
<br />
absHRef :: String -> String -> String -- (5)<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
The tree is traversed (1) and for every A element the attribute<br />
list is processed (2). All HREF attribute values (4) are manipulated<br />
by <hask>changeAttrValue</hask> called with a string function (5).<br />
<hask>expandURIString</hask> is a pure function defined in HXT for computing<br />
an absolut URI.<br />
In this first step we only edit A-HREF attribute values. We will refine this<br />
later.<br />
<br />
The second step is the complete computation of the base URL.<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( isElem >>> hasName "html" -- (0)<br />
>>><br />
getChildren -- (1)<br />
>>><br />
isElem >>> hasName "head" -- (2)<br />
>>><br />
getChildren -- (3)<br />
>>><br />
isElem >>> hasName "base" -- (4)<br />
>>><br />
getAttrValue "href" -- (5)<br />
)<br />
&&&<br />
getBaseURI -- (6)<br />
)<br />
>>> expandURI -- (7)<br />
)<br />
`orElse` getBaseURI -- (8)<br />
</haskell><br />
<br />
Input to this arrow is the HTML element, (0) to (5) is the arrow for selecting<br />
the BASE elements HREF value, parallel to this the system base URL is read<br />
with <hask>getBaseURI</hask> (6) like in examples above. The resulting <br />
pair of strings is piped into <hask>expandURI</hask> (7), the arrow version of<br />
<hask>expandURIString</hask>. This arrow ((1) to (7)) fails in the absense<br />
of a BASE element. in this case we take the plain document base (8).<br />
The selection of the BASE elements is not yet very handy. We will define<br />
a more general and elegant function later, allowing an element path as selection argument.<br />
<br />
In the third step, we will combine the to arrows. For this we will use<br />
a new combinator <hask>($<)</hask>. The need for this new combinator<br />
is the following: We need the arrow input (the document) two times,<br />
once for computing the document base, and second for editing the<br />
whole document, and we want to compute the extra string parameter<br />
for editing of course with the above defined arrow.<br />
<br />
The combined arrow, our main arrow, looks like this<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= mkAbsHRefs $< computeBaseRef -- (1)<br />
</haskell><br />
<br />
In (1) first the arrow input is piped into <hask>computeBaseRef</hask>,<br />
this result is used in <hask>mkAbsHRefs</hask> as extra string parameter<br />
when processing the document. Internally the <hask>($<)</hask> combinator<br />
is defined by the basic combinators <hask>(&&&), (>>>)</hask> and <hask>app</hask>, but in a bit more complex computations,<br />
this pattern occurs rather frequently, so ($<) becomes very useful.<br />
<br />
Programming with arrows is one style of point free programming. Point free<br />
programming often becomes unhandy when values are used more than once.<br />
One solution is the special arrow syntax supported by ghc and others, similar to the do notation for monads. But for many simple cases the <hask>($<)</hask> combinator and it's variants <hask>($<<), ($<<<), ($<<<<), ($<$)</hask><br />
is sufficient.<br />
<br />
To complete the development of the example, a last step is neccessary:<br />
The removal of the redundant BASE element.<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= ( mkAbsHRefs $< computeBaseRef )<br />
>>><br />
removeBaseElement<br />
<br />
removeBaseElement :: ArrowXml a => a XmlTree XmlTree<br />
removeBaseElement<br />
= processChildren<br />
( processChildren<br />
( none -- (1)<br />
`when`<br />
( isElem >>> hasName "base" )<br />
)<br />
`when`<br />
( isElem >>> hasName "head" )<br />
)<br />
</haskell><br />
<br />
In this function the children of the HEAD element are searched for<br />
a BASE element. This is removed by aplying the null arrow <hask>none</hask><br />
to the input, returning always the empty list.<br />
<hask>none `when` ...</hask> is the pattern for deleting nodes from a tree.<br />
<br />
The <hask>computeBaseRef</hask> function defined above contains an arrow pattern<br />
for selecting the right subtree that is rather common in HXT applications<br />
<br />
<haskell><br />
isElem >>> hasName n1<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName n2<br />
...<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName nm<br />
</haskell><br />
<br />
For this pattern we will define a convenient function creating the<br />
arrow for selection<br />
<br />
<haskell><br />
getDescendents :: ArrowXml a => [String] -> a XmlTree XmlTree<br />
getDescendents<br />
= foldl1 (\ x y -> x >>> getChildren >>> y) -- (1)<br />
.<br />
map (\ n -> isElem >>> hasName n) -- (2)<br />
</haskell><br />
<br />
The name list is mapped to the element checking arrow (2),<br />
the resulting list of arrows is folded with <hask>getChildren</hask><br />
into a single arrow. <hask>computeBaseRef</hask> can then be simplified<br />
and becomes more readable:<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( getDescendents ["html","head","base"] -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
...<br />
</haskell><br />
<br />
An even more general and flexible technic are the XPath expressions<br />
available for selection of document parts defined in the module<br />
<hask>Text.XML.HXT.Arrow.XmlNodeSet</hask>.<br />
<br />
With XPath <hask>computeBaseRef</hask> can be simplified to<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( ( getXPathTrees "/html/head/base" -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
</haskell><br />
<br />
Even the attribute selection can be expressed by XPath,<br />
so (1) and (2) can be combined into<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( xshow (getXPathTrees "/html/head/base@href")<br />
...<br />
</haskell><br />
<br />
The extra <hask>xshow</hask> is here required to convert the<br />
XPath result, an XmlTree, into a string.<br />
<br />
XPath defines a<br />
full language for selecting parts of an XML document.<br />
Sometimes it's rather comfortable to make selections of this<br />
type, but the XPath evaluation in general is more expensive<br />
in time and space than a simple combination of arrows, like we've<br />
seen it in <hask>getDescendends</hask>.<br />
<br />
=== Transform external references into absolute references: Refinement ===<br />
<br />
In the above example only A-HREF URLs are edited. Now we extend this<br />
to other element-attribute combinations.<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown ( editRef "a" "href" -- (2)<br />
>>><br />
editRef "img" "src" -- (3)<br />
>>><br />
editRef "link" "href" -- (4)<br />
>>><br />
editRef "script" "src" -- (5)<br />
)<br />
where<br />
editRef en an -- (1)<br />
= processAttrl ( changeAttrValue (absHRef base)<br />
`when`<br />
hasName an<br />
)<br />
`when`<br />
( isElem >>> hasName en )<br />
where<br />
absHRef :: String -> String -> String<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
<hask>editRef</hask> is parameterized by the element and attribute names.<br />
The arrow applied to every element is extended to a sequence of<br />
<hask>editRef</hask>'s ((2)-(5)). Notice that the document is still traversed only once.<br />
To process all possible HTML elements,<br />
this sequence should be extended by further element-attribute pairs.<br />
<br />
This can further be simplified into<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= foldl (>>>) this<br />
.<br />
map (\ (en, an) -> editRef en an)<br />
$<br />
[ ("a", "href")<br />
, ("img", "src")<br />
, ("link", "href")<br />
, ("script", "src") -- and more<br />
]<br />
editRef<br />
= ...<br />
</haskell><br />
<br />
The <hask>foldl (>>>) this</hask> is defined in HXT as <hask>seqA</hask>,<br />
so the above code can be simplified to<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= seqA . map (uncurry editRef)<br />
$<br />
...<br />
</haskell><br />
<br />
== More complex examples ==<br />
<br />
''' to be done '''<br />
<br />
=== Automatic read/writing between xml and Haskell data types ===<br />
<br />
'''Question''': is there any way to write/read Haskell types to/from XML in HXT? HaXml has readXml and showXml, but I can't find any similar mechanism in HXT. Help! -- AlsonKemp<br />
<br />
==== Serializing to Xml ====<br />
<br />
We can create an HXT tree from a single-layer data class as follows:<br />
<br />
<haskell><br />
import IO<br />
import Char<br />
import Text.XML.HXT.Arrow<br />
import Data.Generics<br />
<br />
-- our data class we'll convert into xml<br />
data Config = <br />
Config { username :: String,<br />
logNumDays :: Int,<br />
oleDbString :: String }<br />
deriving (Show, Typeable,Data)<br />
<br />
-- helper function adapted from http://www.defmacro.org/ramblings/haskell-web.html<br />
-- (gshow replaced by gshow')<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- function to create HXT tree arrow from single-layer Haskell data type:<br />
createHxtArrow object = runLA( constA ( xmlSerialize object ) >>> xread)<br />
<br />
-- create a config object to serialize:<br />
<br />
createConfig = Config { username = "test", logNumDays = 3, oleDbString = "qsdf" }<br />
<br />
-- test function, using our Config data type<br />
testConversion = createHxtArrow( createConfig ) ()<br />
</haskell><br />
<br />
-- hughperkins<br />
<br />
==== Deserializing from Xml ====<br />
<br />
Here's a solution to deserialize a simple haskell data type containing Strings and Ints.<br />
<br />
It's not really pretty, but it works.<br />
<br />
Basically, we just convert the incoming xml into gread-compatible format, then use gread :-D<br />
<br />
Currently it works for a simple single-layer Haskell data type containing Ints and Strings. You can add new child data types by adding to the case statement in xmlToGShowFormat.<br />
<br />
If someone has a more elegant solution, please let me know ( hughperkins@gmail.com )<br />
<br />
<haskell><br />
module ParseXml<br />
where<br />
<br />
import IO<br />
import Char<br />
import List<br />
import Maybe<br />
import Data.Generics hiding (Unit)<br />
import Text.XML.HXT.Arrow hiding (when)<br />
<br />
data Config = Config{ name :: String, age :: Int } <br />
--data Config = Config{ age :: Int } <br />
deriving( Data, Show, Typeable, Ord, Eq, Read )<br />
<br />
createConfig = Config "qsdfqsdf" 3<br />
--createConfig = Config 3<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- helper function from http://www.defmacro.org/ramblings/haskell-web.html<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- parse xml to HXT tree, and obtain the value of node "fieldname"<br />
-- returns a string<br />
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)<br />
| otherwise = Nothing<br />
where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName fieldname ) >>> getChildren >>> getText ))[]<br />
<br />
-- parse templateobject to get list of field names<br />
-- apply these to xml to get list of values<br />
-- return (fieldnames list, value list)<br />
xmlToGShowFormat :: Data a => String -> a -> String<br />
xmlToGShowFormat xml templateobject = <br />
go<br />
where mainconstructorname = (showConstr $ toConstr templateobject)<br />
fields = constrFields $ toConstr templateobject<br />
values = map ( \fieldname -> getValue xml fieldname ) fields<br />
datatypes = gmapQ (dataTypeOf) templateobject<br />
constrs = gmapQ (toConstr) templateobject<br />
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject<br />
fieldtogshowformat (value,datatyperep) = case datatyperep of<br />
IntRep -> "(" ++ fromJust value ++ ")"<br />
_ -> show(fromJust value)<br />
formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps)<br />
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")"<br />
<br />
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject)<br />
<br />
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config<br />
dotest' = xmlDeserialize ("<Config><age>12</age><name>test name!</name></Config>") createConfig :: Config<br />
</haskell><br />
<br />
-- hughperkins</div>Tanimotohttps://wiki.haskell.org/HXTHXT2007-11-12T00:27:23Z<p>Tanimoto: Fixing typos.</p>
<hr />
<div>[[Category:Tools]] [[Category:Tutorials]]<br />
<br />
== A gentle introduction to the Haskell XML Toolbox ==<br />
<br />
The [http://www.fh-wedel.de/~si/HXmlToolbox/index.html Haskell XML Toolbox (HXT)] is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language, consisting of a set of combinators, for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace aware XML-Parser that supports almost fully the XML 1.0 Standard. Extensions are a validator for RelaxNG and an XPath evaluator.<br />
<br />
__TOC__<br />
<br />
== Background ==<br />
<br />
The Haskell XML Toolbox bases on the ideas of [http://www.cs.york.ac.uk/fp/HaXml/ HaXml] and [http://www.flightlab.com/~joe/hxml/ HXML] but introduces a more general approach for processing XML with Haskell. HXT uses a generic data model for representing XML documents, including the DTD subset, entity references, CData parts and processing instructions. This data model makes it possible to use tree transformation functions as a uniform design of XML processing steps from parsing, DTD processing, entity processing, validation, namespace propagation, content processing and output.<br />
<br />
== Resources ==<br />
<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/index.html HXT Home] :<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/HXT-7.0.tar.gz HXT-7.0.tar.gz] : lastest release<br />
; [http://darcs.fh-wedel.de/hxt/ darcs.fh-wedel.de/hxt] : darcs repository with head revision of HXT<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc_arrow/ Arrow API] : Haddock documentation of head revision with links to source files<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc/ Complete API] : Haddock documentation with arrows and old API based on filters<br />
<br />
== The basic concepts ==<br />
<br />
=== The basic data structures ===<br />
<br />
Processing of XML is a task of processing tree structures. This is can be done in Haskell in a very elegant way by defining an appropriate tree data type, a Haskell DOM (document object model) structure. The tree structure in HXT is a rose tree with a special XNode data type for storing the XML node information.<br />
<br />
The generally useful tree structure (NTree) is separated from the node type (XNode). This allows for reusing the tree structure and the tree traversal and manipulation functions in other applications.<br />
<br />
<haskell><br />
type NTree a = NTree a [NTree a] -- rose tree<br />
<br />
data XNode = XText String -- plain text node<br />
| ...<br />
| XTag QName XmlTrees -- element name and list of attributes<br />
| XAttr QName -- attribute name<br />
| ...<br />
<br />
type QName = ... -- qualified name<br />
<br />
type XmlTree = NTree XNode<br />
<br />
type XmlTrees = [XmlTree]<br />
</haskell><br />
<br />
=== The concept of filters ===<br />
<br />
Selecting, transforming and generating trees often requires routines, which compute not only a single result tree, but a (possibly empty) list of (sub-)trees. This leads to the idea of XML filters like in HaXml. Filters are functions, which take an XML tree as input and compute a list of result trees.<br />
<br />
<haskell><br />
type XmlFilter = XmlTree -> [XmlTree]<br />
</haskell><br />
<br />
More generally we can define a filter as<br />
<br />
<haskell><br />
type Filter a b = a -> [b]<br />
</haskell><br />
<br />
We will do this abstraction later, when introducing arrows. Many of the functions in the following motivating examples can be generalised this way. But for getting the idea, the <hask>XmlFilter</hask> is sufficient.<br />
<br />
The filter functions are used so frequently, that the idea of defining a domain specific language with filters as the basic processing units comes up. In such a DSL the basic filters are predicates, selectors, constructors and transformers, all working on the HXT DOM tree structure. For a DSL it becomes necessary to define an appropriate set of combinators for building more complex functions from simpler ones. Of course filter composition, like (.) becomes one of the most frequently used combinators. there are more complex filters for traversal of a whole tree and selection or transformation of several nodes. We will see a few first examples in the following part.<br />
<br />
The first task is to build filters from pure functions, to define a lift operator. Pure functions are lifted to filters in the following way:<br />
<br />
Predicates are lifted by mapping False to the empty list and True to the single element list, containing the input tree.<br />
<br />
<haskell><br />
p :: XmlTree -> Bool -- pure function<br />
p t = ...<br />
<br />
pf :: XmlTree -> [XmlTree] -- or XmlFilter<br />
pf t<br />
| p t = [t]<br />
| otherwise = []<br />
</haskell><br />
<br />
The combinator for this type of lifting is called <hask>isA</hask>, it works on any type and is defined as<br />
<br />
<haskell><br />
isA :: (a -> Bool) -> (a -> [a])<br />
isA p x<br />
| p x = [x]<br />
| otherwise = []<br />
</haskell><br />
<br />
A predicate for filtering text nodes looks like this<br />
<br />
<haskell><br />
isXText :: XmlFilter -- XmlTree -> [XmlTrees]<br />
isXText t@(NTree (XText _) _) = [t]<br />
isXText _ = []<br />
</haskell><br />
<br />
Transformers, function that map a tree into another tree, are lifted in a trivial way:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t = exp(t)<br />
<br />
ff :: XmlTree -> [XmlTree]<br />
ff t = [exp(t)]<br />
</haskell><br />
<br />
This basic function is called <hask>arr</hask>, it comes from the Control.Arrow module of the basic library package of ghc.<br />
<br />
Partial functions, functions that can't always compute a result, are usually lifted to totally defined filters:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t<br />
| p t = expr(t)<br />
| otherwise = error "f not defined"<br />
<br />
ff :: XmlFilter<br />
ff t<br />
| p t = [expr(t)]<br />
| otherwise = []<br />
</haskell><br />
<br />
This is a rather comfortable situation, with these filters we don't have to deal with illegal argument errors. Illegal arguments are just mapped to the empty list.<br />
<br />
When processing trees, there's often the case, that no, exactly one, or more than one result is possible. These functions, returning a set of results are often a bit imprecisely called ''nondeterministic'' functions. These functions, e.g. selecting all children of a node or all grandchildren, are exactly our filters. In this context lists instead of sets of values are the appropriate result type, because the ordering in XML is important and duplicates are possible.<br />
<br />
Working with filters is rather similar to working with binary relations, and working with relations is rather natural and comfortable, database people do know this very well.<br />
<br />
Two first examples for working with ''nondeterministic'' functions are selecting the children and the grandchildren of an XmlTree which can be implemented by<br />
<br />
<haskell><br />
getChildren :: XmlFilter<br />
getChildren (NTree n cs)<br />
= cs<br />
<br />
getGrandChildren :: XmlFilter<br />
getGrandChildren (NTree n cs)<br />
= concat [ getChildren c | c <- cs ]<br />
</haskell><br />
<br />
=== Filter combinators ===<br />
<br />
Composition of filters (like function composition) is the most important combinator. We will use the infix operator <hask>(>>>)</hask> for filter composition and reverse the arguments, so we can read composition sequences from left to right, like with pipes in Unix. Composition is defined as follows:<br />
<br />
<haskell><br />
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f >>> g) t = concat [g t' | t' <- f t]<br />
</haskell><br />
<br />
This definition corresponds 1-1 to the composition of binary relations. With help of the <hask>(>>>)</hask> operator the definition of <hask>getGrandChildren</hask> becomes rather simple:<br />
<br />
<haskell><br />
getGrandChildren :: XmlFilter<br />
getGrandChildren = getChildren >>> getChildren<br />
</haskell><br />
<br />
Selecting all text nodes of the children of an element can also be formulated very easily with the help of <hask>(>>>)</hask><br />
<br />
<haskell><br />
getTextChildren :: XmlFilter<br />
getTextChildren = getChildren >>> isXText<br />
</haskell><br />
<br />
In case of predicate filter the <hask>(>>>)</hask> serves as a logical and operator, or from the relational view as an intersection operator: <hask>isA p1 >>> isA p2</hask> selects all values for which p1 and p2 both hold.<br />
<br />
The dual operator to <hask>(>>>)</hask> is the locical or, (thinking in sets: The union operator). For this we define a sum operator <hask>(<+>)</hask>. The sum of two filters is defined as follows:<br />
<br />
<haskell><br />
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f <+> g) t = f t ++ g t<br />
</haskell><br />
<br />
Example: <hask>isA p1 <+> isA p2</hask> is the locical or for filter.<br />
<br />
Combining elementary filters with (>>>) and (<+>) leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulated with:<br />
<br />
<haskell><br />
getTextChildren2 :: XmlFilter<br />
getTextChildren2 = getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
</haskell><br />
<br />
'''Exercise:''' Are these filters equivalent or what's the difference between the two filters?<br />
<br />
<haskell><br />
getChildren >>> ( isXText <+> ( getChildren >>> isXText ) )<br />
<br />
( getChildren >>> isXText ) <+> ( getChildren >>> getChildren >>> isXText )<br />
</haskell><br />
<br />
Of course we need choice combinators. The first idea is an if-then-else filter, <br />
built up from three simpler filters. But often it's easier and more elegant to work with simpler binary combinators for choice. So we will introduce the simpler ones first.<br />
<br />
One of these choice combinators is called <hask>orElse</hask> and is defined as<br />
follows:<br />
<br />
<haskell><br />
orElse :: XmlFilter -> XmlFilter -> XmlFilter<br />
orElse f g t<br />
| null res1 = g t<br />
| otherwise = res1<br />
where<br />
res1 = f t<br />
</haskell><br />
<br />
The meaning is the following: If f computes a none empty list as result, f succeeds and this list is the result, else g is applied to the input and this yields the result. There are two other simple choice combinators usually written in infix notation, <hask> g `guards` f</hask> and <hask>f `when` g</hask>:<br />
<br />
<haskell><br />
guards :: XmlFilter -> XmlFilter -> XmlFilter<br />
guards g f t<br />
| null (g t) = []<br />
| otherwise = f t<br />
<br />
when :: XmlFilter -> XmlFilter -> XmlFilter<br />
when f g t<br />
| null (g t) = [t]<br />
| otherwise = f t<br />
</haskell><br />
<br />
These choice operators become useful when transforming and manipulation trees.<br />
<br />
=== Tree traversal filter ===<br />
<br />
A very basic operation on tree structures is the traversal of all nodes and the selection and/or transformation of nodes. Theses traversal filters serve as control structures for processing whole trees. They correspond to the map and fold combinators for lists.<br />
<br />
The simplest traversal filter does a top down search of all nodes with a special feature. This filter, called <hask>deep</hask>, is defined as follows:<br />
<br />
<haskell><br />
deep :: XmlFilter -> XmlFilter<br />
deep f = f `orElse` (getChildren >>> deep f)<br />
</haskell><br />
<br />
When a predicate filter is applied to <hask>deep</hask>, a top down search is done and all subtrees satisfying the predicate are collected. The descent into the tree stops, when a subtree is found because of the use of <hask>orElse</hask>.<br />
<br />
'''Example:''' Selecting all plain text nodes of a document can be formulated with:<br />
<br />
<haskell><br />
deep isXText<br />
</haskell><br />
<br />
'''Example:''' Selecting all "top level" tables in a HTML documents looks like<br />
this:<br />
<br />
<haskell><br />
deep (isElem >>> hasName "table")<br />
</haskell><br />
<br />
A variant of <hask>deep</hask>, called <hask>multi</hask>, performs a complete search, where the tree traversal does not stop, when a node is found.<br />
<br />
<haskell><br />
multi :: XmlFilter -> XmlFilter<br />
multi f = f <+> (getChildren >>> multi f)<br />
</haskell><br />
<br />
'''Example:''' Selecting all tables in a HTML document, even nested ones, <hask>multi</hask> has to be used instead of <hask>deep</hask>:<br />
<br />
<hask>multi (isElem >>> hasName "table")</hask><br />
<br />
=== Arrows ===<br />
<br />
We've already seen, that the filters <hask>a -> [b]</hask> are a very<br />
powerful and sometimes a more elgant way to process XML than pure<br />
function. This is the good news. The bad news is, that filter are not<br />
general enough. Of course we sometimes want to do some I/O and we want<br />
to stay in the filter level. So we need something like<br />
<br />
<haskell><br />
type XmlIOFilter = XmlTree -> IO [XmlTree]<br />
</haskell><br />
<br />
for working in the IO monad.<br />
<br />
Sometimes it's apropriate to thread some state through the computation<br />
like in state monads. This leads to a type like<br />
<br />
<haskell><br />
type XmlStateFilter state = state -> XmlTree -> (state, [XmlTree])<br />
</haskell><br />
<br />
And in real world applications we need both extensions at the same<br />
time. Of course I/O is necessary but usually there are also some<br />
global options and variables for controlling the computations. In HXT,<br />
for instance there are variables for controlling trace output, options<br />
for setting the default encoding scheme for input data and a base URI<br />
for accessing documents, which are addressed in a content or in a DTD<br />
part by relative URIs. So we need something like<br />
<br />
<haskell><br />
type XmlIOStateFilter state = state -> XmlTree -> IO (state, [XmlTree])<br />
</haskell><br />
<br />
We want to work with all four filter variants, and in the future<br />
perhaps with even more general filters, but of course not with four<br />
sets of filter names, e.g. <hask>deep, deepST, deepIO, deepIOST</hask>.<br />
<br />
This is the point where <hask>newtype</hask>s and <hask>class</hask>es<br />
come in. Classes are needed for overloading names and<br />
<hask>newtype</hask>s are needed to declare instances. Further the<br />
restriction of <hask>XmlTree</hask> as argument and result type is<br />
not neccessary and hinders reuse in many cases.<br />
<br />
A filter discussed above has all features of an arrow. Arrows are<br />
introduced for generalising the concept of functions and function<br />
combination to more general kinds of computation than pure functions.<br />
<br />
A basic set of combinators for arrows is defined in the classes in the<br />
<hask>Control.Arrow</hask> module, containing the above mentioned <hask>(>>>), (<+>), arr</hask>.<br />
<br />
In HXT the additional classes for filters working with lists as result type are<br />
defined in <hask>Control.Arrow.ArrowList</hask>. The choice operators are<br />
in <hask>Control.Arrow.ArrowIf</hask>, tree filters, like <hask>getChildren, deep, multi, ...</hask> in<br />
<hask>Control.Arrow.ArrowTree</hask> and the elementary XML specific<br />
filters in <hask>Text.XML.HXT.XmlArrow</hask>.<br />
<br />
In HXT there are four types instantiated with these classes for<br />
pure list arrows, list arrows with a state, list arrows with IO<br />
and list arrows with a state and IO.<br />
<br />
<haskell><br />
newtype LA a b = LA { runLA :: (a -> [b]) }<br />
<br />
newtype SLA s a b = SLA { runSLA :: (s -> a -> (s, [b])) }<br />
<br />
newtype IOLA a b = IOLA { runIOLA :: (a -> IO [b]) }<br />
<br />
newtype IOSLA s a b = IOSLA { runIOSLA :: (s -> a -> IO (s, [b])) }<br />
</haskell><br />
<br />
The first one and the last one are those used most frequently in the<br />
toolbox, and of course there are lifting functions for converting the<br />
special arrows into the more general ones.<br />
<br />
Don't worry about all these conceptional details. Let's have a look into some<br />
''Hello world'' examples.<br />
<br />
== Getting started: Hello world examples ==<br />
<br />
=== copyXML ===<br />
<br />
The first complete example is a program for<br />
copying an XML document<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
import System.Environment<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
[src, dst] <- getArgs<br />
runX ( readDocument [(a_validate, v_0)] src<br />
>>><br />
writeDocument [] dst<br />
)<br />
return ()<br />
</haskell><br />
<br />
The interesting part of this example is<br />
the call of <hask>runX</hask>. <hask>runX</hask> executes an<br />
arrow. This arrow is one of the more powerful list arrows with IO and<br />
a HXT system state.<br />
<br />
The arrow itself is a composition of <hask>readDocument</hask> and<br />
<hask>writeDocument</hask>.<br />
<hask>readDocument</hask> is an arrow for reading, DTD processing and<br />
validation of documents. Its behaviour can be controlled by a list of<br />
options. Here we turn off the validation step. The <hask>src</hask>, a file<br />
name or an URI is read and parsed and a document tree is built. This<br />
tree is ''piped'' into the output arrow. This one also is<br />
controlled by a set of options. Here all the defaults are used.<br />
<hask>writeDocument</hask> converts the tree into a string and writes<br />
it to the <hask>dst</hask>.<br />
<br />
We've omitted here the boring stuff of option parsing and error<br />
handling.<br />
<br />
Compilation and a test run looks like this:<br />
<br />
<pre><br />
hobel > ghc -o copyXml -package hxt CopyXML.hs<br />
hobel > cat hello.xml<br />
<hello>world</hello><br />
hobel > copyXml hello.xml -<br />
<?xml version="1.0" encoding="UTF-8"?><br />
<hello>world</hello><br />
hobel ><br />
</pre><br />
<br />
The mini XML document in file <tt>hello.xml</tt> is read and<br />
a document tree is built. Then this tree is converted into a string<br />
and written to standard output (filename: <tt>-</tt>). It is decorated<br />
with an XML declaration containing the version and the output<br />
encoding.<br />
<br />
For processing HTML documents there is a HTML parser, which tries to<br />
parse and interprete rather anything as HTML. The HTML parser can be<br />
selected by calling<br />
<br />
<hask>readDocument [(a_parse_html, v_1), ...]</hask><br />
<br />
with the apropriate option.<br />
<br />
=== Pattern for a main program ===<br />
<br />
A more realistic pattern for a simple Unix filter like program has<br />
the following structure:<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
<br />
import System.IO<br />
import System.Environment<br />
import System.Console.GetOpt<br />
import System.Exit<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
argv <- getArgs<br />
(al, src, dst) <- cmdlineOpts argv<br />
[rc] <- runX (application al src dst)<br />
if rc >= c_err<br />
then exitWith (ExitFailure (0-1))<br />
else exitWith ExitSuccess<br />
<br />
-- | the dummy for the boring stuff of option evaluation,<br />
-- usually done with 'System.Console.GetOpt'<br />
<br />
cmdlineOpts :: [String] -> IO (Attributes, String, String)<br />
cmdlineOpts argv<br />
= return ([(a_validate, v_0)], argv!!0, argv!!1)<br />
<br />
-- | the main arrow<br />
<br />
application :: Attributes -> String -> String -> IOSArrow b Int<br />
application al src dst<br />
= readDocument al src<br />
>>><br />
processChildren (processDocumentRootElement `when` isElem) -- (1)<br />
>>><br />
writeDocument al dst<br />
>>><br />
getErrStatus<br />
<br />
<br />
-- | the dummy for the real processing: the identity filter<br />
<br />
processDocumentRootElement :: IOSArrow XmlTree XmlTree<br />
processDocumentRootElement<br />
= this -- substitute this by the real application<br />
</haskell><br />
<br />
This program has the same functionality as our first example,<br />
but it separates the arrow from the boring option evaluation and<br />
return code computation.<br />
<br />
The interesing line is (1).<br />
<hask>readDocument</hask> generates a tree structure with a so called extra<br />
root node. This root node is a node above the XML document root<br />
element. The node above the XML document root element is neccessary<br />
because of possible other elements on the same tree level as the XML<br />
root, for instance comments, processing instructions or whitespace.<br />
<br />
Furthermore the artificial root node serves for storing meta<br />
information about the document in the attribute list, like the<br />
document name, the encoding scheme, the HTTP transfer headers and<br />
other information.<br />
<br />
To process the real XML root element, we have to take the children of<br />
the root node, select the XML root element and process this, but<br />
remain all other children unchanged. This is done with<br />
<hask>processChildren</hask> and the <hask>when</hask> choice<br />
operator. <hask>processChildren</hask> applies a filter elementwise to<br />
all children of a node. All results form processing the list of children from<br />
the result node.<br />
<br />
The structure of internal document tree can be made visible<br />
e.g. by adding the option pair <hask>(a_show_tree, v_1)</hask> to the<br />
<hask>writeDocument</hask> arrow. This will emit the tree in a readable<br />
text representation instead of the real document.<br />
<br />
In the next section we will give examples for the<br />
<hask>processDocumentRootElement</hask> arrow.<br />
<br />
== Selection examples ==<br />
<br />
=== Selecting text from an HTML document ===<br />
<br />
Selecting all the plain text of an XML/HTML document<br />
can be formulated with<br />
<br />
<haskell><br />
selectAllText :: ArrowXml a => a XmlTree XmlTree<br />
selectAllText<br />
= deep isXText<br />
</haskell><br />
<br />
<hask>deep</hask> traverses the whole tree, stops the traversal when<br />
a node is a text node (<hask>isXText</hask>) and returns all the text nodes.<br />
There are two other traversal operators <hask>deepest</hask> and <hask>multi</hask>,<br />
In this case, where the selected nodes are all leave, these would give the same result.<br />
<br />
=== Selecting text and ALT attribute values ===<br />
<br />
Let's take a bit more complex task: We want to select all text, but also the values of the <tt>alt</tt> attributes<br />
of image tags.<br />
<br />
<haskell><br />
selectAllTextAndAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndAltValues<br />
= deep<br />
( isXText -- (1)<br />
<+><br />
( isElem >>> hasName "img" -- (2)<br />
>>><br />
getAttrValue "alt" -- (3)<br />
>>><br />
mkText -- (4)<br />
)<br />
)<br />
</haskell><br />
<br />
The whole tree is searched for text nodes (1) and for image elements (2), from the image elements<br />
the alt attribute values are selected as plain text (3), this text is transformed into a text node (4).<br />
<br />
=== Selecting text and ALT attributes values (2) ===<br />
<br />
Let's refine the above filter one step further. The text from the alt attributes shall be marked in the output<br />
by surrounding double square brackets. Empty alt values shall be ignored.<br />
<br />
<haskell><br />
selectAllTextAndRealAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndRealAltValues<br />
= deep<br />
( isXText<br />
<+><br />
( isElem >>> hasName "img"<br />
>>><br />
getAttrValue "alt"<br />
>>><br />
isA significant -- (1)<br />
>>><br />
arr addBrackets -- (2)<br />
>>><br />
mkText<br />
)<br />
)<br />
where<br />
significant :: String -> Bool<br />
significant = not . all (`elem` " \n\r\t")<br />
<br />
addBrackets :: String -> String<br />
addBrackets s<br />
= " [[ " ++ s ++ " ]] "<br />
</haskell><br />
<br />
This example shows two combinators for building arrows from pure functions.<br />
The first one <hask>isA</hask> removes all empty or whitespace values from alt attributes (1),<br />
the other <hask>arr</hask> lifts the editing function to the arrow level (2).<br />
<br />
== Document construction examples ==<br />
<br />
=== The ''Hello World'' document ===<br />
<br />
The first document, of course, is a ''Hello World'' document:<br />
<br />
<haskell><br />
helloWorld :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld<br />
= mkelem "html" [] -- (1)<br />
[ mkelem "head" []<br />
[ mkelem "title" []<br />
[ txt "Hello World" ] -- (2)<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ] -- (3)<br />
[ mkelem "h1" []<br />
[ txt "Hello World" ] -- (4)<br />
]<br />
]<br />
</haskell><br />
<br />
The main arrows for document construction are <hask>mkelem</hask><br />
and it's variants (<hask>selem, aelem, eelem</hask>) for element creation, <hask>attr</hask> and <hask>sattr</hask> for attributes and <hask>mktext</hask><br />
and <hask>txt</hask> for text nodes. <hask>mkelem</hask> takes three arguments, the element name (or tag name), a list of arrows for the construction of attributes, not empty in (3), and a list of arrows for the contents. Text content is generated in (2) and (4).<br />
<br />
To write this document to a file use the following arrow<br />
<br />
<haskell><br />
root [] [helloWorld] -- (1)<br />
>>><br />
writeDocument [(a_indent, v_1)] "hello.xml" -- (2)<br />
</haskell><br />
<br />
When this arrow is executed, the <hask>helloWorld</hask><br />
document is wrapped into a so called root node (1). This complete<br />
document is written to "hello.xml" (2).<br />
<hask>writeDocument</hask> and its variants always expect<br />
a whole document tree with such a root node. Before writing, the document is<br />
indented (<hask>(a_indent, v_1)</hask>)) by inserting extra whitespace<br />
text nodes, and an XML declaration with version and encoding is added. If the indent option is not given, the whole document would appears on a single line:<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8"?><br />
<html><br />
<head><br />
<title>Hello World</title><br />
</head><br />
<body class="haskell"><br />
<h1>Hello World</h1><br />
</body><br />
</html><br />
</pre><br />
<br />
The code can be shortened a bit by using some of the<br />
convenient functions:<br />
<br />
<haskell><br />
helloWorld2 :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld2<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Hello World" ]<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ]<br />
[ selem "h1"<br />
[ txt "Hello World" ]<br />
]<br />
]<br />
</haskell><br />
<br />
In the above two examples the arrow input is totally ignored, because<br />
of the use of the constant arrow <hask>txt "..."</hask>.<br />
<br />
=== A page about all images within a HTML page ===<br />
<br />
A bit more interesting task is the construction of a page<br />
containg a table of all images within a page inclusive image URLs, geometry and ALT attributes.<br />
<br />
The program for this has a frame similar to the <hask>helloWorld</hask> program,<br />
but the rows of the table must be filled in from the input document.<br />
In the first step we will generate a table with a single column containing<br />
the URL of the image.<br />
<br />
<haskell><br />
imageTable :: ArrowXml a => a XmlTree XmlTree<br />
imageTable<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Images in Page" ]<br />
]<br />
, selem "body"<br />
[ selem "h1"<br />
[ txt "Images in Page" ]<br />
, selem "table"<br />
[ collectImages -- (1)<br />
>>><br />
genTableRows -- (2)<br />
]<br />
]<br />
]<br />
where<br />
collectImages -- (1)<br />
= deep ( isElem<br />
>>><br />
hasName "img"<br />
)<br />
genTableRows -- (2)<br />
= selem "tr"<br />
[ selem "td"<br />
[ getAttrValue "src" >>> mkText ]<br />
]<br />
</haskell><br />
<br />
With (1) the image elements are collected, and with (2)<br />
the HTML code for an image element is built.<br />
<br />
Applied to <tt>http://www.haskell.org/</tt> we get the following result<br />
(at the time writing this page):<br />
<br />
<pre><br />
<html><br />
<head><br />
<title>Images in Page</title><br />
</head><br />
<body><br />
<h1>Images in Page</h1><br />
<table><br />
<tr><br />
<td>/haskellwiki_logo.png</td><br />
</tr><br />
<tr><br />
<td>/sitewiki/images/1/10/Haskelllogo-small.jpg</td><br />
</tr><br />
<tr><br />
<td>/haskellwiki_logo_small.png</td><br />
</tr><br />
</table><br />
</body><br />
</html><br />
</pre><br />
<br />
When generating HTML, often there are constant parts within the page,<br />
in the example e.g. the page header. It's possible to write these<br />
parts as a string containing plain HTML and then read this with<br />
a simple XML contents parser called <hask>xread</hask>.<br />
<br />
The example above could then be rewritten as<br />
<br />
<haskell><br />
imageTable<br />
= selem "html"<br />
[ pageHeader<br />
, ...<br />
]<br />
where<br />
pageHeader<br />
= constA "<head><title>Images in Page</title></head>"<br />
>>><br />
xread<br />
...<br />
</haskell><br />
<br />
<hask>xread</hask> is a very primitive arrow. It does not run in the<br />
IO monad, so it can be used in any context, but therefore the error handling<br />
is very limited. <hask>xread</hask> parses an XML element content.<br />
<br />
=== A page about all images within a HTML page: 1. Refinement ===<br />
<br />
The next refinement step is the extension of the table such that<br />
it contains four columns, one for the image itself, one for the URL,<br />
the geometry and the ALT text. The extended <hask>getTableRows</hask><br />
has the following form:<br />
<br />
<haskell><br />
genTableRows<br />
= selem "tr"<br />
[ selem "td" -- (1)<br />
[ this -- (1.1)<br />
]<br />
, selem "td" -- (2)<br />
[ getAttrValue "src"<br />
>>><br />
mkText<br />
>>><br />
mkelem "a" -- (2.1)<br />
[ attr "href" this ]<br />
[ this ]<br />
]<br />
, selem "td" -- (3)<br />
[ ( getAttrValue "width"<br />
&&& -- (3.1)<br />
getAttrValue "height"<br />
)<br />
>>><br />
arr2 geometry -- (3.2)<br />
>>><br />
mkText<br />
]<br />
, selem "td" -- (4)<br />
[ getAttrValue "alt"<br />
>>><br />
mkText<br />
]<br />
]<br />
where<br />
geometry :: String -> String -> String<br />
geometry "" ""<br />
= ""<br />
geometry w h<br />
= w ++ "x" ++ h<br />
</haskell><br />
<br />
In (1) the identity arrow <hask>this</hask> is used for<br />
inserting the whole image element (<hask>this</hask> value) into the first column.<br />
(2) is the column from the previous example but the URL has been made active<br />
by embedding the URL in an A-element (2.1). In (3) there are two<br />
new combinators, <hask>(&&&)</hask> (3.1) is an arrow for applying two<br />
arrows to the same input and combine the results into a pair. <hask>arr2</hask><br />
works like <hask>arr</hask> but it lifts a binary function into an arrow<br />
accepting a pair of values. <hask>arr2 f</hask> is a shortcut for<br />
<hask>arr (uncurry f)</hask>. So width and height are combined into an X11 like<br />
geometry spec. (4) adds the ALT-text.<br />
<br />
=== A page about all images within a HTML page: 2. Refinement ===<br />
<br />
The generated HTML page is not yet very useful, because it usually<br />
contains relativ HREFs to the images, so the links do not work.<br />
We have to transform the SRC attribute values into absolute URLs.<br />
This can be done with the following code:<br />
<br />
<haskell><br />
imageTable2 :: IOStateArrow s XmlTree XmlTree<br />
imageTable2<br />
= ...<br />
...<br />
, selem "table"<br />
[ collectImages<br />
>>><br />
mkAbsImageRef -- (1)<br />
>>><br />
genTableRows<br />
]<br />
...<br />
<br />
mkAbsImageRef :: IOStateArrow s XmlTree XmlTree -- (1)<br />
mkAbsImageRef<br />
= processAttrl ( mkAbsRef -- (2)<br />
`when`<br />
hasName "src" -- (3)<br />
)<br />
where<br />
mkAbsRef -- (4)<br />
= replaceChildren<br />
( xshow getChildren -- (5)<br />
>>><br />
( mkAbsURI `orElse` this ) -- (6)<br />
>>><br />
mkText -- (7)<br />
)<br />
</haskell><br />
<br />
The <hask>imageTable2</hask> is extended by an arrow <hask>mkAbsImageRef</hask><br />
(1). This arrow uses the global system state of HXT, in which the base URL<br />
of a document is stored. For editing the SRC attribute value, the attribute list<br />
of the image elements is processed with <hask>processAttrl</hask>.<br />
With the <hask>`when` hasName "src"</hask> only SRC attributes are manipulated (3). The real work is done in (4): The URL is selected with <hask>getChildren</hask>, a text node, and converted into a string (<hask>xshow</hask>), the URL is transformed into an absolute URL<br />
with <hask>mkAbsURI</hask> (6). This arrow may fail, e.g. in case of illegal<br />
URLs. In this case the URL remains unchanged (<hask>`orElse` this</hask>).<br />
The resulting String value is converted into a text node forming the new<br />
attribute value node (7).<br />
<br />
Because of the use of the use of the global HXT state in <hask>mkAbsURI</hask><br />
<hask>mkAbsRef</hask> and <hask>imageTable2</hask> need to have the more specialized signature <hask>IOStateArrow s XmlTree XmlTree</hask>.<br />
<br />
== Transformation examples ==<br />
<br />
=== Decorating external references of an HTML document ===<br />
<br />
In the following examples, we want to decorate the external references<br />
in an HTML page by a small icon, like it's done in many wikis.<br />
For this task the document tree has to be traversed, all parts<br />
except the intersting A-Elements remain unchanged. At the end of the list of children of an A-Element we add an image element.<br />
<br />
Here is the first version:<br />
<br />
<haskell><br />
addRefIcon :: ArrowXml a => a XmlTree XmlTree<br />
addRefIcon<br />
= processTopDown -- (1)<br />
( addImg -- (2)<br />
`when`<br />
isExternalRef -- (3)<br />
)<br />
where<br />
isExternalRef -- (4)<br />
= isElem<br />
>>><br />
hasName "a"<br />
>>><br />
hasAttr "href"<br />
>>><br />
getAttrValue "href"<br />
>>><br />
isA isExtRef<br />
where<br />
isExtRef -- (4.1)<br />
= isPrefixOf "http:" -- or something more precise<br />
<br />
addImg<br />
= replaceChildren -- (5)<br />
( getChildren -- (6)<br />
<+><br />
imgElement -- (7)<br />
)<br />
<br />
imgElement<br />
= mkelem "img" -- (8)<br />
[ sattr "src" "/icons/ref.png" -- (9)<br />
, sattr "alt" "external ref"<br />
] [] -- (10)<br />
</haskell><br />
<br />
The traversal is done with <hask>processTopDown</hask> (1).<br />
This arrow applies an arrow to all nodes of the whole document tree.<br />
The transformation arrow applies the <hask>addImg</hask> (2) to<br />
all A-elements (3),(4). This arrow uses a bit simplified test (4.1)<br />
for external URLs.<br />
<hask>addImg</hask> manipulates all children (5) of the A-elements by<br />
selecting the current children (6) and adding an image element (7).<br />
The image element is constructed with <hask>mkelem</hask> (8). This takes<br />
an element name, a list of arrows for computing the attributes and a<br />
list of arrows for computing the contents. The content of the image element is<br />
empty (10). The attributes are constructed with <hask>sattr</hask> (9).<br />
<hask>sattr</hask> ignores the arrow input and builds an attribute form<br />
the name value pair of arguments.<br />
<br />
=== Transform external references into absolute references ===<br />
<br />
In the following example we will develop a program for<br />
editing a HTML page such that all references to external documents<br />
(images, hypertext refs, style refs, ...) become absolute references.<br />
We will see some new, but very useful combinators in the solution.<br />
<br />
The task seems to be rather trivial. In a tree travaersal<br />
all references are edited with respect to the document base.<br />
But in HTML there is a BASE element, allowed in the content of HEAD<br />
with a HREF attribute, which defines the document base. Again this<br />
href can be a relative URL.<br />
<br />
We start the development with the editing arrow. This gets<br />
the real document base as argument.<br />
<br />
<haskell><br />
mkAbsHRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsHRefs base<br />
= processTopDown editHRef -- (1)<br />
where<br />
editHRef<br />
= processAttrl -- (3)<br />
( changeAttrValue (absHRef base) -- (5)<br />
`when`<br />
hasName "href" -- (4)<br />
)<br />
`when`<br />
( isElem >>> hasName "a" ) -- (2)<br />
where<br />
<br />
absHRef :: String -> String -> String -- (5)<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
The tree is traversed (1) and for every A element the attribute<br />
list is processed (2). All HREF attribute values (4) are manipulated<br />
by <hask>changeAttrValue</hask> called with a string function (5).<br />
<hask>expandURIString</hask> is a pure function defined in HXT for computing<br />
an absolut URI.<br />
In this first step we only edit A-HREF attribute values. We will refine this<br />
later.<br />
<br />
The second step is the complete computation of the base URL.<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( isElem >>> hasName "html" -- (0)<br />
>>><br />
getChildren -- (1)<br />
>>><br />
isElem >>> hasName "head" -- (2)<br />
>>><br />
getChildren -- (3)<br />
>>><br />
isElem >>> hasName "base" -- (4)<br />
>>><br />
getAttrValue "href" -- (5)<br />
)<br />
&&&<br />
getBaseURI -- (6)<br />
)<br />
>>> expandURI -- (7)<br />
)<br />
`orElse` getBaseURI -- (8)<br />
</haskell><br />
<br />
Input to this arrow is the HTML element, (0) to (5) is the arrow for selecting<br />
the BASE elements HREF value, parallel to this the system base URL is read<br />
with <hask>getBaseURI</hask> (6) like in examples above. The resulting <br />
pair of strings is piped into <hask>expandURI</hask> (7), the arrow version of<br />
<hask>expandURIString</hask>. This arrow ((1) to (7)) fails in the absense<br />
of a BASE element. in this case we take the plain document base (8).<br />
The selection of the BASE elements is not yet very handy. We will define<br />
a more general and elegant function later, allowing an element path as selection argument.<br />
<br />
In the third step, we will combine the to arrows. For this we will use<br />
a new combinator <hask>($<)</hask>. The need for this new combinator<br />
is the following: We need the arrow input (the document) two times,<br />
once for computing the document base, and second for editing the<br />
whole document, and we want to compute the extra string parameter<br />
for editing of course with the above defined arrow.<br />
<br />
The combined arrow, our main arrow, looks like this<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= mkAbsHRefs $< computeBaseRef -- (1)<br />
</haskell><br />
<br />
In (1) first the arrow input is piped into <hask>computeBaseRef</hask>,<br />
this result is used in <hask>mkAbsHRefs</hask> as extra string parameter<br />
when processing the document. Internally the <hask>($<)</hask> combinator<br />
is defined by the basic combinators <hask>(&&&), (>>>)</hask> and <hask>app</hask>, but in a bit more complex computations,<br />
this pattern occurs rather frequently, so ($<) becomes very useful.<br />
<br />
Programming with arrows is one style of point free programming. Point free<br />
programming often becomes unhandy when values are used more than once.<br />
One solution is the special arrow syntax supported by ghc and others, similar to the do notation for monads. But for many simple cases the <hask>($<)</hask> combinator and it's variants <hask>($<<), ($<<<), ($<<<<), ($<$)</hask><br />
is sufficient.<br />
<br />
To complete the development of the example, a last step is neccessary:<br />
The removal of the redundant BASE element.<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= ( mkAbsHRefs $< computeBaseRef )<br />
>>><br />
removeBaseElement<br />
<br />
removeBaseElement :: ArrowXml a => a XmlTree XmlTree<br />
removeBaseElement<br />
= processChildren<br />
( processChildren<br />
( none -- (1)<br />
`when`<br />
( isElem >>> hasName "base" )<br />
)<br />
`when`<br />
( isElem >>> hasName "head" )<br />
)<br />
</haskell><br />
<br />
In this function the children of the HEAD element are searched for<br />
a BASE element. This is removed by aplying the null arrow <hask>none</hask><br />
to the input, returning always the empty list.<br />
<hask>none `when` ...</hask> is the pattern for deleting nodes from a tree.<br />
<br />
The <hask>computeBaseRef</hask> function defined above contains an arrow pattern<br />
for selecting the right subtree that is rather common in HXT applications<br />
<br />
<haskell><br />
isElem >>> hasName n1<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName n2<br />
...<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName nm<br />
</haskell><br />
<br />
For this pattern we will define a convenient function creating the<br />
arrow for selection<br />
<br />
<haskell><br />
getDescendents :: ArrowXml a => [String] -> a XmlTree XmlTree<br />
getDescendents<br />
= foldl1 (\ x y -> x >>> getChildren >>> y) -- (1)<br />
.<br />
map (\ n -> isElem >>> hasName n) -- (2)<br />
</haskell><br />
<br />
The name list is mapped to the element checking arrow (2),<br />
the resulting list of arrows is folded with <hask>getChildren</hask><br />
into a single arrow. <hask>computeBaseRef</hask> can then be simplified<br />
and becomes more readable:<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( getDescendents ["html","head","base"] -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
...<br />
</haskell><br />
<br />
An even more general and flexible technic are the XPath expressions<br />
available for selection of document parts defined in the module<br />
<hask>Text.XML.HXT.Arrow.XmlNodeSet</hask>.<br />
<br />
With XPath <hask>computeBaseRef</hask> can be simplified to<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( ( getXPathTrees "/html/head/base" -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
</haskell><br />
<br />
Even the attribute selection can be expressed by XPath,<br />
so (1) and (2) can be combined into<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( xshow (getXPathTrees "/html/head/base@href")<br />
...<br />
</haskell><br />
<br />
The extra <hask>xshow</hask> is here required to convert the<br />
XPath result, an XmlTree, into a string.<br />
<br />
XPath defines a<br />
full language for selecting parts of an XML document.<br />
Sometimes it's rather comfortable to make selections of this<br />
type, but the XPath evaluation in general is more expensive<br />
in time and space than a simple combination of arrows, like we've<br />
seen it in <hask>getDescendends</hask>.<br />
<br />
=== Transform external references into absolute references: Refinement ===<br />
<br />
In the above example only A-HREF URLs are edited. Now we extend this<br />
to other element-attribute combinations.<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown ( editRef "a" "href" -- (2)<br />
>>><br />
editRef "img" "src" -- (3)<br />
>>><br />
editRef "link" "href" -- (4)<br />
>>><br />
editRef "script" "src" -- (5)<br />
)<br />
where<br />
editRef en an -- (1)<br />
= processAttrl ( changeAttrValue (absHRef base)<br />
`when`<br />
hasName an<br />
)<br />
`when`<br />
( isElem >>> hasName en )<br />
where<br />
absHRef :: String -> String -> String<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
<hask>editRef</hask> is parameterized by the element and attribute names.<br />
The arrow applied to every element is extended to a sequence of<br />
<hask>editRef</hask>'s ((2)-(5)). Notice that the document is still traversed only once.<br />
To process all possible HTML elements,<br />
this sequence should be extended by further element-attribute pairs.<br />
<br />
This can further be simplified into<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= foldl (>>>) this<br />
.<br />
map (\ (en, an) -> editRef en an)<br />
$<br />
[ ("a", "href")<br />
, ("img", "src")<br />
, ("link", "href")<br />
, ("script", "src") -- and more<br />
]<br />
editRef<br />
= ...<br />
</haskell><br />
<br />
The <hask>foldl (>>>) this</hask> is defined in HXT as <hask>seqA</hask>,<br />
so the above code can be simplified to<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= seqA . map (uncurry editRef)<br />
$<br />
...<br />
</haskell><br />
<br />
== More complex examples ==<br />
<br />
''' to be done '''<br />
<br />
=== Automatic read/writing between xml and Haskell data types ===<br />
<br />
'''Question''': is there any way to write/read Haskell types to/from XML in HXT? HaXml has readXml and showXml, but I can't find any similar mechanism in HXT. Help! -- AlsonKemp<br />
<br />
==== Serializing to Xml ====<br />
<br />
We can create an HXT tree from a single-layer data class as follows:<br />
<br />
<haskell><br />
import IO<br />
import Char<br />
import Text.XML.HXT.Arrow<br />
import Data.Generics<br />
<br />
-- our data class we'll convert into xml<br />
data Config = <br />
Config { username :: String,<br />
logNumDays :: Int,<br />
oleDbString :: String }<br />
deriving (Show, Typeable,Data)<br />
<br />
-- helper function adapted from http://www.defmacro.org/ramblings/haskell-web.html<br />
-- (gshow replaced by gshow')<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- function to create HXT tree arrow from single-layer Haskell data type:<br />
createHxtArrow object = runLA( constA ( xmlSerialize object ) >>> xread)<br />
<br />
-- create a config object to serialize:<br />
<br />
createConfig = Config { username = "test", logNumDays = 3, oleDbString = "qsdf" }<br />
<br />
-- test function, using our Config data type<br />
testConversion = createHxtArrow( createConfig ) ()<br />
</haskell><br />
<br />
-- hughperkins<br />
<br />
==== Deserializing from Xml ====<br />
<br />
Here's a solution to deserialize a simple haskell data type containing Strings and Ints.<br />
<br />
It's not really pretty, but it works.<br />
<br />
Basically, we just convert the incoming xml into gread-compatible format, then use gread :-D<br />
<br />
Currently it works for a simple single-layer Haskell data type containing Ints and Strings. You can add new child data types by adding to the case statement in xmlToGShowFormat.<br />
<br />
If someone has a more elegant solution, please let me know ( hughperkins@gmail.com )<br />
<br />
<haskell><br />
module ParseXml<br />
where<br />
<br />
import IO<br />
import Char<br />
import List<br />
import Maybe<br />
import Data.Generics hiding (Unit)<br />
import Text.XML.HXT.Arrow hiding (when)<br />
<br />
data Config = Config{ name :: String, age :: Int } <br />
--data Config = Config{ age :: Int } <br />
deriving( Data, Show, Typeable, Ord, Eq, Read )<br />
<br />
createConfig = Config "qsdfqsdf" 3<br />
--createConfig = Config 3<br />
gshow' :: Data a => a -> String<br />
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br />
<br />
-- helper function from http://www.defmacro.org/ramblings/haskell-web.html<br />
introspectData :: Data a => a -> [(String, String)]<br />
introspectData a = zip fields (gmapQ gshow' a)<br />
where fields = constrFields $ toConstr a<br />
<br />
-- function to create xml string from single-layer Haskell data type<br />
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br />
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br />
++ "</" ++ show(toConstr object) ++ ">"<br />
<br />
-- parse xml to HXT tree, and obtain the value of node "fieldname"<br />
-- returns a string<br />
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)<br />
| otherwise = Nothing<br />
where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName fieldname ) >>> getChildren >>> getText ))[]<br />
<br />
-- parse templateobject to get list of field names<br />
-- apply these to xml to get list of values<br />
-- return (fieldnames list, value list)<br />
xmlToGShowFormat :: Data a => String -> a -> String<br />
xmlToGShowFormat xml templateobject = <br />
go<br />
where mainconstructorname = (showConstr $ toConstr templateobject)<br />
fields = constrFields $ toConstr templateobject<br />
values = map ( \fieldname -> getValue xml fieldname ) fields<br />
datatypes = gmapQ (dataTypeOf) templateobject<br />
constrs = gmapQ (toConstr) templateobject<br />
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject<br />
fieldtogshowformat (value,datatyperep) = case datatyperep of<br />
IntRep -> "(" ++ fromJust value ++ ")"<br />
_ -> show(fromJust value)<br />
formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps)<br />
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")"<br />
<br />
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject)<br />
<br />
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config<br />
dotest' = xmlDeserialize ("<Config><age>12</age><name>test name!</name></Config>") createConfig :: Config<br />
</haskell><br />
<br />
-- hughperkins</div>Tanimotohttps://wiki.haskell.org/Talk:GHC_under_WineTalk:GHC under Wine2007-07-13T08:01:40Z<p>Tanimoto: </p>
<hr />
<div>Has anybody tried Gtk2Hs on wine?</div>Tanimotohttps://wiki.haskell.org/Talk:How_to_write_a_Haskell_programTalk:How to write a Haskell program2007-07-13T00:44:42Z<p>Tanimoto: </p>
<hr />
<div>How do people feel about<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
\begin{code}<br />
import Distribution.Simple<br />
main = defaultMain<br />
\end{code}<br />
</haskell><br />
<br />
instead of<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
<br />
> import Distribution.Simple<br />
> main = defaultMain<br />
<br />
</haskell><br />
<br />
[[User:DonStewart|dons]] 07:59, 31 October 2006 (UTC)In fact, just this works:<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
import Distribution.Simple<br />
main = defaultMain<br />
</haskell><br />
<br />
which is simplest of all<br />
<br />
== Directory structure ==<br />
<br />
Shouldn't the advise be to let all the source code be collected under src/ and the testing under test/ extra scripts under scripts/ etc.?<br />
<br />
== Thanks! ==<br />
<br />
I was putting off (and meaning to get around to) cabalising my software until I saw how easy it was on this page. BTW, I kinda like the birdtracks as is -- kowey 09:20, 31 October 2006 (UTC)<br />
<br />
== Imported to the wikibook ==<br />
<br />
I'm using this tutorial to bootstrap a the Haskell wikibook [http://en.wikibooks.org/wiki/Haskell/Packaging Packaging chapter]. The wikibook version diverges somewhat in that it ignores the Haskell community stuff, and (one day) tries to flow with the rest of the book. -- [[User:EricKow|EricKow]] 15:33, 10 January 2007 (UTC)<br />
<br />
== Error message about license field ==<br />
<br />
Just as a heads up, I'm getting this error message after creating a project with mkcabal:<br />
<haskell><br />
$ runhaskell Setup.lhs configure<br />
Setup.lhs: testing.cabal:4: Parse of field 'license' failed:<br />
</haskell><br />
<br />
Upon inspection, it seems that it doesn't like 'GPL2' or 'GPL3'. I manually changed it to 'GPL', as shown in the wiki page, and it worked. I tested this on ghc 6.6 and ghc 6.6.1. --[[User:tanimoto|tanimoto]]<br />
<br />
Perhaps submit a patch to add support for other licenses? [[User:DonStewart|dons]] 09:25, 12 July 2007 (UTC)<br />
<br />
Thanks, dons, but let me check to see if this is actually due to the fact that I'm using an older version of Cabal. [[User:tanimoto|tanimoto]]</div>Tanimotohttps://wiki.haskell.org/Talk:How_to_write_a_Haskell_programTalk:How to write a Haskell program2007-07-12T07:11:50Z<p>Tanimoto: </p>
<hr />
<div>How do people feel about<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
\begin{code}<br />
import Distribution.Simple<br />
main = defaultMain<br />
\end{code}<br />
</haskell><br />
<br />
instead of<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
<br />
> import Distribution.Simple<br />
> main = defaultMain<br />
<br />
</haskell><br />
<br />
[[User:DonStewart|dons]] 07:59, 31 October 2006 (UTC)In fact, just this works:<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
import Distribution.Simple<br />
main = defaultMain<br />
</haskell><br />
<br />
which is simplest of all<br />
<br />
== Directory structure ==<br />
<br />
Shouldn't the advise be to let all the source code be collected under src/ and the testing under test/ extra scripts under scripts/ etc.?<br />
<br />
== Thanks! ==<br />
<br />
I was putting off (and meaning to get around to) cabalising my software until I saw how easy it was on this page. BTW, I kinda like the birdtracks as is -- kowey 09:20, 31 October 2006 (UTC)<br />
<br />
== Imported to the wikibook ==<br />
<br />
I'm using this tutorial to bootstrap a the Haskell wikibook [http://en.wikibooks.org/wiki/Haskell/Packaging Packaging chapter]. The wikibook version diverges somewhat in that it ignores the Haskell community stuff, and (one day) tries to flow with the rest of the book. -- [[User:EricKow|EricKow]] 15:33, 10 January 2007 (UTC)<br />
<br />
== Error message about license field ==<br />
<br />
Just as a heads up, I'm getting this error message after creating a project with mkcabal:<br />
<haskell><br />
$ runhaskell Setup.lhs configure<br />
Setup.lhs: testing.cabal:4: Parse of field 'license' failed:<br />
</haskell><br />
<br />
Upon inspection, it seems that it doesn't like 'GPL2' or 'GPL3'. I manually changed it to 'GPL', as shown in the wiki page, and it worked. I tested this on ghc 6.6 and ghc 6.6.1. --[[User:tanimoto|tanimoto]]</div>Tanimotohttps://wiki.haskell.org/Talk:How_to_write_a_Haskell_programTalk:How to write a Haskell program2007-07-12T07:11:36Z<p>Tanimoto: </p>
<hr />
<div>How do people feel about<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
\begin{code}<br />
import Distribution.Simple<br />
main = defaultMain<br />
\end{code}<br />
</haskell><br />
<br />
instead of<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
<br />
> import Distribution.Simple<br />
> main = defaultMain<br />
<br />
</haskell><br />
<br />
[[User:DonStewart|dons]] 07:59, 31 October 2006 (UTC)In fact, just this works:<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
import Distribution.Simple<br />
main = defaultMain<br />
</haskell><br />
<br />
which is simplest of all<br />
<br />
== Directory structure ==<br />
<br />
Shouldn't the advise be to let all the source code be collected under src/ and the testing under test/ extra scripts under scripts/ etc.?<br />
<br />
== Thanks! ==<br />
<br />
I was putting off (and meaning to get around to) cabalising my software until I saw how easy it was on this page. BTW, I kinda like the birdtracks as is -- kowey 09:20, 31 October 2006 (UTC)<br />
<br />
== Imported to the wikibook ==<br />
<br />
I'm using this tutorial to bootstrap a the Haskell wikibook [http://en.wikibooks.org/wiki/Haskell/Packaging Packaging chapter]. The wikibook version diverges somewhat in that it ignores the Haskell community stuff, and (one day) tries to flow with the rest of the book. -- [[User:EricKow|EricKow]] 15:33, 10 January 2007 (UTC)<br />
<br />
== Error message with license field ==<br />
<br />
Just as a heads up, I'm getting this error message after creating a project with mkcabal:<br />
<haskell><br />
$ runhaskell Setup.lhs configure<br />
Setup.lhs: testing.cabal:4: Parse of field 'license' failed:<br />
</haskell><br />
<br />
Upon inspection, it seems that it doesn't like 'GPL2' or 'GPL3'. I manually changed it to 'GPL', as shown in the wiki page, and it worked. I tested this on ghc 6.6 and ghc 6.6.1. --[[User:tanimoto|tanimoto]]</div>Tanimotohttps://wiki.haskell.org/Talk:How_to_write_a_Haskell_programTalk:How to write a Haskell program2007-07-12T07:09:14Z<p>Tanimoto: </p>
<hr />
<div>How do people feel about<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
\begin{code}<br />
import Distribution.Simple<br />
main = defaultMain<br />
\end{code}<br />
</haskell><br />
<br />
instead of<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
<br />
> import Distribution.Simple<br />
> main = defaultMain<br />
<br />
</haskell><br />
<br />
[[User:DonStewart|dons]] 07:59, 31 October 2006 (UTC)In fact, just this works:<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
import Distribution.Simple<br />
main = defaultMain<br />
</haskell><br />
<br />
which is simplest of all<br />
<br />
== Directory structure ==<br />
<br />
Shouldn't the advise be to let all the source code be collected under src/ and the testing under test/ extra scripts under scripts/ etc.?<br />
<br />
== Thanks! ==<br />
<br />
I was putting off (and meaning to get around to) cabalising my software until I saw how easy it was on this page. BTW, I kinda like the birdtracks as is -- kowey 09:20, 31 October 2006 (UTC)<br />
<br />
== Imported to the wikibook ==<br />
<br />
I'm using this tutorial to bootstrap a the Haskell wikibook [http://en.wikibooks.org/wiki/Haskell/Packaging Packaging chapter]. The wikibook version diverges somewhat in that it ignores the Haskell community stuff, and (one day) tries to flow with the rest of the book. -- [[User:EricKow|EricKow]] 15:33, 10 January 2007 (UTC)<br />
<br />
== Error message ==<br />
<br />
Just as a heads up, I'm getting this error message after creating a project with mkcabal:<br />
<haskell><br />
$ runhaskell Setup.lhs configure<br />
Setup.lhs: testing.cabal:4: Parse of field 'license' failed:<br />
</haskell><br />
<br />
Upon inspection, it seems that it doesn't like 'GPL2' or 'GPL3'. I manually changed it to 'GPL', as shown in the wiki page, and it worked. I tested this on ghc 6.6 and ghc 6.6.1. --[[User:tanimoto|tanimoto]]</div>Tanimotohttps://wiki.haskell.org/Talk:How_to_write_a_Haskell_programTalk:How to write a Haskell program2007-07-12T07:08:19Z<p>Tanimoto: </p>
<hr />
<div>How do people feel about<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
\begin{code}<br />
import Distribution.Simple<br />
main = defaultMain<br />
\end{code}<br />
</haskell><br />
<br />
instead of<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
<br />
> import Distribution.Simple<br />
> main = defaultMain<br />
<br />
</haskell><br />
<br />
[[User:DonStewart|dons]] 07:59, 31 October 2006 (UTC)In fact, just this works:<br />
<br />
<haskell><br />
#!/usr/bin/env runhaskell<br />
import Distribution.Simple<br />
main = defaultMain<br />
</haskell><br />
<br />
which is simplest of all<br />
<br />
== Directory structure ==<br />
<br />
Shouldn't the advise be to let all the source code be collected under src/ and the testing under test/ extra scripts under scripts/ etc.?<br />
<br />
== Thanks! ==<br />
<br />
I was putting off (and meaning to get around to) cabalising my software until I saw how easy it was on this page. BTW, I kinda like the birdtracks as is -- kowey 09:20, 31 October 2006 (UTC)<br />
<br />
== Imported to the wikibook ==<br />
<br />
I'm using this tutorial to bootstrap a the Haskell wikibook [http://en.wikibooks.org/wiki/Haskell/Packaging Packaging chapter]. The wikibook version diverges somewhat in that it ignores the Haskell community stuff, and (one day) tries to flow with the rest of the book. -- [[User:EricKow|EricKow]] 15:33, 10 January 2007 (UTC)<br />
<br />
== Error message ==<br />
<br />
Just as a heads up, I'm getting this error message after creating a project with mkcabal:<br />
<haskell><br />
$ runhaskell Setup.lhs configure<br />
Setup.lhs: testing.cabal:4: Parse of field 'license' failed:<br />
</haskell><br />
<br />
Upon inspection, it seems that it doesn't like 'GPL2' or 'GPL3'. I manually changed it to 'GPL', as shown in the wiki page, and it worked. I tested this on ghc 6.6 and ghc 6.6.1. [[User:Paulo|tanimoto]]</div>Tanimoto