https://wiki.haskell.org/api.php?action=feedcontributions&user=Weihu&feedformat=atomHaskellWiki - User contributions [en]2019-12-10T15:49:09ZUser contributionsMediaWiki 1.27.4https://wiki.haskell.org/index.php?title=Numeric_Haskell:_A_Vector_Tutorial&diff=33748Numeric Haskell: A Vector Tutorial2010-02-21T07:26:49Z<p>Weihu: </p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
[http://hackage.haskell.org/package/vector Vector] is a Haskell library for working with arrays. It has an emphasis on very high performance through loop fusion, whilst retaining a rich interface. The main data types are boxed and unboxed arrays, and arrays may be immutable (pure), or mutable. Arrays may hold Storable elements, suitable for passing to and from C, and you can convert between the array types. Arrays are indexed by non-negative <hask>Int</hask> values.<br />
<br />
The vector library has an API similar to the famous Haskell list library, with many of the same names.<br />
<br />
This tutorial is modelled on [http://www.scipy.org/Tentative_NumPy_Tutorial the NumPy tutorial].<br />
<br />
__TOC__<br />
<br />
= Quick Tour =<br />
<br />
Here is a quick overview to get you started.<br />
<br />
== Importing the library ==<br />
<br />
Download the vector package:<br />
<br />
$ cabal install vector<br />
<br />
and import it as, for boxed arrays:<br />
<br />
<haskell><br />
import qualified Data.Vector as V<br />
</haskell><br />
<br />
or:<br />
<br />
<haskell><br />
import qualified Data.Vector.Unboxed as V<br />
</haskell><br />
<br />
for unboxed arrays. The library needs to be imported qualified as it shares the same function names as list operations in the Prelude.<br />
<br />
== Generating Vectors ==<br />
<br />
New vectors can be generated in many ways:<br />
<br />
<haskell><br />
$ ghci<br />
GHCi, version 6.12.1: 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 />
<br />
Prelude> :m + Data.Vector<br />
<br />
-- Generating a vector from a list:<br />
Prelude Data.Vector> let a = fromList [10, 20, 30, 40]<br />
<br />
Prelude Data.Vector> a<br />
fromList [10,20,30,40] :: Data.Vector.Vector<br />
<br />
-- Or filled from a sequence<br />
Prelude Data.Vector> enumFromStepN 10 10 4<br />
fromList [10,20,30,40] :: Data.Vector.Vector<br />
<br />
-- A vector created from four consecutive values<br />
Prelude Data.Vector> enumFromN 10 4<br />
fromList [10,11,12,13] :: Data.Vector.Vector<br />
</haskell><br />
<br />
You can also build vectors using operations similar to lists:<br />
<br />
<haskell><br />
-- The empty vector<br />
Prelude Data.Vector> empty<br />
fromList [] :: Data.Vector.Vector<br />
<br />
-- A vector of length one<br />
Prelude Data.Vector> singleton 2<br />
fromList [2] :: Data.Vector.Vector<br />
<br />
-- A vector of length 10, filled with the value '2'<br />
-- Note that to disambiguate names,<br />
-- and avoid a clash with the Prelude,<br />
-- with use the full path to the Vector module<br />
Prelude Data.Vector> Data.Vector.replicate 10 2<br />
fromList [2,2,2,2,2,2,2,2,2,2] :: Data.Vector.Vector<br />
</haskell><br />
<br />
In general, you may construct new vectors by applying a function to the index space:<br />
<br />
<haskell><br />
Prelude Data.Vector> generate 10 (^2)<br />
fromList [0,1,4,9,16,25,36,49,64,81] :: Data.Vector.Vector<br />
</haskell><br />
<br />
Vectors may have more than one dimension:<br />
<br />
<haskell><br />
-- Here we create a two dimensional vector, 10 columns,<br />
-- each row filled with the row index.<br />
Prelude Data.Vector> let x = generate 10 (\n -> Data.Vector.replicate 10 n)<br />
<br />
-- The type is "Vector of Vector of Ints"<br />
Prelude Data.Vector> :t x<br />
x :: Vector (Vector Int)<br />
</haskell><br />
<br />
Vectors may be grown or shrunk arbitrarily:<br />
<br />
<haskell><br />
Prelude Data.Vector> let y = Data.Vector.enumFromTo 0 11<br />
Prelude Data.Vector> y<br />
fromList [0,1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
<br />
-- Take the first 3 elements as a new vector<br />
Prelude Data.Vector> Data.Vector.take 3 y<br />
fromList [0,1,2] :: Data.Vector.Vector<br />
<br />
-- Duplicate and join the vector<br />
Prelude Data.Vector> y Data.Vector.++ y<br />
fromList [0,1,2,3,4,5,6,7,8,9,10,11,0,1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Modifying vectors ==<br />
<br />
Just as with lists, you can iterate (map) over arrays, reduce them (fold), filter them, or join them in various ways:<br />
<br />
<haskell><br />
-- mapping a function over the elements of a vector<br />
Prelude Data.Vector> Data.Vector.map (^2) y<br />
fromList [0,1,4,9,16,25,36,49,64,81,100,121] :: Data.Vector.Vector<br />
<br />
-- Extract only the odd elements from a vector<br />
Prelude Data.Vector> Data.Vector.filter odd y<br />
fromList [1,3,5,7,9,11] :: Data.Vector.Vector<br />
<br />
-- Reduce a vector<br />
Prelude Data.Vector> Data.Vector.foldl (+) 0 y<br />
66<br />
<br />
-- Take a scan (partial results from a reduction):<br />
Prelude Data.Vector> Data.Vector.scanl (+) 0 y<br />
fromList [0,0,1,3,6,10,15,21,28,36,45,55,66] :: Data.Vector.Vector<br />
<br />
-- Zip two arrays pairwise, into an array of pairs<br />
Prelude Data.Vector> Data.Vector.zip y y<br />
fromList [(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11)] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Indexing vectors ==<br />
<br />
And like all good arrays, you can index them in various ways:<br />
<br />
<haskell><br />
-- Take the first element<br />
Prelude Data.Vector> Data.Vector.head y<br />
0<br />
<br />
-- Take the last element<br />
Prelude Data.Vector> Data.Vector.tail y<br />
fromList [1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
<br />
-- Take an arbitrary element<br />
Prelude Data.Vector> y ! 4<br />
4<br />
</haskell><br />
<br />
= The Tutorial =<br />
<br />
The vector package provides several types of array. The most general interface is via [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector.html Data.Vector], which provides for boxed arrays, holding any type.<br />
<br />
There are also more specialized array types:<br />
<br />
* [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Unboxed.html Unboxed] <br />
* [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Storable.html Storable] <br />
<br />
which provide unboxed arrays (i.e. no closures) and storable arrays (data that is pinned, and may be passed to and from C via a Ptr).<br />
<br />
In all cases, the operations are subject to loop fusion. That is, if you compose two functions, <br />
<br />
map f . map g<br />
<br />
the compiler will rewrite it into a single traversal:<br />
<br />
map (f . g)<br />
<br />
saving time and space.<br />
<br />
== Simple example ==<br />
<br />
You can create the arrays in many ways, for example, from a regular Haskell list:<br />
<br />
<haskell<br />
Prelude Data.Vector> let a = fromList [2,3,4]<br />
<br />
Prelude Data.Vector> a<br />
fromList [2,3,4] :: Data.Vector.Vector<br />
<br />
Prelude Data.Vector> :t a<br />
a :: Vector Integer<br />
</haskell><br />
<br />
GHCi will print the contents of the vector as executable code.<br />
<br />
To create a multidimensional array, you can use a nested list generator to fill it:<br />
<br />
<haskell><br />
Prelude Data.Vector> let x = fromList [ fromList [1 .. x] | x <- [1..10] ]<br />
<br />
Prelude Data.Vector> :t x<br />
x :: Vector (Vector Integer)<br />
</haskell><br />
<br />
-- XXX TODO need a better printing function for multidimensional arrays.<br />
<br />
You can also just create arrays filled with zeroes:<br />
<br />
<haskell><br />
Prelude Data.Vector> Data.Vector.replicate 10 0<br />
fromList [0,0,0,0,0,0,0,0,0,0] :: Data.Vector.Vector<br />
</haskell><br />
<br />
And you can fill arrays from a sequence generator:<br />
<br />
<haskell><br />
Prelude Data.Vector> enumFromN 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10] :: Data.Vector.Vector<br />
<br />
Prelude Data.Vector> enumFromStepN 0 10 10<br />
fromList [0,10,20,30,40,50,60,70,80,90] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Array Types ==<br />
<br />
The vector package provides several array types, with an identical interface. They have different flexibility with respect to the types of values that may be stored in them, and different performance characteristics.<br />
<br />
In general:<br />
<br />
* End users should use Data.Vector.Unboxed for most cases<br />
* If you need to store more complex structures, use Data.Vector<br />
* If you need to pass to C, use Data.Vector.Storable<br />
<br />
For library writers;<br />
<br />
* Use the generic interface, to ensure your library is maximally flexible: Data.Vector.Generic<br />
<br />
<br />
=== Boxed Arrays: Data.Vector ===<br />
<br />
The most flexible type is [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector.html#t%3AVector Data.Vector.Vector], which provides *boxed* arrays: arrays of pointers to Haskell values.<br />
<br />
* Data.Vector.Vector's are fully polymorphic: they can hold any valid Haskell type<br />
<br />
These arrays are suitable for storing complex Haskell types (sum types, or algebraic data types), but a better choice for simple data types is Data.Vector.Unboxed.<br />
<br />
=== Unboxed Arrays: Data.Vector.Unboxed ===<br />
<br />
Simple, atomic types, and pair types can be stored in a more efficient manner: consecutive memory slots without pointers. The [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Unboxed.html#t%3AVector Data.Array.Unboxed.Vector] type provides unboxed arrays of types that are members of the Unbox class, including:<br />
<br />
* Bool<br />
* ()<br />
* Char<br />
* Double<br />
* Float<br />
* Int<br />
* Int8, 16, 32, 64<br />
* Word<br />
* Word8, 16, 32, 64<br />
* Complex a's, where 'a' is in Unbox<br />
* Tuple types, where the elements are unboxable<br />
<br />
Unboxed arrays should be preferred when you have unboxable elements, as they are generally more efficient.<br />
<br />
=== Storable Arrays: passing data to C ===<br />
<br />
Storable arrays ([http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Storable.html#t%3AVector Data.Vector.Storable.Vector]) are vectors of any type in the Storable class.<br />
<br />
These arrays are pinned, and may be converted to and from pointers, that may be passed to C functions, using a number of functions:<br />
<br />
<haskell><br />
unsafeFromForeignPtr<br />
:: Storable a<br />
=> ForeignPtr a<br />
-> Int<br />
-> Int <br />
-> Vector a <br />
<br />
-- Create a vector from a ForeignPtr with an offset and a length. The data may<br />
-- not be modified through the ForeignPtr afterwards.<br />
<br />
unsafeToForeignPtr<br />
:: Storable a<br />
=> Vector a<br />
-> (ForeignPtr a, Int, Int)<br />
<br />
-- Yield the underlying ForeignPtr together with the offset to the data and its<br />
-- length. The data may not be modified through the ForeignPtr.<br />
<br />
unsafeWith<br />
:: Storable a<br />
=> Vector a<br />
-> (Ptr a -> IO b)<br />
-> IO b<br />
<br />
-- Pass a pointer to the vector's data to the IO action. The data may not be<br />
-- modified through the 'Ptr.<br />
</haskell><br />
<br />
=== Pure Arrays ===<br />
=== Impure Arrays ===<br />
<br />
Arrays can be created and operated on in a mutable fashion -- using destructive updates, as in an imperative language. Once all operations are complete, the mutable array can be "frozen" to a pure array, which changes its type.<br />
<br />
Mutable arrays plus freezing are quite useful for initializing arrays from data in the outside world.<br />
<br />
For example, to fill a, generic array, we first<br />
<br />
* allocate an empty vector of size @n@<br />
* destructively update the cells using a generator function<br />
* freeze the array and return it as a pure value.<br />
<br />
<haskell><br />
import qualified System.Random.Mersenne as R<br />
<br />
import qualified Data.Vector.Generic as G<br />
import qualified Data.Vector.Generic.Mutable as GM<br />
<br />
random :: (R.MTRandom a, G.Vector v a) => R.MTGen -> Int -> IO (v a)<br />
random g n = do<br />
v <- GM.new n<br />
fill v 0<br />
G.unsafeFreeze v<br />
where<br />
fill v i<br />
| i < n = do<br />
x <- R.random g<br />
GM.unsafeWrite v i x<br />
fill v (i+1)<br />
| otherwise = return ()<br />
</haskell><br />
<br />
Here we use the Data.Vector.Generic.Mutable.new to allocate a new, uninitialized array, which we then write elements to (using unsafeWrite).<br />
<br />
By using the generic interface, we can construct boxed, storable or unboxed arrays all from the same code.<br />
<br />
=== Some examples ===<br />
<br />
The most important attributes of an array are available in O(1) time, such as the size (length), <br />
<br />
<haskell><br />
-- how big is the array?<br />
Prelude Data.Vector> let a = fromList [1,2,3,4,5,6,7,8,9,10]<br />
Prelude Data.Vector> Data.Vector.length a<br />
10<br />
<br />
-- is the array empty?<br />
Prelude Data.Vector> Data.Vector.null a<br />
False<br />
</haskell><br />
<br />
== Array Creation ==<br />
<br />
=== Enumerations ===<br />
<br />
The most common way to generate a vector is via an enumeration function:<br />
<br />
* enumFromN<br />
* enumFromStepN<br />
<br />
And the list-like:<br />
<br />
* enumFromTo<br />
* enumFromThenTo <br />
<br />
The enumFrom*N functions are guaranteed to optimize well for any type. The enumFromTo functions might fall back to generating from lists if there is no specialization for your type. They are currently specialized to most Int/Word/Double/Float generators.<br />
<br />
<haskell><br />
> enumFromN 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10]<br />
<br />
> enumFromStepN 1 3 4<br />
fromList [1,4,7,10]<br />
<br />
> Data.Vector.enumFromTo 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10]<br />
<br />
-- counting backwards<br />
> Data.Vector.enumFromThenTo 10 9 1<br />
fromList [10,9,8,7,6,5,4,3,2,1]<br />
</haskell><br />
<br />
==== A note on fusion ====<br />
<br />
As for almost all vector functions, if an enumerator is composed with a traversal or fold, they will fuse into a single loop.<br />
<br />
For example, we can fuse generation of an array of doubles, with computing the product of the square roots. The source program consists of two loops:<br />
<br />
<haskell><br />
import qualified Data.Vector as V<br />
<br />
test :: V.Vector Int -> Double<br />
test = V.foldl (\ a b -> a * sqrt (fromIntegral b)) 0<br />
<br />
create :: Int -> V.Vector Int<br />
create n = (V.enumFromTo 1 n)<br />
<br />
main = print (test (create 1000000))<br />
</haskell><br />
<br />
And after optimization (revealed with the ghc-core tool), we have only one loop:<br />
<br />
<haskell><br />
main_$s$wfoldlM_loop :: Int# -> Double# -> Double#<br />
<br />
main_$s$wfoldlM_loop =<br />
\ (sc_sWA :: Int#) (sc1_sWB :: Double#) -><br />
case <=# sc_sWA 1000000 of _ {<br />
False -> sc1_sWB;<br />
True -><br />
main_$s$wfoldlM_loop<br />
(+# sc_sWA 1)<br />
(*##<br />
sc1_sWB (sqrtDouble# (int2Double# sc_sWA)))<br />
}<br />
</haskell><br />
<br />
Doubling the performance, by halving the number of traversals. Fusion also means we can avoid any intermediate data structure allocation.<br />
<br />
=== An example: filling a vector from a file ===<br />
<br />
We often want to populate a vector using a external data file. The easiest way to do this is with bytestring IO, and Data.Vector.unfoldr (or the equivalent functions in Data.Vector.Unboxed or Data.Vector.Storable:<br />
<br />
==== Parsing Ints ====<br />
<br />
The simplest way to parse a file of Int or Integer types is with a strict or lazy ByteString, and the readInt or readInteger functions:<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.Vector as U<br />
import System.Environment<br />
<br />
main = do<br />
[f] <- getArgs<br />
s <- L.readFile f<br />
print . U.sum . parse $ s<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = U.unfoldr step<br />
where<br />
step !s = case L.readInt s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
Note the use of bang patterns to ensure the parsing accumulated state is produced strictly.<br />
<br />
Create a data file filled with 1 million integers:<br />
<br />
$ seq 1 1000000 > data<br />
<br />
Compile with -Odph (enables special optimizations to help fusion):<br />
<br />
$ ghc -Odph --make vector.hs<br />
<br />
Run:<br />
<br />
$ time ./vector data <br />
500000500000<br />
./vector data 0.08s user 0.01s system 98% cpu 0.088 total<br />
<br />
==== Parsing Floating Point Values ====<br />
<br />
To load a file of floating point values into a vector, you can use bytestrings and the [http://hackage.haskell.org/package/bytestring-lexing bytestring-lexing] package, which provides readDouble and readFloat functions.<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.ByteString.Lex.Lazy.Double as L<br />
import qualified Data.Vector as U<br />
import System.Environment<br />
<br />
main = do<br />
[f] <- getArgs<br />
s <- L.readFile f<br />
print . U.sum . parse $ s<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = U.unfoldr step<br />
where<br />
step !s = case L.readDouble s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
=== Parsing Binary Data ===<br />
<br />
The best way to parse binary data is via bytestrings and the [http://hackage.haskell.org/package/binary Data.Binary] package.<br />
<br />
There are instances of Binary and Serialize available in the [http://hackage.haskell.org/package/vector-binary-instances-0.1 vector-binary-<br />
instances] package.<br />
<br />
An example: parsing a list of integers in text form, serializing them back in binary form, then loading that binary file:<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import Data.Vector.Binary<br />
import Data.Binary<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.Vector.Unboxed as V<br />
<br />
main = do<br />
s <- L.readFile "dat"<br />
let v = parse s :: V.Vector Int<br />
encodeFile "dat2" v<br />
v' <- decodeFile "dat2" :: IO (V.Vector Int)<br />
print (v == v')<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = V.unfoldr step<br />
where<br />
step !s = case L.readInt s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
=== Random numbers ===<br />
<br />
If we can parse from a file, we can also fill a vector with random numbers. <br />
We'll use the [http://hackage.haskell.org/package/mersenne-random mersenne-random] package:<br />
<br />
$ cabal install mersenne-random<br />
<br />
We can then use MTRandom class to generate random vectors of different types:<br />
<br />
<haskell><br />
import qualified Data.Vector.Unboxed as U<br />
import System.Random.Mersenne<br />
import Control.Monad<br />
<br />
main = do<br />
-- create a new source of randomness<br />
-- andan infinite list of randoms<br />
g <- newMTGen Nothing<br />
rs <- randoms g<br />
<br />
-- fill a vector with the first 10 random Ints<br />
let a = U.fromList (take 10 rs) :: U.Vector Int<br />
<br />
-- print the sum<br />
print (U.sum a)<br />
<br />
-- print each element<br />
forM_ (U.toList a) print<br />
</haskell><br />
<br />
Running it:<br />
<br />
<haskell><br />
$ runhaskell B.hs<br />
-56426044567146682<br />
-2144043065897064806<br />
-2361203915295681429<br />
1023751035988638668<br />
-5145147152582103336<br />
6545758323081548799<br />
-7630294342751488332<br />
-5861937811333342436<br />
-3198510304070719259<br />
8949914511577398116<br />
-8681457396993884283<br />
</haskell><br />
<br />
We can also just use the vector-random package to generate new vectors initialized with the mersenne twister generator:<br />
<br />
For example, to generate 100 million random Doubles and sum them:<br />
<br />
<haskell><br />
<br />
import qualified Data.Vector.Unboxed as U<br />
import System.Random.Mersenne<br />
import qualified Data.Vector.Random.Mersenne as G<br />
<br />
main = do<br />
g <- newMTGen Nothing<br />
a <- G.random g 10000000 :: IO (U.Vector Double) -- 100 M<br />
print (U.sum a)<br />
</haskell><br />
<br />
== Transformations on Vectors ==<br />
<br />
A primary operation on arrays are the zip class of functions. <br />
<br />
<haskell><br />
> let a = fromList [20,30,40,50]<br />
<br />
> let b = enumFromN 0 4<br />
<br />
> a <br />
fromList [20,30,40,50]<br />
<br />
> b<br />
fromList [0,1,2,3]<br />
<br />
> Data.Vector.zipWith (-) a b<br />
fromList [20,29,38,47]<br />
</haskell><br />
<br />
We can also, of course, apply a function to each element of a vector (map):<br />
<br />
<haskell><br />
> Data.Vector.map (^2) b<br />
fromList [0,1,4,9]<br />
<br />
> Data.Vector.map (\e -> 10 * sin (fromIntegral e)) a<br />
fromList [9.129452507276277,-9.880316240928618,7.451131604793488,-2.6237485370392877]<br />
<br />
> Data.Vector.map (< 35) a<br />
fromList [True,True,False,False]<br />
</haskell><br />
<br />
=== Folds: Sums, Products, Min, Max ===<br />
<br />
Many special purpose folds (reductions) on vectors are available:<br />
<br />
<haskell><br />
> let a = enumFromN 1 100<br />
<br />
> Data.Vector.sum a<br />
5050<br />
<br />
> Data.Vector.product a<br />
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000<br />
<br />
> Data.Vector.minimum a<br />
1<br />
<br />
> Data.Vector.maximum a<br />
100<br />
</haskell><br />
<br />
== Indexing, Slicing and Iterating ==<br />
<br />
One dimensional arrays can be indexed, sliced and iterated over pretty much like lists.<br />
<br />
Because Haskell values are by default immutable, all slice operations are zero-copying.<br />
<br />
<haskell><br />
> let a = enumFromN 0 10<br />
<br />
> a<br />
fromList [0,1,2,3,4,5,6,7,8,9]<br />
<br />
> let b = Data.Vector.map (^3) a<br />
<br />
> b ! 2<br />
8<br />
<br />
> slice 2 3 b<br />
fromList [8,27,64]<br />
</haskell><br />
<br />
slice takes 3 arguments: the initial index to slice from, the number of elements to slice, and the vector to operate on. <br />
<br />
A number of special-purpose slices are also available:<br />
<br />
<haskell><br />
> Data.Vector.init b<br />
fromList [0,1,8,27,64,125,216,343,512]<br />
<br />
> Data.Vector.tail b<br />
fromList [1,8,27,64,125,216,343,512,729]<br />
<br />
> Data.Vector.take 3 b<br />
fromList [0,1,8] :: Data.Vector.Vector<br />
<br />
> Data.Vector.drop 3 b<br />
fromList [27,64,125,216,343,512,729] :: Data.Vector.Vector<br />
</haskell><br />
<br />
=== Unsafe Slices ===<br />
<br />
For performance reasons you may wish to avoid bounds checks, when you<br />
can prove that the substring or index will be in bounds. For these cases<br />
there are unsafe operations, that let you skip the bounds check:<br />
<br />
<haskell><br />
> let a = fromList [1..10]<br />
<br />
> unsafeSlice 2 4 a<br />
fromList [3,4,5,6]<br />
<br />
> unsafeInit a<br />
fromList [1,2,3,4,5,6,7,8,9]<br />
<br />
> unsafeTail a<br />
fromList [2,3,4,5,6,7,8,9,10]<br />
</haskell><br />
<br />
and also unsafeTake, unsafeDrop.<br />
<br />
== Examples ==<br />
<br />
=== Sum of Squares ===<br />
<br />
Take the sum of the squares of the elements of a vector:<br />
<br />
<haskell><br />
sumsq :: U.Vector Int -> Int<br />
sumsq v = U.sum (U.map (\x -> x * x) v)<br />
</haskell><br />
<br />
== Stacking together different arrays ==<br />
== Splitting one array into several smaller ones ==<br />
== Copies and Views ==<br />
== No Copy at All ==<br />
== Indexing with Arrays of Indices ==<br />
== Indexing with Boolean Arrays ==<br />
== Permutations ==<br />
== Randoms ==<br />
== IO ==<br />
== References ==</div>Weihuhttps://wiki.haskell.org/index.php?title=Numeric_Haskell:_A_Vector_Tutorial&diff=33747Numeric Haskell: A Vector Tutorial2010-02-21T07:03:58Z<p>Weihu: </p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
[http://hackage.haskell.org/package/vector Vector] is a Haskell library for working with arrays. It has an emphasis on very high performance through loop fusion, whilst retaining a rich interface. The main data types are boxed and unboxed arrays, and arrays may be immutable (pure), or mutable. Arrays may hold Storable elements, suitable for passing to and from C, and you can convert between the array types. Arrays are indexed by non-negative <hask>Int</hask> values.<br />
<br />
The vector library has an API similar to the famous Haskell list library, with many of the same names.<br />
<br />
This tutorial is modelled on [http://www.scipy.org/Tentative_NumPy_Tutorial the NumPy tutorial].<br />
<br />
__TOC__<br />
<br />
= Quick Tour =<br />
<br />
Here is a quick overview to get you started.<br />
<br />
== Importing the library ==<br />
<br />
Download the vector package:<br />
<br />
$ cabal install vector<br />
<br />
and import it as, for boxed arrays:<br />
<br />
<haskell><br />
import qualified Data.Vector as V<br />
</haskell><br />
<br />
or:<br />
<br />
<haskell><br />
import qualified Data.Vector.Unboxed as V<br />
</haskell><br />
<br />
for unboxed arrays. The library needs to be imported qualified as it shares the same function names as list operations in the Prelude.<br />
<br />
== Generating Vectors ==<br />
<br />
New vectors can be generated in many ways:<br />
<br />
<haskell><br />
$ ghci<br />
GHCi, version 6.12.1: 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 />
<br />
Prelude> :m + Data.Vector<br />
<br />
-- Generating a vector from a list:<br />
Prelude Data.Vector> let a = fromList [10, 20, 30, 40]<br />
<br />
Prelude Data.Vector> a<br />
fromList [10,20,30,40] :: Data.Vector.Vector<br />
<br />
-- Or filled from a sequence<br />
Prelude Data.Vector> enumFromStepN 10 10 4<br />
fromList [10,20,30,40] :: Data.Vector.Vector<br />
<br />
-- A vector created from four consecutive values<br />
Prelude Data.Vector> enumFromN 10 4<br />
fromList [10,11,12,13] :: Data.Vector.Vector<br />
</haskell><br />
<br />
You can also build vectors using operations similar to lists:<br />
<br />
<haskell><br />
-- The empty vector<br />
Prelude Data.Vector> empty<br />
fromList [] :: Data.Vector.Vector<br />
<br />
-- A vector of length one<br />
Prelude Data.Vector> singleton 2<br />
fromList [2] :: Data.Vector.Vector<br />
<br />
-- A vector of length 10, filled with the value '2'<br />
-- Note that to disambiguate names,<br />
-- and avoid a clash with the Prelude,<br />
-- with use the full path to the Vector module<br />
Prelude Data.Vector> Data.Vector.replicate 10 2<br />
fromList [2,2,2,2,2,2,2,2,2,2] :: Data.Vector.Vector<br />
</haskell><br />
<br />
In general, you may construct new vectors by applying a function to the index space:<br />
<br />
<haskell><br />
Prelude Data.Vector> generate 10 (^2)<br />
fromList [0,1,4,9,16,25,36,49,64,81] :: Data.Vector.Vector<br />
</haskell><br />
<br />
Vectors may have more than one dimension:<br />
<br />
<haskell><br />
-- Here we create a two dimensional vector, 10 columns,<br />
-- each row filled with the row index.<br />
Prelude Data.Vector> let x = generate 10 (\n -> Data.Vector.replicate 10 n)<br />
<br />
-- The type is "Vector of Vector of Ints"<br />
Prelude Data.Vector> :t x<br />
x :: Vector (Vector Int)<br />
</haskell><br />
<br />
Vectors may be grown or shrunk arbitrarily:<br />
<br />
<haskell><br />
Prelude Data.Vector> let y = Data.Vector.enumFromTo 0 11<br />
Prelude Data.Vector> y<br />
fromList [0,1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
<br />
-- Take the first 3 elements as a new vector<br />
Prelude Data.Vector> Data.Vector.take 3 y<br />
fromList [0,1,2] :: Data.Vector.Vector<br />
<br />
-- Duplicate and join the vector<br />
Prelude Data.Vector> y Data.Vector.++ y<br />
fromList [0,1,2,3,4,5,6,7,8,9,10,11,0,1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Modifying vectors ==<br />
<br />
Just as with lists, you can iterate (map) over arrays, reduce them (fold), filter them, or join them in various ways:<br />
<br />
<haskell><br />
-- mapping a function over the elements of a vector<br />
Prelude Data.Vector> Data.Vector.map (^2) y<br />
fromList [0,1,4,9,16,25,36,49,64,81,100,121] :: Data.Vector.Vector<br />
<br />
-- Extract only the odd elements from a vector<br />
Prelude Data.Vector> Data.Vector.filter odd y<br />
fromList [1,3,5,7,9,11] :: Data.Vector.Vector<br />
<br />
-- Reduce a vector<br />
Prelude Data.Vector> Data.Vector.foldl (+) 0 y<br />
66<br />
<br />
-- Take a scan (partial results from a reduction):<br />
Prelude Data.Vector> Data.Vector.scanl (+) 0 y<br />
fromList [0,0,1,3,6,10,15,21,28,36,45,55,66] :: Data.Vector.Vector<br />
<br />
-- Zip two arrays pairwise, into an array of pairs<br />
Prelude Data.Vector> Data.Vector.zip y y<br />
fromList [(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11)] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Indexing vectors ==<br />
<br />
And like all good arrays, you can index them in various ways:<br />
<br />
<haskell><br />
-- Take the first element<br />
Prelude Data.Vector> Data.Vector.head y<br />
0<br />
<br />
-- Take the last element<br />
Prelude Data.Vector> Data.Vector.tail y<br />
fromList [1,2,3,4,5,6,7,8,9,10,11] :: Data.Vector.Vector<br />
<br />
-- Take an arbitrary element<br />
Prelude Data.Vector> y ! 4<br />
4<br />
</haskell><br />
<br />
= The Tutorial =<br />
<br />
The vector package provides several types of array. The most general interface is via [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector.html Data.Vector], which provides for boxed arrays, holding any type.<br />
<br />
There are also more specialized array types:<br />
<br />
* [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Unboxed.html Unboxed] <br />
* [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Storable.html Storable] <br />
<br />
which provide unboxed arrays (i.e. no closures) and storable arrays (data that is pinned, and may be passed to and from C via a Ptr).<br />
<br />
In all cases, the operations are subject to loop fusion. That is, if you compose two functions, <br />
<br />
map f . map g<br />
<br />
the compiler will rewrite it into a single traversal:<br />
<br />
map (f . g)<br />
<br />
saving time and space.<br />
<br />
== Simple example ==<br />
<br />
You can create the arrays in many ways, for example, from a regular Haskell list:<br />
<br />
<haskell<br />
Prelude Data.Vector> let a = fromList [2,3,4]<br />
<br />
Prelude Data.Vector> a<br />
fromList [2,3,4] :: Data.Vector.Vector<br />
<br />
Prelude Data.Vector> :t a<br />
a :: Vector Integer<br />
</haskell><br />
<br />
GHCi will print the contents of the vector as executable code.<br />
<br />
To create a multidimensional array, you can use a nested list generator to fill it:<br />
<br />
<haskell><br />
Prelude Data.Vector> let x = fromList [ fromList [1 .. x] | x <- [1..10] ]<br />
<br />
Prelude Data.Vector> :t x<br />
x :: Vector (Vector Integer)<br />
</haskell><br />
<br />
-- XXX TODO need a better printing function for multidimensional arrays.<br />
<br />
You can also just create arrays filled with zeroes:<br />
<br />
<haskell><br />
Prelude Data.Vector> Data.Vector.replicate 10 0<br />
fromList [0,0,0,0,0,0,0,0,0,0] :: Data.Vector.Vector<br />
</haskell><br />
<br />
And you can fill arrays from a sequence generator:<br />
<br />
<haskell><br />
Prelude Data.Vector> enumFromN 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10] :: Data.Vector.Vector<br />
<br />
Prelude Data.Vector> enumFromStepN 0 10 10<br />
fromList [0,10,20,30,40,50,60,70,80,90] :: Data.Vector.Vector<br />
</haskell><br />
<br />
== Array Types ==<br />
<br />
The vector package provides several array types, with an identical interface. They have different flexibility with respect to the types of values that may be stored in them, and different performance characteristics.<br />
<br />
In general:<br />
<br />
* End users should use Data.Vector.Unboxed for most cases<br />
* If you need to store more complex structures, use Data.Vector<br />
* If you need to pass to C, use Data.Vector.Storable<br />
<br />
For library writers;<br />
<br />
* Use the generic interface, to ensure your library is maximally flexible: Data.Vector.Generic<br />
<br />
<br />
=== Boxed Arrays: Data.Vector ===<br />
<br />
The most flexible type is [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector.html#t%3AVector Data.Vector.Vector], which provides *boxed* arrays: arrays of pointers to Haskell values.<br />
<br />
* Data.Vector.Vector's are fully polymorphic: they can hold any valid Haskell type<br />
<br />
These arrays are suitable for storing complex Haskell types (sum types, or algebraic data types), but a better choice for simple data types is Data.Vector.Unboxed.<br />
<br />
=== Unboxed Arrays: Data.Vector.Unboxed ===<br />
<br />
Simple, atomic types, and pair types can be stored in a more efficient manner: consecutive memory slots without pointers. The [http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Unboxed.html#t%3AVector Data.Array.Unboxed.Vector] type provides unboxed arrays of types that are members of the Unbox class, including:<br />
<br />
* Bool<br />
* ()<br />
* Char<br />
* Double<br />
* Float<br />
* Int<br />
* Int8, 16, 32, 64<br />
* Word<br />
* Word8, 16, 32, 64<br />
* Complex a's, where 'a' is in Unbox<br />
* Tuple types, where the elements are unboxable<br />
<br />
Unboxed arrays should be preferred when you have unboxable elements, as they are generally more efficient.<br />
<br />
=== Storable Arrays: passing data to C ===<br />
<br />
Storable arrays ([http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector-Storable.html#t%3AVector Data.Vector.Storable.Vector]) are vectors of any type in the Storable class.<br />
<br />
These arrays are pinned, and may be converted to and from pointers, that may be passed to C functions, using a number of functions:<br />
<br />
<haskell><br />
unsafeFromForeignPtr<br />
:: Storable a<br />
=> ForeignPtr a<br />
-> Int<br />
-> Int <br />
-> Vector a <br />
<br />
-- Create a vector from a ForeignPtr with an offset and a length. The data may --- not be modified through the ForeignPtr afterwards.<br />
<br />
unsafeToForeignPtr<br />
:: Storable a<br />
=> Vector a<br />
-> (ForeignPtr a, Int, Int)<br />
<br />
-- Yield the underlying ForeignPtr together with the offset to the data and its -- length. The data may not be modified through the ForeignPtr.<br />
<br />
unsafeWith<br />
:: Storable a<br />
=> Vector a<br />
-> (Ptr a -> IO b)<br />
-> IO b<br />
<br />
-- Pass a pointer to the vector's data to the IO action. The data may not be -- -- modified through the 'Ptr.<br />
</haskell><br />
<br />
=== Pure Arrays ===<br />
=== Impure Arrays ===<br />
<br />
Arrays can be created and operated on in a mutable fashion -- using destructive updates, as in an imperative language. Once all operations are complete, the mutable array can be "frozen" to a pure array, which changes its type.<br />
<br />
Mutable arrays plus freezing are quite useful for initializing arrays from data in the outside world.<br />
<br />
For example, to fill a, generic array, we first<br />
<br />
* allocate an empty vector of size @n@<br />
* destructively update the cells using a generator function<br />
* freeze the array and return it as a pure value.<br />
<br />
<haskell><br />
import qualified System.Random.Mersenne as R<br />
<br />
import qualified Data.Vector.Generic as G<br />
import qualified Data.Vector.Generic.Mutable as GM<br />
<br />
random :: (R.MTRandom a, G.Vector v a) => R.MTGen -> Int -> IO (v a)<br />
random g n = do<br />
v <- GM.new n<br />
fill v 0<br />
G.unsafeFreeze v<br />
where<br />
fill v i<br />
| i < n = do<br />
x <- R.random g<br />
GM.unsafeWrite v i x<br />
fill v (i+1)<br />
| otherwise = return ()<br />
</haskell><br />
<br />
Here we use the Data.Vector.Generic.Mutable.new to allocate a new, uninitialized array, which we then write elements to (using unsafeWrite).<br />
<br />
By using the generic interface, we can construct boxed, storable or unboxed arrays all from the same code.<br />
<br />
=== Some examples ===<br />
<br />
The most important attributes of an array are available in O(1) time, such as the size (length), <br />
<br />
<haskell><br />
-- how big is the array?<br />
Prelude Data.Vector> let a = fromList [1,2,3,4,5,6,7,8,9,10]<br />
Prelude Data.Vector> Data.Vector.length a<br />
10<br />
<br />
-- is the array empty?<br />
Prelude Data.Vector> Data.Vector.null a<br />
False<br />
</haskell><br />
<br />
== Array Creation ==<br />
<br />
=== Enumerations ===<br />
<br />
The most common way to generate a vector is via an enumeration function:<br />
<br />
* enumFromN<br />
* enumFromStepN<br />
<br />
And the list-like:<br />
<br />
* enumFromTo<br />
* enumFromThenTo <br />
<br />
The enumFrom*N functions are guaranteed to optimize well for any type. The enumFromTo functions might fall back to generating from lists if there is no specialization for your type. They are currently specialized to most Int/Word/Double/Float generators.<br />
<br />
<haskell><br />
> enumFromN 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10]<br />
<br />
> enumFromStepN 1 3 4<br />
fromList [1,4,7,10]<br />
<br />
> Data.Vector.enumFromTo 1 10<br />
fromList [1,2,3,4,5,6,7,8,9,10]<br />
<br />
-- counting backwards<br />
> Data.Vector.enumFromThenTo 10 9 1<br />
fromList [10,9,8,7,6,5,4,3,2,1]<br />
</haskell><br />
<br />
==== A note on fusion ====<br />
<br />
As for almost all vector functions, if an enumerator is composed with a traversal or fold, they will fuse into a single loop.<br />
<br />
For example, we can fuse generation of an array of doubles, with computing the product of the square roots. The source program consists of two loops:<br />
<br />
<haskell><br />
import qualified Data.Vector as V<br />
<br />
test :: V.Vector Int -> Double<br />
test = V.foldl (\ a b -> a * sqrt (fromIntegral b)) 0<br />
<br />
create :: Int -> V.Vector Int<br />
create n = (V.enumFromTo 1 n)<br />
<br />
main = print (test (create 1000000))<br />
</haskell><br />
<br />
And after optimization (revealed with the ghc-core tool), we have only one loop:<br />
<br />
<haskell><br />
main_$s$wfoldlM_loop :: Int# -> Double# -> Double#<br />
<br />
main_$s$wfoldlM_loop =<br />
\ (sc_sWA :: Int#) (sc1_sWB :: Double#) -><br />
case <=# sc_sWA 1000000 of _ {<br />
False -> sc1_sWB;<br />
True -><br />
main_$s$wfoldlM_loop<br />
(+# sc_sWA 1)<br />
(*##<br />
sc1_sWB (sqrtDouble# (int2Double# sc_sWA)))<br />
}<br />
</haskell><br />
<br />
Doubling the performance, by halving the number of traversals. Fusion also means we can avoid any intermediate data structure allocation.<br />
<br />
=== An example: filling a vector from a file ===<br />
<br />
We often want to populate a vector using a external data file. The easiest way to do this is with bytestring IO, and Data.Vector.unfoldr (or the equivalent functions in Data.Vector.Unboxed or Data.Vector.Storable:<br />
<br />
==== Parsing Ints ====<br />
<br />
The simplest way to parse a file of Int or Integer types is with a strict or lazy ByteString, and the readInt or readInteger functions:<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.Vector as U<br />
import System.Environment<br />
<br />
main = do<br />
[f] <- getArgs<br />
s <- L.readFile f<br />
print . U.sum . parse $ s<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = U.unfoldr step<br />
where<br />
step !s = case L.readInt s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
Note the use of bang patterns to ensure the parsing accumulated state is produced strictly.<br />
<br />
Create a data file filled with 1 million integers:<br />
<br />
$ seq 1 1000000 > data<br />
<br />
Compile with -Odph (enables special optimizations to help fusion):<br />
<br />
$ ghc -Odph --make vector.hs<br />
<br />
Run:<br />
<br />
$ time ./vector data <br />
500000500000<br />
./vector data 0.08s user 0.01s system 98% cpu 0.088 total<br />
<br />
==== Parsing Floating Point Values ====<br />
<br />
To load a file of floating point values into a vector, you can use bytestrings and the [http://hackage.haskell.org/package/bytestring-lexing bytestring-lexing] package, which provides readDouble and readFloat functions.<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.ByteString.Lex.Lazy.Double as L<br />
import qualified Data.Vector as U<br />
import System.Environment<br />
<br />
main = do<br />
[f] <- getArgs<br />
s <- L.readFile f<br />
print . U.sum . parse $ s<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = U.unfoldr step<br />
where<br />
step !s = case L.readDouble s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
=== Parsing Binary Data ===<br />
<br />
The best way to parse binary data is via bytestrings and the [http://hackage.haskell.org/package/binary Data.Binary] package.<br />
<br />
There are instances of Binary and Serialize available in the [http://hackage.haskell.org/package/vector-binary-instances-0.1 vector-binary-<br />
instances] package.<br />
<br />
An example: parsing a list of integers in text form, serializing them back in binary form, then loading that binary file:<br />
<br />
<haskell><br />
{-# LANGUAGE BangPatterns #-}<br />
<br />
import Data.Vector.Binary<br />
import Data.Binary<br />
import qualified Data.ByteString.Lazy.Char8 as L<br />
import qualified Data.Vector.Unboxed as V<br />
<br />
main = do<br />
s <- L.readFile "dat"<br />
let v = parse s :: V.Vector Int<br />
encodeFile "dat2" v<br />
v' <- decodeFile "dat2" :: IO (V.Vector Int)<br />
print (v == v')<br />
<br />
-- Fill a new vector from a file containing a list of numbers.<br />
parse = V.unfoldr step<br />
where<br />
step !s = case L.readInt s of<br />
Nothing -> Nothing<br />
Just (!k, !t) -> Just (k, L.tail t)<br />
</haskell><br />
<br />
=== Random numbers ===<br />
<br />
If we can parse from a file, we can also fill a vector with random numbers. <br />
We'll use the [http://hackage.haskell.org/package/mersenne-random mersenne-random] package:<br />
<br />
$ cabal install mersenne-random<br />
<br />
We can then use MTRandom class to generate random vectors of different types:<br />
<br />
<haskell><br />
import qualified Data.Vector.Unboxed as U<br />
import System.Random.Mersenne<br />
import Control.Monad<br />
<br />
main = do<br />
-- create a new source of randomness<br />
-- andan infinite list of randoms<br />
g <- newMTGen Nothing<br />
rs <- randoms g<br />
<br />
-- fill a vector with the first 10 random Ints<br />
let a = U.fromList (take 10 rs) :: U.Vector Int<br />
<br />
-- print the sum<br />
print (U.sum a)<br />
<br />
-- print each element<br />
forM_ (U.toList a) print<br />
</haskell><br />
<br />
Running it:<br />
<br />
<haskell><br />
$ runhaskell B.hs<br />
-56426044567146682<br />
-2144043065897064806<br />
-2361203915295681429<br />
1023751035988638668<br />
-5145147152582103336<br />
6545758323081548799<br />
-7630294342751488332<br />
-5861937811333342436<br />
-3198510304070719259<br />
8949914511577398116<br />
-8681457396993884283<br />
</haskell><br />
<br />
We can also just use the vector-random package to generate new vectors initialized with the mersenne twister generator:<br />
<br />
For example, to generate 100 million random Doubles and sum them:<br />
<br />
<haskell><br />
<br />
import qualified Data.Vector.Unboxed as U<br />
import System.Random.Mersenne<br />
import qualified Data.Vector.Random.Mersenne as G<br />
<br />
main = do<br />
g <- newMTGen Nothing<br />
a <- G.random g 10000000 :: IO (U.Vector Double) -- 100 M<br />
print (U.sum a)<br />
</haskell><br />
<br />
== Transformations on Vectors ==<br />
<br />
A primary operation on arrays are the zip class of functions. <br />
<br />
<haskell><br />
> let a = fromList [20,30,40,50]<br />
<br />
> let b = enumFromN 0 4<br />
<br />
> a <br />
fromList [20,30,40,50]<br />
<br />
> b<br />
fromList [0,1,2,3]<br />
<br />
> Data.Vector.zipWith (-) a b<br />
fromList [20,29,38,47]<br />
</haskell><br />
<br />
We can also, of course, apply a function to each element of a vector (map):<br />
<br />
<haskell><br />
> Data.Vector.map (^2) b<br />
fromList [0,1,4,9]<br />
<br />
> Data.Vector.map (\e -> 10 * sin (fromIntegral e)) a<br />
fromList [9.129452507276277,-9.880316240928618,7.451131604793488,-2.6237485370392877]<br />
<br />
> Data.Vector.map (< 35) a<br />
fromList [True,True,False,False]<br />
</haskell><br />
<br />
=== Folds: Sums, Products, Min, Max ===<br />
<br />
Many special purpose folds (reductions) on vectors are available:<br />
<br />
<haskell><br />
> let a = enumFromN 1 100<br />
<br />
> Data.Vector.sum a<br />
5050<br />
<br />
> Data.Vector.product a<br />
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000<br />
<br />
> Data.Vector.minimum a<br />
1<br />
<br />
> Data.Vector.maximum a<br />
100<br />
</haskell><br />
<br />
== Indexing, Slicing and Iterating ==<br />
<br />
One dimensional arrays can be indexed, sliced and iterated over pretty much like lists.<br />
<br />
Because Haskell values are by default immutable, all slice operations are zero-copying.<br />
<br />
<haskell><br />
> let a = enumFromN 0 10<br />
<br />
> a<br />
fromList [0,1,2,3,4,5,6,7,8,9]<br />
<br />
> let b = Data.Vector.map (^3) a<br />
<br />
> b ! 2<br />
8<br />
<br />
> slice 2 3 b<br />
fromList [8,27,64]<br />
</haskell><br />
<br />
slice takes 3 arguments: the initial index to slice from, the number of elements to slice, and the vector to operate on. <br />
<br />
A number of special-purpose slices are also available:<br />
<br />
<haskell><br />
> Data.Vector.init b<br />
fromList [0,1,8,27,64,125,216,343,512]<br />
<br />
> Data.Vector.tail b<br />
fromList [1,8,27,64,125,216,343,512,729]<br />
<br />
> Data.Vector.take 3 b<br />
fromList [0,1,8] :: Data.Vector.Vector<br />
<br />
> Data.Vector.drop 3 b<br />
fromList [27,64,125,216,343,512,729] :: Data.Vector.Vector<br />
</haskell><br />
<br />
=== Unsafe Slices ===<br />
<br />
For performance reasons you may wish to avoid bounds checks, when you<br />
can prove that the substring or index will be in bounds. For these cases<br />
there are unsafe operations, that let you skip the bounds check:<br />
<br />
<haskell><br />
> let a = fromList [1..10]<br />
<br />
> unsafeSlice 2 4 a<br />
fromList [3,4,5,6]<br />
<br />
> unsafeInit a<br />
fromList [1,2,3,4,5,6,7,8,9]<br />
<br />
> unsafeTail a<br />
fromList [2,3,4,5,6,7,8,9,10]<br />
</haskell><br />
<br />
and also unsafeTake, unsafeDrop.<br />
<br />
== Examples ==<br />
<br />
=== Sum of Squares ===<br />
<br />
Take the sum of the squares of the elements of a vector:<br />
<br />
<haskell><br />
sumsq :: U.Vector Int -> Int<br />
sumsq v = U.sum (U.map (\x -> x * x) v)<br />
</haskell><br />
<br />
== Stacking together different arrays ==<br />
== Splitting one array into several smaller ones ==<br />
== Copies and Views ==<br />
== No Copy at All ==<br />
== Indexing with Arrays of Indices ==<br />
== Indexing with Boolean Arrays ==<br />
== Permutations ==<br />
== Randoms ==<br />
== IO ==<br />
== References ==</div>Weihuhttps://wiki.haskell.org/index.php?title=Xmonad/Using_xmonad_on_Apple_OSX&diff=30658Xmonad/Using xmonad on Apple OSX2009-10-08T00:12:34Z<p>Weihu: </p>
<hr />
<div>xmonad runs well under X11 on Apple OSX machines, and needs little work to be<br />
useful. This page collects advice and information on using xmonad<br />
successfully with OSX.<br />
<br />
<gallery><br />
Image:Screen-atomb-apple.png|Apple OSX Tiger<br />
Image:Xmonad-leopard-dmenu.png|Apple OSX Leopard<br />
Image:Xmonad-mac.png|Apple OSX Leopard Fullscreen<br />
Image:Xmonad-mac-expose.png|Expose<br />
</gallery><br />
<br />
If you're using xmonad on a mac, add details about your configuration<br />
here!<br />
<br />
== Installing on OSX Tiger ==<br />
<br />
=== Installing XMonad ===<br />
* ghc: You can get from haskell.org/ghc, MacPorts, or Fink. Fink has an older version of ghc -- one that will work with xmonad (for now?), but will make baby xmonad cry.<br />
* X11 lib: Get from hackage.haskell.org, build using the standard Cabal steps. Make sure that Xinerama gets detected in the configure step. If you see a "present but not compiled" warning, that might be okay (it worked for me).<br />
* xmonad and xmonad-contrib: Get from hackage.haskell.org, build using the standard Cabal steps.<br />
<br />
I installed into my home directory by adding "--user --prefix=$HOME/usr" to the configure steps. The default is /usr/local.<br />
<br />
=== Configuring Your .xinitrc to Run XMonad ===<br />
<ol><br />
<li>Build and install XMonad like you would any other Haskell library.</li><br />
<li>do the following on the Terminal:<br />
<pre><br />
$ cp /private/etc/X11/xinit/xinitrc ~/.xinitrc<br />
$ chmod +w ~/.xinitrc<br />
$ vim ~/.xinitrc <br />
#comment out the line 'exec quartz-wm' and add PATH-TO-XMONAD/xmonad after it.<br />
</pre></li><br />
<li>You may want to add <code>quartz-wm --only-proxy &</code> to your xinitrc, which synchronizes X11/OSX clipboards.</li><br />
<li>Open X11. XMonad should be running now.</li><br />
</ol><br />
<br />
=== Configuring Xmonad for OS X ===<br />
* You probably don't have a numlock key. Set numlockMask to 0. (The default is mod2Mask, which happens to be Apple's default for the command key.)<br />
<br />
* You may use the defaultGaps to make xmonad not clash with the dock. As the dock size is configurable and may vary depending on the number of icons in the dock you will have to measure your dock yourself. Before 0.7 defaultGaps are in xmonad, since 0.7 these should be in xmonad-contrib.<br />
<br />
=== Full screen mode ===<br />
I highly recommend running X11 in full-screen mode. To enable this, open the Preferences dialog for the X11 app, check the checkbox, and restart X11. This way, you don't have to worry about stupid things like the dock / menubar / OS X apps getting in your way.<br />
<br />
=== Does Not Replace Quartz, Silly ===<br />
You won't be able to use xmonad to manage normal OS X apps. X11 will just be another OS X application sitting in your dock that you can switch to. However, it is pretty easy to install a decent set of X11 apps. If you have MacPorts installed you can install the packages firefox-x11, rxvt-unicode, unclutter, and 'vim +gtk2' (the +gtk2 variant for PRIMARY/CLIPBOARD support) to get started.<br />
<br />
=== Fitting Other Bits For Use With xmonad on OS X ===<br />
<br />
==== dmenu ====<br />
dmenu can be built on OS X without problems but it is invisible unless you run X11 in full-screen. Unlike xmonad it does not detect the OS X top menu bar and is completely hidden by it. You can also make it display at the bottom (behind the dock :). <br />
<br />
Since I do not know how to detect the top menubar either I just patched dmenu to add support for gaps. Unfortunately the dmenu authors do not seem very responsive so I attach the patch here.<br />
<br />
[[Media:Dmenu-gap.patch]]<br />
<br />
You can then run <code>dmenu -g 22</code> to work around the OS X top menu.<br />
<br />
=== Potential Configuration Problems ===<br />
You may have problems with configuring XMonad under OSX - if you see the ''"error detected while loading xmonad configuration"'' error message but with no error output, it could be because the PATH inherited by XMonad doesn't include ghc (eg by default it won't include /usr/local/bin).<br />
<br />
Possible solutions:<br />
<br />
# http://forums.macosxhints.com/showthread.php?s=&threadid=12382<br />
# http://forums.macosxhints.com/showthread.php?t=14279<br />
# Or just hardwire the path into xmonad itself - change "ghc" -> "/usr/local/bin/ghc" (or whatever) in Core.hs before building XMonad.<br />
<br />
== Installing on OSX Leopard ==<br />
These instructions have been tested on a blank but fully updated system (04/04/09).<br />
<br />
=== Installing xmonad ===<br />
==== Installing GHC ====<br />
# Install xcode, this can be found on the OSX install disk; it can also be downloaded [http://developer.apple.com/technology/Xcode.html from apple] (you will have to sign upto a free developer account).<br />
# Download and install [http://haskell.org/ghc/ ghc].<br />
<br />
=== Configuring Your .profile ===<br />
Insert the following into your ~/.profile<br />
<pre><br />
export PATH=$PATH:~/.cabal/bin:/usr/local/bin<br />
export USERWM=`which xmonad`<br />
</pre><br />
Much of this isn't needed until later, but it's good to get it out the way now.<br />
<br />
==== Installing Cabal ====<br />
# Download and extract Cabal install from http://www.haskell.org/cabal/download.html<br />
# In a terminal: <pre>$ cd ''Cabal install directory''; ./bootstrap.sh</pre><br />
# Update cabal <pre>$ cabal update</pre><br />
# Install xmonad <pre>$ cabal install xmonad</pre><br />
<br />
=== Install dmenu (optional but recommended) ===<br />
# Download and extract dmenu from http://tools.suckless.org/dmenu<br />
# <pre>$ cd ''dmenu directory''; sudo make install</pre><br />
<br />
=== Updating X11 ===<br />
The version of X11 shipped with Leopard (04/04/09) does not support going fullscreen. I recommend updating X11. It is likely that a Leopard update will eventually make this step unnecessary.<br />
Download and install the latest version from [http://xquartz.macosforge.org/ macosforge].<br />
<br />
=== Configuring Your .xinitrc to Run XMonad ===<br />
write:<br />
<pre><br />
source ~/.profile<br />
exec /usr/X11/lib/X11/xinit/xinitrc<br />
</pre><br />
to ~/.xinitrc<br />
<br />
Alternatively, if this doesn't work (because you haven't updated X11):<br />
write:<br />
<pre><br />
source ~/.profile<br />
exec $USERWM<br />
</pre><br />
to ~/.xinitrc<br />
<br />
=== Configuring Your Keyboard ===<br />
I can't find the meta key (xmonad is unusable without it) in the default configuration. I followed [http://tylerkieft.com/archives/2006/10/05/redefine-the-x11-meta-key-in-mac-os-x/ this guide] (write <pre>clear Mod1<br />
clear Mod2<br />
keycode 63 = Mode_switch<br />
keycode 66 = Meta_L<br />
add Mod1 = Meta_L<br />
add Mod2 = Mode_switch</pre> to ~/.Xmodmap) and now the meta key is the left alt.<br />
<br />
=== Further Configuring ===<br />
* The menu bar shouldn't get in the way (fullscreen or otherwise, updated or standard X11). The Dock however will, I recommend hiding the Dock or always working in fullscreen mode.<br />
* You can start X11 (and Xmonad) by running any program that uses X, or by running X11.app. If you run X11.app a default program is started. You can configure this program by running <pre> $ defaults write org.x.X11 "app_to_run" "gnome-terminal" </pre> (replace gnome-terminal with a program of your choice). or <pre>$ defaults write org.x.X11 "app_to_run" ""</pre> to have no application run by default.<br />
* There shouldn't be anything unusual about configuring [http://www.xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Doc-Configuring.html ~/.xmonad/xmonad.hs].<br />
<br />
=== Discussion ===<br />
* XMonad and Vimperator (Firefox 3 extension) make a powerful combination on Linux. I cannot achieve this on OSX because the newest X11 version of Firefox I can install is version 2. If anyone has any hints on installing Firefox 3 X11 please share them.<br />
* XMonad only works with X11 software- a package manager such as Port is helpful http://www.macports.org/ .<br />
<br />
<br />
[[Category:XMonad]]</div>Weihuhttps://wiki.haskell.org/index.php?title=Talk:OpenGLTutorial1&diff=29664Talk:OpenGLTutorial12009-08-20T07:08:21Z<p>Weihu: </p>
<hr />
<div>The program didn't display anything for me.<br />
I changed the line "<hask>clear [ColorBuffer]</hask>" in the ''display'' function to <hask>"clear [ColorBuffer, DepthBuffer]"</hask>, and it worked.</div>Weihuhttps://wiki.haskell.org/index.php?title=GADTs_for_dummies&diff=26137GADTs for dummies2009-01-27T14:29:30Z<p>Weihu: </p>
<hr />
<div>For a long time, I didn't understand what GADTs are and how they can be used. It was a sort of conspiracy of silence - people who understand GADTs think<br />
it is all obvious, and don't need any explanation, but I still<br />
couldn't understand.<br />
<br />
Now I have an idea how it works, and think that it was really obvious :) and I want to share my understanding - may be my way to realize GADTs can help<br />
someone else. So:<br />
<br />
== Type functions ==<br />
<br />
A "data" declaration is a way to declare both type constructor and data<br />
constructors. For example,<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
declares type constructor "Either" and two data constructors "Left"<br />
and "Right". Ordinary Haskell functions works with data constructors:<br />
<br />
<haskell><br />
isLeft (Left a) = True<br />
isLeft (Right b) = False<br />
</haskell><br />
<br />
but there is also an analogous way to work with type constructors!<br />
<br />
<haskell><br />
type X a = Either a a<br />
</haskell><br />
<br />
declares a TYPE FUNCTION named "X". Its parameter "a" must be some type<br />
and it returns some type as its result. We can't use "X" on data values,<br />
but we can use it on type values. Type constructors declared with<br />
"data" statements and type functions declared with "type" statements<br />
used together to build arbitrarily complex types. In such<br />
"computations" type constructors serves as basic "values" and type<br />
functions as a way to process them.<br />
<br />
Indeed, type functions in Haskell are very limited compared to<br />
ordinary functions - they don't support pattern matching,<br />
nor multiple statements, nor recursion.<br />
<br />
== Hypothetical Haskell extension - Full-featured type functions ==<br />
<br />
Let's build hypothetical Haskell extension, that mimics for type<br />
functions the well-known ways to define ordinary functions, including<br />
pattern matching:<br />
<br />
<haskell><br />
type F [a] = Set a<br />
</haskell><br />
<br />
multiple statements (this is meaningful only in presence of pattern matching):<br />
<br />
<haskell><br />
type F Bool = Char<br />
F String = Int<br />
</haskell><br />
<br />
and recursion (which again needs pattern matching and multiple statements):<br />
<br />
<haskell><br />
type F [a] = F a<br />
F (Map a b) = F b<br />
F (Set a) = F a<br />
F a = a<br />
</haskell><br />
<br />
As you may already have guessed, this last definition calculates a simple base type of arbitrarily-nested collections, e.g: <br />
<br />
<haskell><br />
F [[[Set Int]]] = <br />
F [[Set Int]] =<br />
F [Set Int] = <br />
F (Set Int) =<br />
F Int =<br />
Int<br />
</haskell><br />
<br />
Let's don't forget about statement guards:<br />
<br />
<haskell><br />
type F a | IsSimple a == TrueType = a<br />
</haskell><br />
<br />
Here we define type function F only for simple datatypes by using in<br />
guard type function "IsSimple":<br />
<br />
<haskell><br />
type IsSimple Bool = TrueType<br />
IsSimple Int = TrueType<br />
....<br />
IsSimple Double = TrueType<br />
IsSimple a = FalseType<br />
<br />
data TrueType = T<br />
data FalseType = F<br />
</haskell><br />
<br />
These definitions seem a bit odd, and while we are in imaginary land,<br />
let's consider a way to write this shorter:<br />
<br />
<haskell><br />
type F a | IsSimple a = a<br />
<br />
type IsSimple Bool<br />
IsSimple Int<br />
....<br />
IsSimple Double<br />
</haskell><br />
<br />
Here, we just defined list of simple types, the implied result of all<br />
written statements for "IsSimple" is True value, and False value for<br />
anything else. Essentially, "IsSimple" is no less than TYPE PREDICATE!<br />
<br />
I really love it! :) How about constructing a predicate that traverses a<br />
complex type trying to decide whether it contains "Int" anywhere?<br />
<br />
<haskell><br />
type HasInt Int<br />
HasInt [a] = HasInt a<br />
HasInt (Set a) = HasInt a<br />
HasInt (Map a b) | HasInt a<br />
HasInt (Map a b) | HasInt b<br />
</haskell><br />
<br />
or a type function that substitutes one type with another inside<br />
arbitrary-deep types:<br />
<br />
<haskell><br />
type Replace t a b | t==a = b<br />
Replace [t] a b = [Replace t a b]<br />
Replace (Set t) a b = Set (Replace t a b)<br />
Replace (Map t1 t2) a b = Map (Replace t1 a b) (Replace t2 a b)<br />
Replace t a b = t<br />
</haskell><br />
<br />
== One more hypothetical extension - multi-value type functions ==<br />
<br />
Let's add more fun! We will introduce one more hypothetical Haskell<br />
extension - type functions that may have MULTIPLE VALUES. Say,<br />
<br />
<haskell><br />
type Collection a = [a]<br />
Collection a = Set a<br />
Collection a = Map b a<br />
</haskell><br />
<br />
So, "Collection Int" has "[Int]", "Set Int" and "Map String Int" as<br />
its values, i.e. different collection types with elements of type<br />
"Int".<br />
<br />
Pay attention to the last statement of the "Collection" definition, where<br />
we've used type variable "b" that was not mentioned on the left side<br />
nor defined in any other way. It's perfectly possible - anyway<br />
"Collection" function has multiple values, so using on the right side<br />
some free variable that can be replaced with any type is not a problem<br />
at all - the "Map Bool Int", "Map [Int] Int" and "Map Int Int" all are<br />
possible values of "Collection Int" along with "[Int]" and "Set Int".<br />
<br />
On the first look, it seems that multiple-value functions are<br />
meaningless - they can't be used to define datatypes, because we need<br />
concrete types here. But on the second look :) we can find them<br />
useful to define type constraints and type families.<br />
<br />
We can also represent multiple-value function as predicate:<br />
<br />
<haskell><br />
type Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
If you remember Prolog, you should guess that predicate, in contrast to<br />
function, is multi-purpose thing - it can be used to deduce any<br />
parameter from other ones. For example, in this hypothetical definition:<br />
<br />
<haskell><br />
head | Collection Int a :: a -> Int<br />
</haskell><br />
<br />
we define 'head' function for any Collection containing Ints.<br />
<br />
And in this, again, hypothetical definition:<br />
<br />
<haskell><br />
data Safe c | Collection c a = Safe c a<br />
</haskell><br />
<br />
we deduced element type 'a' from collection type 'c' passed as the<br />
parameter to the type constructor.<br />
<br />
<br />
<br />
== Back to real Haskell - type classes ==<br />
<br />
Reading all those glorious examples you may be wondering - why Haskell<br />
don't yet supports full-featured type functions? Hold your breath...<br />
Haskell already contains them and at least GHC implements all the<br />
mentioned abilities more than 10 years ago! They just was named...<br />
TYPE CLASSES! Let's translate all our examples to their language:<br />
<br />
<haskell><br />
class IsSimple a<br />
instance IsSimple Bool<br />
instance IsSimple Int<br />
....<br />
instance IsSimple Double<br />
</haskell><br />
<br />
Haskell'98 standard supports type classes with only one parameter that<br />
limits us to defining only type predicates like this one. But GHC and<br />
Hugs supports multi-parameter type classes that allows us to define<br />
arbitrarily-complex type functions<br />
<br />
<haskell><br />
class Collection a c<br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
instance Collection a (Map b a)<br />
</haskell><br />
<br />
All the "hypothetical" Haskell extensions we investigated earlier -<br />
actually implemented at the type class level!<br />
<br />
Pattern matching:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
</haskell><br />
<br />
Multiple statements:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
</haskell><br />
<br />
Recursion:<br />
<br />
<haskell><br />
instance (Collection a c) => Collection a [c]<br />
</haskell><br />
<br />
Pattern guards:<br />
<br />
<haskell><br />
instance (IsSimple a) => Collection a (UArray a)<br />
</haskell><br />
<br />
<br />
<br />
Let's define type class which contains any collection which uses Int as<br />
its elements or indexes:<br />
<br />
<haskell><br />
class HasInt a<br />
instance HasInt Int<br />
instance (HasInt a) => HasInt [a]<br />
instance (HasInt a) => HasInt (Map a b)<br />
instance (HasInt b) => HasInt (Map a b)<br />
</haskell><br />
<br />
<br />
Anther example is a class that replaces all occurrences of 'a' with<br />
'b' in type 't' and return result as 'res':<br />
<br />
<haskell><br />
class Replace t a b res<br />
instance Replace t a a t<br />
instance Replace [t] a b [Replace t a b]<br />
instance (Replace t a b res)<br />
=> Replace (Set t) a b (Set res)<br />
instance (Replace t1 a b res1, Replace t2 a b res2)<br />
=> Replace (Map t1 t2) a b (Map res1 res2)<br />
instance Replace t a b t<br />
</haskell><br />
<br />
You can compare it to the hypothetical definition we gave earlier.<br />
It's important to note that type class instances, as opposite to<br />
function statements, are not checked in order. Instead, most<br />
_specific_ instance automatically selected. So, in Replace case, the<br />
last instance that is most general will be selected only if all other<br />
are failed to match and that is that we want.<br />
<br />
In many other cases this automatic selection is not powerful enough<br />
and we are forced to use some artificial tricks or complain to the<br />
language developers. The two most well-known language extensions<br />
proposed to solve such problems are instance priorities, which allow<br />
to explicitly specify instance selection order, and '/=' constraints,<br />
which can be used to explicitly prohibit unwanted matches:<br />
<br />
<haskell><br />
instance Replace t a a t<br />
instance (a/=b) => Replace [t] a b [Replace t a b]<br />
instance (a/=b, t/=[_]) => Replace t a b t<br />
</haskell><br />
<br />
You can check that these instances are no more overlaps.<br />
<br />
<br />
At practice, type-level arithmetics by itself is not very useful. It<br />
becomes really strong weapon when combined with another feature that<br />
type classes provide - member functions. For example:<br />
<br />
<haskell><br />
class Collection a c where<br />
foldr1 :: (a -> a -> a) -> c -> a<br />
<br />
class Num a where<br />
(+) :: a -> a -> a<br />
<br />
sum :: (Num a, Collection a c) => c -> a<br />
sum = foldr1 (+)<br />
</haskell><br />
<br />
<br />
I'll be also glad to see possibility to use type classes in data<br />
declarations like this:<br />
<br />
<haskell><br />
data Safe c = (Collection c a) => Safe c a<br />
</haskell><br />
<br />
but afaik this is also not yet implemented<br />
<br />
<br />
UNIFICATION<br />
...<br />
<br />
<br />
<br />
== Back to GADTs ==<br />
<br />
If you are wonder how relates all these interesting type manipulations<br />
to GADTs, now is the time to give you answer. As you know, Haskell<br />
contains highly developed ways to express data-to-data functions. Now<br />
we also know that Haskell contains rich facilities to write<br />
type-to-type functions in form of "type" statements and type classes.<br />
But how "data" statements fits in this infrastructure?<br />
<br />
My answer: they just defines type-to-data constructors translation.<br />
Moreover, this translation may give multiple results. Say, the<br />
following definition:<br />
<br />
<haskell><br />
data Maybe a = Just a | Nothing<br />
</haskell><br />
<br />
defines type-to-data constructors function "Maybe" that has parameter<br />
"a" and for each "a" has two possible results - "Just a" and<br />
"Nothing". We can rewrite it in the same hypothetical syntax that was<br />
used above for multi-value type functions:<br />
<br />
<haskell><br />
data Maybe a = Just a<br />
Maybe a = Nothing<br />
</haskell><br />
<br />
Or how about this:<br />
<br />
<haskell><br />
data List a = Cons a (List a)<br />
List a = Nil<br />
</haskell><br />
<br />
and this:<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
But how are flexible "data" definitions? As you should remember,<br />
"type" definitions was very limited in their features, while type<br />
classes, vice versa, much more developed than ordinary Haskell<br />
functions facilities. What about features of "data" definitions<br />
examined as sort of functions?<br />
<br />
On the one side, they supports multiple statements and multiple<br />
results and can be recursive, like the "List" definition above. On the<br />
other side, that's all - no pattern matching or even type constants on<br />
the left side and no guards.<br />
<br />
Lack of pattern matching means that left side can contain only free<br />
type variables, that in turn means that left sides of all "data"<br />
statements for one type will be essentially the same. Therefore,<br />
repeated left sides in multi-statement "data" definitions are omitted<br />
and instead of<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
we write just<br />
<br />
<haskell><br />
data Either a b = Left a<br />
| Right b<br />
</haskell><br />
<br />
<br />
And here finally comes the GADTs! It's just a way to define data types<br />
using pattern matching and constants on the left side of "data"<br />
statements! How about this:<br />
<br />
<haskell><br />
data T String = D1 Int<br />
T Bool = D2<br />
T [a] = D3 (a,a)<br />
</haskell><br />
<br />
Amazed? After all, GADTs seems really very simple and obvious<br />
extension to data type definition facilities.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The idea is to allow a data constructor's return type to<br />
be specified directly:<br />
<br />
<haskell><br />
data Term a where<br />
Lit :: Int -> Term Int<br />
Pair :: Term a -> Term b -> Term (a,b)<br />
...<br />
</haskell><br />
<br />
In a function that performs pattern matching on Term, the pattern<br />
match gives type as well as value information. For example,<br />
consider this function:<br />
<br />
<haskell><br />
eval :: Term a -> a<br />
eval (Lit i) = i<br />
eval (Pair a b) = (eval a, eval b)<br />
...<br />
</haskell><br />
<br />
If the argument matches Lit, it must have been built with a<br />
Lit constructor, so type 'a' must be Int, and hence we can return 'i'<br />
(an Int) in the right hand side. The same objections applies to the Pair<br />
constructor.<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Further reading ==<br />
<br />
The best paper on type level arithmetic using type classes i've seen<br />
is "Faking it: simulating dependent types in Haskell"<br />
( http://www.cs.nott.ac.uk/~ctm/faking.ps.gz ). Most part of my<br />
article is just duplicates his work.<br />
<br />
The great demonstration of type-level arithmetic is TypeNats package<br />
which "defines type-level natural numbers and arithmetic operations on<br />
them including addition, subtraction, multiplication, division and GCD"<br />
( darcs get --partial --tag '0.1' http://www.eecs.tufts.edu/~rdocki01/typenats/ )<br />
<br />
I should also mention here Oleg Kiselyov page on type-level<br />
programming in Haskell: http://okmij.org/ftp/Haskell/types.html<br />
<br />
<br />
There are plenty of GADT-related papers, but best for beginners<br />
remains the "Fun with phantom types"<br />
(http://www.informatik.uni-bonn.de/~ralf/publications/With.pdf).<br />
Phantom types is another name of GADT. You should also know that this<br />
paper uses old GADT syntax. This paper is must-read because it<br />
contains numerous examples of practical GADT usage - theme completely<br />
omitted from my article.<br />
<br />
<br />
Other GADT-related papers i know:<br />
<br />
"Dynamic Optimization for Functional Reactive Programming using<br />
Generalized Algebraic Data Types"<br />
http://www.cs.nott.ac.uk/~nhn/Publications/icfp2005.pdf<br />
<br />
"Phantom types" (actually more scientific version of "Fun with phantom types")<br />
http://citeseer.ist.psu.edu/rd/0,606209,1,0.25,Download/http:qSqqSqwww.informatik.uni-bonn.deqSq~ralfqSqpublicationsqSqPhantom.ps.gz<br />
<br />
"Phantom types and subtyping" http://arxiv.org/ps/cs.PL/0403034<br />
<br />
"Existentially quantified type classes" by Stuckey, Sulzmann and Wazny (URL?)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Random rubbish from previous versions of article ==<br />
<br />
<br />
<haskell><br />
data family Map k :: * -> *<br />
<br />
data instance Map () v = MapUnit (Maybe v)<br />
data instance Map (a, b) v = MapPair (Map a (Map b v))<br />
</haskell><br />
<br />
<br />
<br />
<br />
<br />
<br />
let's consider well-known 'data' declarations:<br />
<br />
<haskell><br />
data T a = D a a Int<br />
</haskell><br />
<br />
it can be seen as function 'T' from type 'a' to some data constructor.<br />
<br />
'T Bool', for example, gives result 'D Bool Bool Int', while<br />
<br />
'T [Int]' gives result 'D [Int] [Int] Int'.<br />
<br />
'data' declaration can also have several "results", say<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
and "result" of 'Either Int String' can be either "Left Int" or "Right<br />
String"<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Well, to give compiler confidence<br />
that 'a' can be deduced in just one way from 'c', we can add some<br />
form of hint:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
The first line i added tell the compiler that Collection predicate has<br />
two parameters and the second parameter determines the first. Based on<br />
this restriction, compiler can detect and prohibit attempts to define<br />
different element types for the same collection:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a (Map b a)<br />
Collection b (Map b a) -- error! prohibits functional dependency<br />
</haskell><br />
<br />
Of course, Collection is just a function from 'c' to 'a', but if we<br />
will define it directly as a function:<br />
<br />
<haskell><br />
type Collection [a] = a<br />
Collection (Set a) = a<br />
Collection (Map b a) = a<br />
</haskell><br />
<br />
- it can't be used in 'head' definition above. Moreover, using<br />
functional dependencies we can define bi-directional functions:<br />
<br />
<haskell><br />
type TwoTimesBigger :: a b | a->b, b->a<br />
TwoTimesBigger Int8 Int16<br />
TwoTimesBigger Int16 Int32<br />
TwoTimesBigger Int32 Int64<br />
</haskell><br />
<br />
or predicates with 3, 4 or more parameters with any relations between<br />
them. It's a great power!</div>Weihuhttps://wiki.haskell.org/index.php?title=GADTs_for_dummies&diff=26130GADTs for dummies2009-01-26T20:26:42Z<p>Weihu: </p>
<hr />
<div>For a long time, I didn't understandd what GADTs are and how they can be used. It was a sort of conspiracy of silence - people who understand GADTs think<br />
it is all obvious, and don't need any explanation, but I still<br />
couldn't understand.<br />
<br />
Now I have an idea how it works, and think that it was really obvious :) and I want to share my understanding - may be my way to realize GADTs can help<br />
someone else. So:<br />
<br />
== Type functions ==<br />
<br />
A "data" declaration is a way to declare both type constructor and data<br />
constructors. For example,<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
declares type constructor "Either" and two data constructors "Left"<br />
and "Right". Ordinary Haskell functions works with data constructors:<br />
<br />
<haskell><br />
isLeft (Left a) = True<br />
isLeft (Right b) = False<br />
</haskell><br />
<br />
but there is also an analogous way to work with type constructors!<br />
<br />
<haskell><br />
type X a = Either a a<br />
</haskell><br />
<br />
declares a TYPE FUNCTION named "X". Its parameter "a" must be some type<br />
and it returns some type as its result. We can't use "X" on data values,<br />
but we can use it on type values. Type constructors declared with<br />
"data" statements and type functions declared with "type" statements<br />
used together to build arbitrarily complex types. In such<br />
"computations" type constructors serves as basic "values" and type<br />
functions as a way to process them.<br />
<br />
Indeed, type functions in Haskell are very limited compared to<br />
ordinary functions - they don't support pattern matching,<br />
nor multiple statements, nor recursion.<br />
<br />
== Hypothetical Haskell extension - Full-featured type functions ==<br />
<br />
Let's build hypothetical Haskell extension, that mimics for type<br />
functions the well-known ways to define ordinary functions, including<br />
pattern matching:<br />
<br />
<haskell><br />
type F [a] = Set a<br />
</haskell><br />
<br />
multiple statements (this is meaningful only in presence of pattern matching):<br />
<br />
<haskell><br />
type F Bool = Char<br />
F String = Int<br />
</haskell><br />
<br />
and recursion (which again needs pattern matching and multiple statements):<br />
<br />
<haskell><br />
type F [a] = F a<br />
F (Map a b) = F b<br />
F (Set a) = F a<br />
F a = a<br />
</haskell><br />
<br />
As you may already have guessed, this last definition calculates a simple base type of arbitrarily-nested collections, e.g: <br />
<br />
<haskell><br />
F [[[Set Int]]] = <br />
F [[Set Int]] =<br />
F [Set Int] = <br />
F (Set Int) =<br />
F Int =<br />
Int<br />
</haskell><br />
<br />
Let's don't forget about statement guards:<br />
<br />
<haskell><br />
type F a | IsSimple a == TrueType = a<br />
</haskell><br />
<br />
Here we define type function F only for simple datatypes by using in<br />
guard type function "IsSimple":<br />
<br />
<haskell><br />
type IsSimple Bool = TrueType<br />
IsSimple Int = TrueType<br />
....<br />
IsSimple Double = TrueType<br />
IsSimple a = FalseType<br />
<br />
data TrueType = T<br />
data FalseType = F<br />
</haskell><br />
<br />
These definitions seem a bit odd, and while we are in imaginary land,<br />
let's consider a way to write this shorter:<br />
<br />
<haskell><br />
type F a | IsSimple a = a<br />
<br />
type IsSimple Bool<br />
IsSimple Int<br />
....<br />
IsSimple Double<br />
</haskell><br />
<br />
Here, we just defined list of simple types, the implied result of all<br />
written statements for "IsSimple" is True value, and False value for<br />
anything else. Essentially, "IsSimple" is no less than TYPE PREDICATE!<br />
<br />
I really love it! :) How about constructing a predicate that traverses a<br />
complex type trying to decide whether it contains "Int" anywhere?<br />
<br />
<haskell><br />
type HasInt Int<br />
HasInt [a] = HasInt a<br />
HasInt (Set a) = HasInt a<br />
HasInt (Map a b) | HasInt a<br />
HasInt (Map a b) | HasInt b<br />
</haskell><br />
<br />
or a type function that substitutes one type with another inside<br />
arbitrary-deep types:<br />
<br />
<haskell><br />
type Replace t a b | t==a = b<br />
Replace [t] a b = [Replace t a b]<br />
Replace (Set t) a b = Set (Replace t a b)<br />
Replace (Map t1 t2) a b = Map (Replace t1 a b) (Replace t2 a b)<br />
Replace t a b = t<br />
</haskell><br />
<br />
== One more hypothetical extension - multi-value type functions ==<br />
<br />
Let's add more fun! We will introduce one more hypothetical Haskell<br />
extension - type functions that may have MULTIPLE VALUES. Say,<br />
<br />
<haskell><br />
type Collection a = [a]<br />
Collection a = Set a<br />
Collection a = Map b a<br />
</haskell><br />
<br />
So, "Collection Int" has "[Int]", "Set Int" and "Map String Int" as<br />
its values, i.e. different collection types with elements of type<br />
"Int".<br />
<br />
Pay attention to the last statement of the "Collection" definition, where<br />
we've used type variable "b" that was not mentioned on the left side<br />
nor defined in any other way. It's perfectly possible - anyway<br />
"Collection" function has multiple values, so using on the right side<br />
some free variable that can be replaced with any type is not a problem<br />
at all - the "Map Bool Int", "Map [Int] Int" and "Map Int Int" all are<br />
possible values of "Collection Int" along with "[Int]" and "Set Int".<br />
<br />
On the first look, it seems that multiple-value functions are<br />
meaningless - they can't be used to define datatypes, because we need<br />
concrete types here. But on the second look :) we can find them<br />
useful to define type constraints and type families.<br />
<br />
We can also represent multiple-value function as predicate:<br />
<br />
<haskell><br />
type Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
If you remember Prolog, you should guess that predicate, in contrast to<br />
function, is multi-purpose thing - it can be used to deduce any<br />
parameter from other ones. For example, in this hypothetical definition:<br />
<br />
<haskell><br />
head | Collection Int a :: a -> Int<br />
</haskell><br />
<br />
we define 'head' function for any Collection containing Ints.<br />
<br />
And in this, again, hypothetical definition:<br />
<br />
<haskell><br />
data Safe c | Collection c a = Safe c a<br />
</haskell><br />
<br />
we deduced element type 'a' from collection type 'c' passed as the<br />
parameter to the type constructor.<br />
<br />
<br />
<br />
== Back to real Haskell - type classes ==<br />
<br />
Reading all those glorious examples you may be wondering - why Haskell<br />
don't yet supports full-featured type functions? Hold your breath...<br />
Haskell already contains them and at least GHC implements all the<br />
mentioned abilities more than 10 years ago! They just was named...<br />
TYPE CLASSES! Let's translate all our examples to their language:<br />
<br />
<haskell><br />
class IsSimple a<br />
instance IsSimple Bool<br />
instance IsSimple Int<br />
....<br />
instance IsSimple Double<br />
</haskell><br />
<br />
Haskell'98 standard supports type classes with only one parameter that<br />
limits us to defining only type predicates like this one. But GHC and<br />
Hugs supports multi-parameter type classes that allows us to define<br />
arbitrarily-complex type functions<br />
<br />
<haskell><br />
class Collection a c<br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
instance Collection a (Map b a)<br />
</haskell><br />
<br />
All the "hypothetical" Haskell extensions we investigated earlier -<br />
actually implemented at the type class level!<br />
<br />
Pattern matching:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
</haskell><br />
<br />
Multiple statements:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
</haskell><br />
<br />
Recursion:<br />
<br />
<haskell><br />
instance (Collection a c) => Collection a [c]<br />
</haskell><br />
<br />
Pattern guards:<br />
<br />
<haskell><br />
instance (IsSimple a) => Collection a (UArray a)<br />
</haskell><br />
<br />
<br />
<br />
Let's define type class which contains any collection which uses Int as<br />
its elements or indexes:<br />
<br />
<haskell><br />
class HasInt a<br />
instance HasInt Int<br />
instance (HasInt a) => HasInt [a]<br />
instance (HasInt a) => HasInt (Map a b)<br />
instance (HasInt b) => HasInt (Map a b)<br />
</haskell><br />
<br />
<br />
Anther example is a class that replaces all occurrences of 'a' with<br />
'b' in type 't' and return result as 'res':<br />
<br />
<haskell><br />
class Replace t a b res<br />
instance Replace t a a t<br />
instance Replace [t] a b [Replace t a b]<br />
instance (Replace t a b res)<br />
=> Replace (Set t) a b (Set res)<br />
instance (Replace t1 a b res1, Replace t2 a b res2)<br />
=> Replace (Map t1 t2) a b (Map res1 res2)<br />
instance Replace t a b t<br />
</haskell><br />
<br />
You can compare it to the hypothetical definition we gave earlier.<br />
It's important to note that type class instances, as opposite to<br />
function statements, are not checked in order. Instead, most<br />
_specific_ instance automatically selected. So, in Replace case, the<br />
last instance that is most general will be selected only if all other<br />
are failed to match and that is that we want.<br />
<br />
In many other cases this automatic selection is not powerful enough<br />
and we are forced to use some artificial tricks or complain to the<br />
language developers. The two most well-known language extensions<br />
proposed to solve such problems are instance priorities, which allow<br />
to explicitly specify instance selection order, and '/=' constraints,<br />
which can be used to explicitly prohibit unwanted matches:<br />
<br />
<haskell><br />
instance Replace t a a t<br />
instance (a/=b) => Replace [t] a b [Replace t a b]<br />
instance (a/=b, t/=[_]) => Replace t a b t<br />
</haskell><br />
<br />
You can check that these instances are no more overlaps.<br />
<br />
<br />
At practice, type-level arithmetics by itself is not very useful. It<br />
becomes really strong weapon when combined with another feature that<br />
type classes provide - member functions. For example:<br />
<br />
<haskell><br />
class Collection a c where<br />
foldr1 :: (a -> a -> a) -> c -> a<br />
<br />
class Num a where<br />
(+) :: a -> a -> a<br />
<br />
sum :: (Num a, Collection a c) => c -> a<br />
sum = foldr1 (+)<br />
</haskell><br />
<br />
<br />
I'll be also glad to see possibility to use type classes in data<br />
declarations like this:<br />
<br />
<haskell><br />
data Safe c = (Collection c a) => Safe c a<br />
</haskell><br />
<br />
but afaik this is also not yet implemented<br />
<br />
<br />
UNIFICATION<br />
...<br />
<br />
<br />
<br />
== Back to GADTs ==<br />
<br />
If you are wonder how relates all these interesting type manipulations<br />
to GADTs, now is the time to give you answer. As you know, Haskell<br />
contains highly developed ways to express data-to-data functions. Now<br />
we also know that Haskell contains rich facilities to write<br />
type-to-type functions in form of "type" statements and type classes.<br />
But how "data" statements fits in this infrastructure?<br />
<br />
My answer: they just defines type-to-data constructors translation.<br />
Moreover, this translation may give multiple results. Say, the<br />
following definition:<br />
<br />
<haskell><br />
data Maybe a = Just a | Nothing<br />
</haskell><br />
<br />
defines type-to-data constructors function "Maybe" that has parameter<br />
"a" and for each "a" has two possible results - "Just a" and<br />
"Nothing". We can rewrite it in the same hypothetical syntax that was<br />
used above for multi-value type functions:<br />
<br />
<haskell><br />
data Maybe a = Just a<br />
Maybe a = Nothing<br />
</haskell><br />
<br />
Or how about this:<br />
<br />
<haskell><br />
data List a = Cons a (List a)<br />
List a = Nil<br />
</haskell><br />
<br />
and this:<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
But how are flexible "data" definitions? As you should remember,<br />
"type" definitions was very limited in their features, while type<br />
classes, vice versa, much more developed than ordinary Haskell<br />
functions facilities. What about features of "data" definitions<br />
examined as sort of functions?<br />
<br />
On the one side, they supports multiple statements and multiple<br />
results and can be recursive, like the "List" definition above. On the<br />
other side, that's all - no pattern matching or even type constants on<br />
the left side and no guards.<br />
<br />
Lack of pattern matching means that left side can contain only free<br />
type variables, that in turn means that left sides of all "data"<br />
statements for one type will be essentially the same. Therefore,<br />
repeated left sides in multi-statement "data" definitions are omitted<br />
and instead of<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
we write just<br />
<br />
<haskell><br />
data Either a b = Left a<br />
| Right b<br />
</haskell><br />
<br />
<br />
And here finally comes the GADTs! It's just a way to define data types<br />
using pattern matching and constants on the left side of "data"<br />
statements! How about this:<br />
<br />
<haskell><br />
data T String = D1 Int<br />
T Bool = D2<br />
T [a] = D3 (a,a)<br />
</haskell><br />
<br />
Amazed? After all, GADTs seems really very simple and obvious<br />
extension to data type definition facilities.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The idea is to allow a data constructor's return type to<br />
be specified directly:<br />
<br />
<haskell><br />
data Term a where<br />
Lit :: Int -> Term Int<br />
Pair :: Term a -> Term b -> Term (a,b)<br />
...<br />
</haskell><br />
<br />
In a function that performs pattern matching on Term, the pattern<br />
match gives type as well as value information. For example,<br />
consider this function:<br />
<br />
<haskell><br />
eval :: Term a -> a<br />
eval (Lit i) = i<br />
eval (Pair a b) = (eval a, eval b)<br />
...<br />
</haskell><br />
<br />
If the argument matches Lit, it must have been built with a<br />
Lit constructor, so type 'a' must be Int, and hence we can return 'i'<br />
(an Int) in the right hand side. The same objections applies to the Pair<br />
constructor.<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Further reading ==<br />
<br />
The best paper on type level arithmetic using type classes i've seen<br />
is "Faking it: simulating dependent types in Haskell"<br />
( http://www.cs.nott.ac.uk/~ctm/faking.ps.gz ). Most part of my<br />
article is just duplicates his work.<br />
<br />
The great demonstration of type-level arithmetic is TypeNats package<br />
which "defines type-level natural numbers and arithmetic operations on<br />
them including addition, subtraction, multiplication, division and GCD"<br />
( darcs get --partial --tag '0.1' http://www.eecs.tufts.edu/~rdocki01/typenats/ )<br />
<br />
I should also mention here Oleg Kiselyov page on type-level<br />
programming in Haskell: http://okmij.org/ftp/Haskell/types.html<br />
<br />
<br />
There are plenty of GADT-related papers, but best for beginners<br />
remains the "Fun with phantom types"<br />
(http://www.informatik.uni-bonn.de/~ralf/publications/With.pdf).<br />
Phantom types is another name of GADT. You should also know that this<br />
paper uses old GADT syntax. This paper is must-read because it<br />
contains numerous examples of practical GADT usage - theme completely<br />
omitted from my article.<br />
<br />
<br />
Other GADT-related papers i know:<br />
<br />
"Dynamic Optimization for Functional Reactive Programming using<br />
Generalized Algebraic Data Types"<br />
http://www.cs.nott.ac.uk/~nhn/Publications/icfp2005.pdf<br />
<br />
"Phantom types" (actually more scientific version of "Fun with phantom types")<br />
http://citeseer.ist.psu.edu/rd/0,606209,1,0.25,Download/http:qSqqSqwww.informatik.uni-bonn.deqSq~ralfqSqpublicationsqSqPhantom.ps.gz<br />
<br />
"Phantom types and subtyping" http://arxiv.org/ps/cs.PL/0403034<br />
<br />
"Existentially quantified type classes" by Stuckey, Sulzmann and Wazny (URL?)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Random rubbish from previous versions of article ==<br />
<br />
<br />
<haskell><br />
data family Map k :: * -> *<br />
<br />
data instance Map () v = MapUnit (Maybe v)<br />
data instance Map (a, b) v = MapPair (Map a (Map b v))<br />
</haskell><br />
<br />
<br />
<br />
<br />
<br />
<br />
let's consider well-known 'data' declarations:<br />
<br />
<haskell><br />
data T a = D a a Int<br />
</haskell><br />
<br />
it can be seen as function 'T' from type 'a' to some data constructor.<br />
<br />
'T Bool', for example, gives result 'D Bool Bool Int', while<br />
<br />
'T [Int]' gives result 'D [Int] [Int] Int'.<br />
<br />
'data' declaration can also have several "results", say<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
and "result" of 'Either Int String' can be either "Left Int" or "Right<br />
String"<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Well, to give compiler confidence<br />
that 'a' can be deduced in just one way from 'c', we can add some<br />
form of hint:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
The first line i added tell the compiler that Collection predicate has<br />
two parameters and the second parameter determines the first. Based on<br />
this restriction, compiler can detect and prohibit attempts to define<br />
different element types for the same collection:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a (Map b a)<br />
Collection b (Map b a) -- error! prohibits functional dependency<br />
</haskell><br />
<br />
Of course, Collection is just a function from 'c' to 'a', but if we<br />
will define it directly as a function:<br />
<br />
<haskell><br />
type Collection [a] = a<br />
Collection (Set a) = a<br />
Collection (Map b a) = a<br />
</haskell><br />
<br />
- it can't be used in 'head' definition above. Moreover, using<br />
functional dependencies we can define bi-directional functions:<br />
<br />
<haskell><br />
type TwoTimesBigger :: a b | a->b, b->a<br />
TwoTimesBigger Int8 Int16<br />
TwoTimesBigger Int16 Int32<br />
TwoTimesBigger Int32 Int64<br />
</haskell><br />
<br />
or predicates with 3, 4 or more parameters with any relations between<br />
them. It's a great power!</div>Weihuhttps://wiki.haskell.org/index.php?title=GADTs_for_dummies&diff=26107GADTs for dummies2009-01-25T16:23:30Z<p>Weihu: </p>
<hr />
<div>For a long time, I didn't understandd what GADTs are and how they can be used. It was a sort of conspiracy of silence - people who understand GADTs think<br />
it is all obvious, and don't need any explanation, but I still<br />
couldn't understand.<br />
<br />
Now I have an idea how it works, and think that it was really obvious :) and I want to share my understanding - may be my way to realize GADTs can help<br />
someone else. So:<br />
<br />
== Type functions ==<br />
<br />
A "data" declaration is a way to declare both type constructor and data<br />
constructors. For example,<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
declares type constructor "Either" and two data constructors "Left"<br />
and "Right". Ordinary Haskell functions works with data constructors:<br />
<br />
<haskell><br />
isLeft (Left a) = True<br />
isLeft (Right b) = False<br />
</haskell><br />
<br />
but there is also an analogous way to work with type constructors!<br />
<br />
<haskell><br />
type X a = Either a a<br />
</haskell><br />
<br />
declares a TYPE FUNCTION named "X". Its parameter "a" must be some type<br />
and it returns some type as its result. We can't use "X" on data values,<br />
but we can use it on type values. Type constructors declared with<br />
"data" statements and type functions declared with "type" statements<br />
used together to build arbitrarily complex types. In such<br />
"computations" type constructors serves as basic "values" and type<br />
functions as a way to process them.<br />
<br />
Indeed, type functions in Haskell are very limited compared to<br />
ordinary functions - they don't support pattern matching,<br />
nor multiple statements, nor recursion.<br />
<br />
== Hypothetical Haskell extension - Full-featured type functions ==<br />
<br />
Let's build hypothetical Haskell extension, that mimics for type<br />
functions the well-known ways to define ordinary functions, including<br />
pattern matching:<br />
<br />
<haskell><br />
type F [a] = Set a<br />
</haskell><br />
<br />
multiple statements (this is meaningful only in presence of pattern matching):<br />
<br />
<haskell><br />
type F Bool = Char<br />
F String = Int<br />
</haskell><br />
<br />
and recursion (which again needs pattern matching and multiple statements):<br />
<br />
<haskell><br />
type F [a] = F a<br />
F (Map a b) = F b<br />
F (Set a) = F a<br />
F a = a<br />
</haskell><br />
<br />
As you may already have guessed, this last definition calculates a simple base type of arbitrarily-nested collections, e.g: <br />
<br />
<haskell><br />
F [[[Set Int]]] = <br />
F [[Set Int]] =<br />
F [Set Int] = <br />
F (Set Int) =<br />
F Int =<br />
Int<br />
</haskell><br />
<br />
Let's don't forget about statement guards:<br />
<br />
<haskell><br />
type F a | IsSimple a == TrueType = a<br />
</haskell><br />
<br />
Here we define type function F only for simple datatypes by using in<br />
guard type function "IsSimple":<br />
<br />
<haskell><br />
type IsSimple Bool = TrueType<br />
IsSimple Int = TrueType<br />
....<br />
IsSimple Double = TrueType<br />
IsSimple a = FalseType<br />
<br />
data TrueType = T<br />
data FalseType = F<br />
</haskell><br />
<br />
These definitions seem a bit odd, and while we are in imaginary land,<br />
let's consider a way to write this shorter:<br />
<br />
<haskell><br />
type F a | IsSimple a = a<br />
<br />
type IsSimple Bool<br />
IsSimple Int<br />
....<br />
IsSimple Double<br />
</haskell><br />
<br />
Here, we just defined list of simple types, the implied result of all<br />
written statements for "IsSimple" is True value, and False value for<br />
anything else. Essentially, "IsSimple" is no less than TYPE PREDICATE!<br />
<br />
I really love it! :) How about constructing a predicate that traverses a<br />
complex type trying to decide whether it contains "Int" anywhere?<br />
<br />
<haskell><br />
type HasInt Int<br />
HasInt [a] = HasInt a<br />
HasInt (Set a) = HasInt a<br />
HasInt (Map a b) | HasInt a<br />
HasInt (Map a b) | HasInt b<br />
</haskell><br />
<br />
or a type function that substitutes one type with another inside<br />
arbitrary-deep types:<br />
<br />
<haskell><br />
type Replace t a b | t==a = b<br />
Replace [t] a b = [Replace t a b]<br />
Replace (Set t) a b = Set (Replace t a b)<br />
Replace (Map t1 t2) a b = Map (Replace t1 a b) (Replace t2 a b)<br />
Replace t a b = t<br />
</haskell><br />
<br />
== One more hypothetical extension - multi-value type functions ==<br />
<br />
Let's add more fun! We will introduce one more hypothetical Haskell<br />
extension - type functions that may have MULTIPLE VALUES. Say,<br />
<br />
<haskell><br />
type Collection a = [a]<br />
Collection a = Set a<br />
Collection a = Map b a<br />
</haskell><br />
<br />
So, "Collection Int" has "[Int]", "Set Int" and "Map String Int" as<br />
its values, i.e. different collection types with elements of type<br />
"Int".<br />
<br />
Pay attention to the last statement of the "Collection" definition, where<br />
we've used type variable "b" that was not mentioned on the left side<br />
nor defined in any other way. It's perfectly possible - anyway<br />
"Collection" function has multiple values, so using on the right side<br />
some free variable that can be replaced with any type is not a problem<br />
at all - the "Map Bool Int", "Map [Int] Int" and "Map Int Int" all are<br />
possible values of "Collection Int" along with "[Int]" and "Set Int".<br />
<br />
On the first look, it seems that multiple-value functions are<br />
meaningless - they can't be used to define datatypes, because we need<br />
concrete types here. But on the second look :) we can find them<br />
useful to define type constraints and type families.<br />
<br />
We can also represent multiple-value function as predicate:<br />
<br />
<haskell><br />
type Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
If you remember Prolog, you should guess that predicate, in contrast to<br />
function, is multi-purpose thing - it can be used to deduce any<br />
parameter from other ones. For example, in this hypothetical definition:<br />
<br />
<haskell><br />
head | Collection Int a :: a -> Int<br />
</haskell><br />
<br />
we define 'head' function for any Collection containing Ints.<br />
<br />
And in this, again, hypothetical definition:<br />
<br />
<haskell><br />
data Safe c | Collection c a = Safe c a<br />
</haskell><br />
<br />
we deduced element type 'a' from collection type 'c' passed as the<br />
parameter to the type constructor.<br />
<br />
<br />
<br />
== Back to real Haskell - type classes ==<br />
<br />
Reading all those glorious examples you may be wondering - why Haskell<br />
don't yet supports full-featured type functions? Hold your breath...<br />
Haskell already contains them and at least GHC implements all the<br />
mentioned abilities more than 10 years ago! They just was named...<br />
TYPE CLASSES! Let's translate all our examples to their language:<br />
<br />
<haskell><br />
class IsSimple a<br />
instance IsSimple Bool<br />
instance IsSimple Int<br />
....<br />
instance IsSimple Double<br />
</haskell><br />
<br />
Haskell'98 standard supports type classes with only one parameter that<br />
limits us to defining only type predicates like this one. But GHC and<br />
Hugs supports multi-parameter type classes that allows us to define<br />
arbitrarily-complex type functions<br />
<br />
<haskell><br />
class Collection a c<br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
instance Collection a (Map b a)<br />
</haskell><br />
<br />
All the "hypothetical" Haskell extensions we investigated earlier -<br />
actually implemented at the type class level!<br />
<br />
Pattern matching:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
</haskell><br />
<br />
Multiple statements:<br />
<br />
<haskell><br />
instance Collection a [a]<br />
instance Collection a (Set a)<br />
</haskell><br />
<br />
Recursion:<br />
<br />
<haskell><br />
instance (Collection a c) => Collection a [c]<br />
</haskell><br />
<br />
Pattern guards:<br />
<br />
<haskell><br />
instance (IsSimple a) => Collection a (UArray a)<br />
</haskell><br />
<br />
<br />
<br />
Let's define type class which contains any collection which uses Int as<br />
its elements or indexes:<br />
<br />
<haskell><br />
class HasInt a<br />
instance HasInt Int<br />
instance (HasInt a) => HasInt [a]<br />
instance (HasInt a) => HasInt (Map a b)<br />
instance (HasInt b) => HasInt (Map a b)<br />
</haskell><br />
<br />
<br />
Anther example is a class that replaces all occurrences of 'a' with<br />
'b' in type 't' and return result as 'res':<br />
<br />
<haskell><br />
class Replace t a b res<br />
instance Replace t a a t<br />
instance Replace [t] a b [Replace t a b]<br />
instance (Replace t a b res)<br />
=> Replace (Set t) a b (Set res)<br />
instance (Replace t1 a b res1, Replace t2 a b res2)<br />
=> Replace (Map t1 t2) a b (Map res1 res2)<br />
instance Replace t a b t<br />
</haskell><br />
<br />
You can compare it to the hypothetical definition we given earlier.<br />
It's important to note that type class instances, as opposite to<br />
function statements, are not checked in order. Instead, most<br />
_specific_ instance automatically selected. So, in Replace case, the<br />
last instance that is most general will be selected only if all other<br />
are failed to match and that is that we want.<br />
<br />
In many other cases this automatic selection is not powerful enough<br />
and we are forced to use some artificial tricks or complain to the<br />
language developers. The two most well-known language extensions<br />
proposed to solve such problems are instance priorities, which allow<br />
to explicitly specify instance selection order, and '/=' constraints,<br />
which can be used to explicitly prohibit unwanted matches:<br />
<br />
<haskell><br />
instance Replace t a a t<br />
instance (a/=b) => Replace [t] a b [Replace t a b]<br />
instance (a/=b, t/=[_]) => Replace t a b t<br />
</haskell><br />
<br />
You can check that these instances are no more overlaps.<br />
<br />
<br />
At practice, type-level arithmetics by itself is not very useful. It<br />
becomes really strong weapon when combined with another feature that<br />
type classes provide - member functions. For example:<br />
<br />
<haskell><br />
class Collection a c where<br />
foldr1 :: (a -> a -> a) -> c -> a<br />
<br />
class Num a where<br />
(+) :: a -> a -> a<br />
<br />
sum :: (Num a, Collection a c) => c -> a<br />
sum = foldr1 (+)<br />
</haskell><br />
<br />
<br />
I'll be also glad to see possibility to use type classes in data<br />
declarations like this:<br />
<br />
<haskell><br />
data Safe c = (Collection c a) => Safe c a<br />
</haskell><br />
<br />
but afaik this is also not yet implemented<br />
<br />
<br />
UNIFICATION<br />
...<br />
<br />
<br />
<br />
== Back to GADTs ==<br />
<br />
If you are wonder how relates all these interesting type manipulations<br />
to GADTs, now is the time to give you answer. As you know, Haskell<br />
contains highly developed ways to express data-to-data functions. Now<br />
we also know that Haskell contains rich facilities to write<br />
type-to-type functions in form of "type" statements and type classes.<br />
But how "data" statements fits in this infrastructure?<br />
<br />
My answer: they just defines type-to-data constructors translation.<br />
Moreover, this translation may give multiple results. Say, the<br />
following definition:<br />
<br />
<haskell><br />
data Maybe a = Just a | Nothing<br />
</haskell><br />
<br />
defines type-to-data constructors function "Maybe" that has parameter<br />
"a" and for each "a" has two possible results - "Just a" and<br />
"Nothing". We can rewrite it in the same hypothetical syntax that was<br />
used above for multi-value type functions:<br />
<br />
<haskell><br />
data Maybe a = Just a<br />
Maybe a = Nothing<br />
</haskell><br />
<br />
Or how about this:<br />
<br />
<haskell><br />
data List a = Cons a (List a)<br />
List a = Nil<br />
</haskell><br />
<br />
and this:<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
But how are flexible "data" definitions? As you should remember,<br />
"type" definitions was very limited in their features, while type<br />
classes, vice versa, much more developed than ordinary Haskell<br />
functions facilities. What about features of "data" definitions<br />
examined as sort of functions?<br />
<br />
On the one side, they supports multiple statements and multiple<br />
results and can be recursive, like the "List" definition above. On the<br />
other side, that's all - no pattern matching or even type constants on<br />
the left side and no guards.<br />
<br />
Lack of pattern matching means that left side can contain only free<br />
type variables, that in turn means that left sides of all "data"<br />
statements for one type will be essentially the same. Therefore,<br />
repeated left sides in multi-statement "data" definitions are omitted<br />
and instead of<br />
<br />
<haskell><br />
data Either a b = Left a<br />
Either a b = Right b<br />
</haskell><br />
<br />
we write just<br />
<br />
<haskell><br />
data Either a b = Left a<br />
| Right b<br />
</haskell><br />
<br />
<br />
And here finally comes the GADTs! It's just a way to define data types<br />
using pattern matching and constants on the left side of "data"<br />
statements! How about this:<br />
<br />
<haskell><br />
data T String = D1 Int<br />
T Bool = D2<br />
T [a] = D3 (a,a)<br />
</haskell><br />
<br />
Amazed? After all, GADTs seems really very simple and obvious<br />
extension to data type definition facilities.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The idea is to allow a data constructor's return type to<br />
be specified directly:<br />
<br />
<haskell><br />
data Term a where<br />
Lit :: Int -> Term Int<br />
Pair :: Term a -> Term b -> Term (a,b)<br />
...<br />
</haskell><br />
<br />
In a function that performs pattern matching on Term, the pattern<br />
match gives type as well as value information. For example,<br />
consider this function:<br />
<br />
<haskell><br />
eval :: Term a -> a<br />
eval (Lit i) = i<br />
eval (Pair a b) = (eval a, eval b)<br />
...<br />
</haskell><br />
<br />
If the argument matches Lit, it must have been built with a<br />
Lit constructor, so type 'a' must be Int, and hence we can return 'i'<br />
(an Int) in the right hand side. The same objections applies to the Pair<br />
constructor.<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Further reading ==<br />
<br />
The best paper on type level arithmetic using type classes i've seen<br />
is "Faking it: simulating dependent types in Haskell"<br />
( http://www.cs.nott.ac.uk/~ctm/faking.ps.gz ). Most part of my<br />
article is just duplicates his work.<br />
<br />
The great demonstration of type-level arithmetic is TypeNats package<br />
which "defines type-level natural numbers and arithmetic operations on<br />
them including addition, subtraction, multiplication, division and GCD"<br />
( darcs get --partial --tag '0.1' http://www.eecs.tufts.edu/~rdocki01/typenats/ )<br />
<br />
I should also mention here Oleg Kiselyov page on type-level<br />
programming in Haskell: http://okmij.org/ftp/Haskell/types.html<br />
<br />
<br />
There are plenty of GADT-related papers, but best for beginners<br />
remains the "Fun with phantom types"<br />
(http://www.informatik.uni-bonn.de/~ralf/publications/With.pdf).<br />
Phantom types is another name of GADT. You should also know that this<br />
paper uses old GADT syntax. This paper is must-read because it<br />
contains numerous examples of practical GADT usage - theme completely<br />
omitted from my article.<br />
<br />
<br />
Other GADT-related papers i know:<br />
<br />
"Dynamic Optimization for Functional Reactive Programming using<br />
Generalized Algebraic Data Types"<br />
http://www.cs.nott.ac.uk/~nhn/Publications/icfp2005.pdf<br />
<br />
"Phantom types" (actually more scientific version of "Fun with phantom types")<br />
http://citeseer.ist.psu.edu/rd/0,606209,1,0.25,Download/http:qSqqSqwww.informatik.uni-bonn.deqSq~ralfqSqpublicationsqSqPhantom.ps.gz<br />
<br />
"Phantom types and subtyping" http://arxiv.org/ps/cs.PL/0403034<br />
<br />
"Existentially quantified type classes" by Stuckey, Sulzmann and Wazny (URL?)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
== Random rubbish from previous versions of article ==<br />
<br />
<br />
<haskell><br />
data family Map k :: * -> *<br />
<br />
data instance Map () v = MapUnit (Maybe v)<br />
data instance Map (a, b) v = MapPair (Map a (Map b v))<br />
</haskell><br />
<br />
<br />
<br />
<br />
<br />
<br />
let's consider well-known 'data' declarations:<br />
<br />
<haskell><br />
data T a = D a a Int<br />
</haskell><br />
<br />
it can be seen as function 'T' from type 'a' to some data constructor.<br />
<br />
'T Bool', for example, gives result 'D Bool Bool Int', while<br />
<br />
'T [Int]' gives result 'D [Int] [Int] Int'.<br />
<br />
'data' declaration can also have several "results", say<br />
<br />
<haskell><br />
data Either a b = Left a | Right b<br />
</haskell><br />
<br />
and "result" of 'Either Int String' can be either "Left Int" or "Right<br />
String"<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Well, to give compiler confidence<br />
that 'a' can be deduced in just one way from 'c', we can add some<br />
form of hint:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a [a]<br />
Collection a (Set a)<br />
Collection a (Map b a)<br />
</haskell><br />
<br />
The first line i added tell the compiler that Collection predicate has<br />
two parameters and the second parameter determines the first. Based on<br />
this restriction, compiler can detect and prohibit attempts to define<br />
different element types for the same collection:<br />
<br />
<haskell><br />
type Collection :: a c | c->a<br />
Collection a (Map b a)<br />
Collection b (Map b a) -- error! prohibits functional dependency<br />
</haskell><br />
<br />
Of course, Collection is just a function from 'c' to 'a', but if we<br />
will define it directly as a function:<br />
<br />
<haskell><br />
type Collection [a] = a<br />
Collection (Set a) = a<br />
Collection (Map b a) = a<br />
</haskell><br />
<br />
- it can't be used in 'head' definition above. Moreover, using<br />
functional dependencies we can define bi-directional functions:<br />
<br />
<haskell><br />
type TwoTimesBigger :: a b | a->b, b->a<br />
TwoTimesBigger Int8 Int16<br />
TwoTimesBigger Int16 Int32<br />
TwoTimesBigger Int32 Int64<br />
</haskell><br />
<br />
or predicates with 3, 4 or more parameters with any relations between<br />
them. It's a great power!</div>Weihuhttps://wiki.haskell.org/index.php?title=GHC/As_a_library&diff=24746GHC/As a library2008-12-14T02:27:31Z<p>Weihu: Added a link to ghc's docs</p>
<hr />
<div>''For instructions on the GHC API with GHC 6.8 or older please refer to [[GHC/As a library (up to 6.8)]]''<br />
<br />
__TOC__<br />
<br />
== Introduction ==<br />
<br />
GHC's functionality can be useful for more things than just compiling Haskell programs. Important use cases are programs that analyse (and perhaps transform) Haskell code. Others include loading Haskell code dynamically in a GHCi-like manner. For this reason, a lot of GHC's features can be accessed by programs which import the <tt>ghc</tt> package.<br />
<br />
The instructions on this page concern the API of GHC 6.10.1 and above. Please not that the GHC API is still in flux and may change quite significantly between major releases while we (the GHC team) provide new features or simplify certain aspects.<br />
<br />
<br />
== Getting Started ==<br />
<br />
To use the GHC API you need GHC 6.10.1 or above and import the <tt>ghc</tt> package.<br />
<pre><br />
ghc -package ghc my_program.hs<br />
</pre><br />
In most cases you probably also want to use the [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/ghc-paths ghc-paths package].<br />
<br />
Most of the common functionality is provided by the <tt>GHC</tt> module, but occasionally you may have to import other modules. See the GHC's [http://www.haskell.org/ghc/docs/latest/html/libraries/ghc/index.html haddock documentation] for a list of these modules.<br />
<br />
== A Simple Example ==<br />
<br />
The following little program essentially does what <tt>ghc --make</tt> does.<br />
<br />
<haskell><br />
import GHC<br />
import GHC.Paths ( libdir )<br />
import DynFlags ( defaultDynFlags )<br />
<br />
main = <br />
defaultErrorHandler defaultDynFlags $ do<br />
runGhc (Just libdir) $ do<br />
dflags <- getSessionDynFlags<br />
setSessionDynFlags dflags<br />
target <- guessTarget "test_main.hs" Nothing<br />
setTargets [target]<br />
load LoadAllTargets<br />
</haskell><br />
<br />
The outermost function, <tt>defaultErrorHandler</tt>, sets up proper exception handlers and prints an error message and exits with exit code 1 if it encounters one of these exceptions.<br />
<br />
Most of GHC's high-level API requires access to a current session. Therefore, these functions require to be called inside a monad that is an instance of the <tt>GhcMonad</tt> typeclass. Two default implementations of this typeclass are <tt>Ghc</tt> and <tt>GhcT</tt>. In the above example we used the <tt>Ghc</tt> monad since we don't need to track any extra state.<br />
<br />
The argument to <tt>runGhc</tt> is a bit tricky. GHC needs this to find its libraries, so the argument must refer to the directory that is printed by <tt>ghc --print-libdir</tt> for the ''same'' version of GHC that the program is being compiled with. Above we therefore use the <tt>ghc-paths</tt> package which provides this for us.</div>Weihuhttps://wiki.haskell.org/index.php?title=The_Monad.Reader/Discuss_Issue12&diff=24175The Monad.Reader/Discuss Issue122008-11-20T08:37:28Z<p>Weihu: </p>
<hr />
<div>Comments welcome!</div>Weihuhttps://wiki.haskell.org/index.php?title=The_Monad.Reader/Discuss_Issue12&diff=24171The Monad.Reader/Discuss Issue122008-11-20T05:27:22Z<p>Weihu: </p>
<hr />
<div>Comments welcome!<br />
<br />
[[User:Weihu|Weihu]] I couldn't get the code in "Compiler Development Made Easy" to run with ghc-6.10.1. What version of ghc is going to support this plugin feature?</div>Weihuhttps://wiki.haskell.org/index.php?title=Applications_and_libraries/Mathematics&diff=23350Applications and libraries/Mathematics2008-10-07T17:26:18Z<p>Weihu: Fixed the link to Decimal</p>
<hr />
<div>== Applications ==<br />
<br />
=== Physics ===<br />
<br />
;[http://ab-initio.mit.edu/meep/ Meep]<br />
:Meep (or MEEP) is a free finite-difference time-domain (FDTD) simulation software package developed at MIT to model electromagnetic systems.<br />
<br />
;[[Numeric Quest]]<br />
:Jan Skibinski's [[Numeric Quest]] library provides modules that are useful for Quantum Mechanics, among other things.<br />
<br />
== Libraries ==<br />
<br />
=== Linear algebra ===<br />
<br />
;[http://alberrto.googlepages.com/gslhaskell GSLHaskell]<br />
:High level functional interface to standard linear algebra computations and other numerical algorithms based on the GNU Scientific Library and LAPACK. Includes numerical differentiation, integration, Fourier transforms, polynomial root-finding, and support for gnuplot. [[GSLHaskell on MacOS X|MacOS X]].<br />
<br />
;[http://www.cs.utah.edu/~hal/HBlas/index.html Wrapper to CLAPACK]<br />
<br />
;[http://haskelldsp.sourceforge.net/ Digital Signal Processing]<br />
:Modules for matrix manipulation, Fourier transform, interpolation, spectral estimation, and frequency estimation.<br />
<br />
;[http://article.gmane.org/gmane.comp.lang.haskell.general/13561 Index-aware linear algebra]<br />
:Frederik Eaton's library for statically checked matrix manipulation in Haskell<br />
<br />
;[[Numeric Quest]]<br />
:Jan Skibinski's [[Numeric Quest]] library provides several modules that are useful for linear algebra in general, among other things.<br />
<br />
;[[vector-space]]<br />
:The [[vector-space]] package defines classes and generic operations for vector spaces and affine spaces. It also defines a type of infinite towers of generalized derivatives (linear transformations).<br />
<br />
<br />
== See also ==<br />
<br />
* [[Linear algebra]]<br />
* [[Mathematical prelude discussion]]<br />
<br />
<br />
See also: [[Linear algebra|Design discussions]]<br />
<br />
=== [[Physical units]] ===<br />
<br />
;[[Dimensionalized numbers]]<br />
: Working with physical units like second, meter and so on in a type-safe manner.<br />
<br />
;[http://darcs.haskell.org/numericprelude/src/Number/SI.hs NumericPrelude: Physical units]<br />
: Numeric values with dynamically checked units.<br />
<br />
;[[CalDims]]<br />
:This is not simply a library providing a new type of <hask>Num</hask> class, but stand-alone calculation tool that supports user defined functions and units (basic and derrived), so it can provide dimension-save calculation (not embedded but via shell). Calculations can be modified/saved via shell. It uses rational numbers to avoid rounding errors where possible.<br />
<br />
;[http://code.google.com/p/dimensional/ Dimensional]<br />
: Library providing data types for performing arithmetic with physical quantities and units. Information about the physical dimensions of the quantities/units is embedded in their types and the validity of operations is verified by the type checker at compile time. The boxing and unboxing of numerical values as quantities is done by multiplication and division of units.<br />
<br />
=== Number representations ===<br />
<br />
==== Decimal numbers ====<br />
<br />
;[http://src.seereason.com/decimal/ Decimal arithmetic library]<br />
:An implementation of real decimal arithmetic, for cases where the binary floating point is not acceptable (for example, money).<br />
<br />
==== Real and rational numbers ====<br />
<br />
There are several levels of [[Exact real arithmetic|handling real numbers]] and according libraries.<br />
<br />
===== Arbitrary precision =====<br />
<br />
* Numbers have fixed precision<br />
* Rounding errors accumulate<br />
* Sharing is easy, i.e. in <hask>sqrt pi + sin pi</hask>, <hask>pi</hask> is computed only once<br />
* Fast, because the routines can make use of the fast implementation of <hask>Integer</hask> operations<br />
<br />
;[[Numeric Quest]]<br />
:Jan Skibinski's [[Numeric Quest]] library provides, among other things, a type for arbitrary precision rational numbers with transcendental functions.<br />
<br />
;[http://cvs.haskell.org/darcs/numericprelude/src/Number/FixedPoint.hs FixedPoint.hs]<br />
:part of NumericPrelude project<br />
<br />
;[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/AERN-Real AERN-Real]<br />
:contains arbitrary precision ''interval arithmetic'' for approximating exact real numbers in a style similar to Mueller's iRRAM and Lambov's RealLib<br />
<br />
;[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/AERN-RnToRm AERN-RnToRm]<br />
:contains arithmetic of ''piecewise polynomial function enclosures'' that efficiently approximate multi-dimensional real functions to arbitrary precision<br />
<br />
;[http://www.mpfr.org/ MPFR] Haskell interface is included in [http://www2.arnes.si/~abizja4/hera/ Hera]<br />
: See below for more information about Hera.<br />
<br />
===== Dynamic precision =====<br />
<br />
* You tell the precision, an expression shall be computed to and the computer finds out, how precise to compute the input values.<br />
* Rounding errors do not accumulate<br />
* Sharing of temporary results is difficult, that is in <hask>sqrt pi + sin pi</hask>, <hask>pi</hask> will certainly be computed twice, each time with the required precision.<br />
* Almost as fast as arbitrary precision computation<br />
<br />
;[http://www.cs.man.ac.uk/arch/dlester/exact.html ERA] is an implementation (in Haskell 1.2) by David Lester.<br />
: It is quite fast, possibly the fastest Haskell implementation. At 220 lines it is also the shortest. Probably the shortest implementation of exact real arithmetic in any language.<br />
: The provided number type <hask>CReal</hask> is instance of the Haskell 98 numeric type classes and thus can be used whereever you used Float or Double before and encountered some numerical difficulties.<br />
:Here is a mirror: http://darcs.augustsson.net/Darcs/CReal/<br />
<br />
;[http://www.doc.ic.ac.uk/~ae/exact-computation/#bm:implementations IC-Reals] is an implementation by Abbas Edalat, Marko Krznar&#263; and Peter J. Potts.<br />
:This implementation uses linear fractional transformations.<br />
<br />
;[http://r6.ca/ Few Digits] by Russell O'Connor.<br />
:This is a prototype of the implementation he intendeds to write in [http://coq.inria.fr/ Coq]. Once the Coq implementation is complete, the Haskell code could be extracted producing an implementation that would be proved correct.<br />
<!--<br />
Example:<br />
*Data.Real.CReal> answer 1000 (exp 1 + sqrt 2)<br />
--><br />
<br />
;COMP is an implementation by Yann Kieffer.<br />
:The work is in beta and relies on new primitive operations on Integers which will be implemented in GHC. The library isn't available yet.<br />
<br />
;[http://www2.arnes.si/~abizja4/hera/ Hera] is an implementation by Aleš Bizjak.<br />
:It uses the [http://www.mpfr.org/ MPFR] library to implement dyadic rationals, on top of which are implemented intervals and real numbers. A real number is represented as a function <code>int -&gt; interval</code> which represents a sequence of intervals converging to the real.<br />
<br />
===== Dynamic precision by lazy evaluation =====<br />
<br />
The real numbers are represented by an infinite datastructure, which allows you to increase precision successively by evaluating the data structure successively. All of the implementations below use some kind of digit stream as number representation.<br />
Sharing of results is simple.<br />
The implementations are either fast on simple expressions, because they use large blocks/bases, or they are fast on complex expressions, because they consume as little as possible input digits in order to emit the required output digits.<br />
<br />
;[http://medialab.freaknet.org/bignum/ BigFloat] is an implementation by Martin Guy.<br />
:It works with streams of decimal digits (strictly in the range from 0 to 9) and a separate sign. The produced digits are always correct. Output is postponed until the code is certain what the next digit is. This sometimes means that [http://medialab.freaknet.org/bignum/dudeney.html no more data is output].<br />
<br />
;In [http://users.info.unicaen.fr/~karczma/arpap/lazypi.ps.gz "The Most Unreliable Technique in the World to compute pi"] Jerzy Karczmarczuk develops some functions for computing pi lazily.<br />
<br />
;[http://darcs.haskell.org/numericprelude/src/Number/Positional.hs NumericPrelude: positional numbers]<br />
:Represents a real number as pair <hask>(exponent,[digit])</hask>, where the digits are <hask>Int</hask>s in the open range <hask>(-basis,basis)</hask>. There is no need for an extra sign item in the number data structure. The <hask>basis</hask> can range from <hask>10</hask> to <hask>1000</hask>. (Binary representations can be derived from the hexadecimal representation.) Showing the numbers in traditional format (non-negative digits) fails for fractions ending with a run of zeros. However the internal representation with negative digits can always be shown and is probably more useful for further processing. An interface for the numeric type hierarchy of the NumericPrelude project is provided.<br />
:It features<br />
:* basis conversion<br />
:* basic arithmetic: addition, subtraction, multiplication, division<br />
:* algebraic arithmetic: square root, other roots (no general polynomial roots)<br />
:* transcendental arithmetic: pi, exponential, logarithm, trigonometric and inverse trigonometric functions<br />
<br />
=== Type class hierarchies ===<br />
<br />
There are several approaches to improve the [[Mathematical prelude discussion|numeric type class hierarchy]].<br />
<br />
;Dylan Thurston and Henning Thielemann's [[Numeric Prelude]]<br />
:Experimental revised framework for numeric type classes. Needs hiding of Prelude, overriding hidden functions like fromInteger and multi-parameter type classes. Probably restricted to GHC.<br />
<br />
;Jerzy Karczmarczuk's [http://www.haskell.org/pipermail/haskell-cafe/2001-February/001510.html approach]<br />
<br />
;Serge D. Mechveliani's [ftp://ftp.botik.ru/pub/local/Mechveliani/basAlgPropos/ Basic Algebra proposal]<br />
<br />
;Andrew Frank's [http://www.haskell.org/pipermail/haskell-cafe/2006-April/015326.html approach]<br />
:The proposal: ftp://ftp.geoinfo.tuwien.ac.at/frank/numbersPrelude_v1.pdf<br />
<br />
;Haskell Prime: [http://hackage.haskell.org/trac/haskell-prime/ticket/112 Ongoing efforts for the language revision]<br />
<br />
=== Discrete mathematics ===<br />
<br />
;[http://andrew.bromage.org/darcs/numbertheory/ Number Theory Library]<br />
:Andrew Bromage's Haskell number theory library, providing operations on primes, fibonacci sequences and combinatorics.<br />
<br />
;[http://users.skynet.be/jyp/HGAL/ HGAL]<br />
:An haskell implementation of Brendan McKay's algorithm for graph canonic labeling and automorphism group. (aka Nauty)<br />
<br />
;[http://www.cambridge.org/uk/catalogue/catalogue.asp?isbn=0521849306 Computational Oriented Matroids]<br />
:is a book by [http://wwwopt.mathematik.tu-darmstadt.de/~bokowski/ Jürgen G. Bokowski], where he develops Haskell code for Matroid computations.<br />
<br />
See also [[Libraries and tools/Cryptography]]<br />
<br />
=== Computer Algebra ===<br />
<br />
;[http://haskell.org/docon/ DoCon] - Algebraic Domain Constructor<br />
:A library for Algebra, turns GHCi into a kind of Computer Algebra System<br />
<br />
;[http://www.info.unicaen.fr/~karczma/arpap/ Papers by Jerzy Karczmarczuk]<br />
:Some interesting uses of Haskell in mathematics, including [[functional differentiation]], power series, continued fractions.<br />
<br />
=== Statistics ===<br />
;[http://www.sftank.net/?q=node/10 hstats]<br />
: Statistical Computing with Haskell<br />
<br />
=== Miscellaneous libraries ===<br />
<br />
;[http://www.robtougher.com/HaskellMath/ HaskellMath]<br />
:The HaskellMath library is a sandbox for experimenting with mathematics algorithms. So far I've implemented a few quantitative finance models (Black Scholes, Binomial Trees, etc) and basic linear algebra functions. Next I might work on either computer algebra or linear programming. All comments welcome!<br />
<br />
;[http://www.polyomino.f2s.com/david/haskell/codeindex.html Haskell for Maths]<br />
:David Amos' [http://www.polyomino.f2s.com/david/haskell/main.html collection of math libraries] in Haskell - including number theory, commutative algebra, combinatorics, permutation groups and more.<br />
<br />
;[http://darcs.haskell.org/htam/ Various math stuff by Henning Thielemann]<br />
:This is some unsorted mathematical stuff including: GNUPlot wrapper, portable grey map (PGM) image reader and writer, simplest numerical integration, differentiation, zero finding, interpolation, solution of differential equations, combinatorics, some solutions of math riddles, computation of fractal dimensions of iterated function systems (IFS)<br />
<br />
;[[Numeric Quest]]<br />
:Jan Skibinski wrote a collection of Haskell modules that are useful for Mathematics in general, and Quantum Mechanics in particular.<br />
<br />
:Some of the modules are hosted on [http://darcs.haskell.org/numeric-quest/ haskell.org]. They include modules for:<br />
:* Rational numbers with transcendental functions<br />
:* Roots of polynomials<br />
:* Eigensystems<br />
:* Tensors<br />
:* Dirac quantum mechanics<br />
<br />
:Other modules in Numeric Quest are currently only available via the [http://web.archive.org/web/20010605003250/http://www.numeric-quest.com/haskell/ Internet Archive]. They include, among many other things:<br />
:* [http://web.archive.org/web/*/http://www.numeric-quest.com/haskell/ State vector evolution]<br />
:* [http://web.archive.org/web/*/http://www.numeric-quest.com/haskell/ Short study of fuzzy oscillator]<br />
<br />
:See the [[Numeric Quest]] page for more information.<br />
<br />
;[http://www.dinkla.net/fp/cglib.html Geometric Algorithms]<br />
:A small Haskell library, containing algorithms for two-dimensional convex hulls, triangulations of polygons, Voronoi-diagrams and Delaunay-triangulations, the QEDS data structure, kd-trees and range-trees.<br />
<br />
;[http://repetae.net/john/recent/out/HsASA.html Adaptive Simulated Annealing]<br />
:A Haskell interface to Lester Ingber's adaptive simulating annealing code.<br />
<br />
;[http://www.solcon.nl/mklooster/repos/hmm/ Hmm: Haskell Metamath]<br />
:Hmm is a small Haskell library to parse and verify Metamath databases.<br />
<br />
;[http://eecs.oregonstate.edu/~erwig/pfp/ Probabilistic Functional Programming]<br />
:The PFP library is a collection of modules for Haskell that facilitates probabilistic functional programming, that is, programming with stochastic values. The probabilistic functional programming approach is based on a data type for representing distributions. A distribution represent the outcome of a probabilistic event as a collection of all possible values, tagged with their likelihood. A nice aspect of this system is that simulations can be specified independently from their method of execution. That is, we can either fully simulate or randomize any simulation without altering the code which defines it.<br />
:Get Darcs repository: <code> darcs get http://darcs.haskell.org/probability/ </code><br />
<br />
;[[Sinc function]]<br />
<br />
;[[Gamma and Beta function]]<br />
<br />
;[http://repetae.net/john/recent/out/Boolean.html Boolean]<br />
:A general boolean algebra class and some instances for Haskell.<br />
<br />
;[http://darcs.haskell.org/~lemmih/hode/ HODE]<br />
:HODE is a binding to the Open Dynamics Engine. ODE is an open source, high performance library for simulating rigid body dynamics.<br />
<br />
;[http://sourceforge.net/projects/ranged-sets Ranged Sets]<br />
:A ranged set is a list of non-overlapping ranges. The ranges have upper and lower boundaries, and a boundary divides the base type into values above and below. No value can ever sit on a boundary. So you can have the set <math>(2.0, 3.0] \cup (5.3, 6)</math>.<br />
<br />
;[http://code.google.com/p/hhydra/ hhydra]<br />
:Hhydra is a tool to compute Goodstein successions and hydra puzzles described by Bernard Hodgson in his article 'Herculean or Sisyphean tasks?' published in No 51 March 2004 of the Newsletter of the European Mathematical Society.<br />
<br />
[[Category:Mathematics]]<br />
{{LibrariesPage}}</div>Weihuhttps://wiki.haskell.org/index.php?title=Programming_guidelines&diff=23141Programming guidelines2008-09-30T02:49:51Z<p>Weihu: </p>
<hr />
<div>Programming guidelines shall help to make the code of a project better<br />
readable and maintainable by the varying number of contributors.<br />
<br />
It takes some programming experience to develop something like a<br />
personal "coding style" and guidelines only serve as rough shape for<br />
code. Guidelines should be followed by all members working on the<br />
project even if they prefer (or are already used to) different<br />
guidelines.<br />
<br />
These guidelines have been originally set up for the hets-project<br />
[http://www.informatik.uni-bremen.de/cofi/hets/ hets-project] and are<br />
now put on the [http://haskell.org/haskellwiki/ HaskellWiki] gradually<br />
integrating parts of [http://haskell.org/hawiki the old hawiki]<br />
entries [http://haskell.org/haskellwiki/Things_to_avoid ThingsToAvoid] and<br />
[http://haskell.org/hawiki/HaskellStyle HaskellStyle] (hopefully not<br />
hurting someone's copyrights). The other related entry<br />
[http://haskell.org/hawiki/TipsAndTricks TipsAndTricks] treats more<br />
specific points that are left out here,<br />
<br />
Surely some style choices are a bit arbitrary (or "religious") and<br />
too restrictive with respect to language extensions. Nevertheless I hope<br />
to keep up these guidelines (at least as a basis) for our project<br />
in order to avoid maintaining diverging guidelines. Of course I want<br />
to supply - partly tool-dependent - reasons for certain decisions and<br />
also show alternatives by possibly bad examples. At the time of<br />
writing I use ghc-6.4.1, haddock-0.7 and (GNU-) emacs with the latest<br />
[http://www.haskell.org/haskell-mode/ haskell mode].<br />
<br />
The following quote and links are taken from<br />
[http://haskell.org/hawiki/HaskellStyle the old general comments]:<br />
<br />
We all have our own ideas about good Haskell style. There's More Than<br />
One Way To Do It. But some ways are better than others.<br />
<br />
Some comments from the GHC team about their internal coding<br />
standards can be found at<br />
http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions<br />
<br />
Also http://research.microsoft.com/~simonpj/papers/haskell-retrospective/<br />
contains some brief comments on syntax and style,<br />
<br />
What now follows are descriptions of program documentation, file<br />
format, naming conventions and good programming practice (adapted form<br />
Matt's C/C++ Programming Guidelines and the Linux kernel coding<br />
style).<br />
<br />
<br />
=== Documentation ===<br />
<br />
<br />
Comments are to be written in application terms (i.e. user's point of<br />
view). Don't use technical terms - that's what the code is for!<br />
<br />
Comments should be written using correct spelling and grammar in complete<br />
sentences with punctation (in English only).<br />
<br />
"Generally, you want your comments to tell WHAT your code does, not HOW.<br />
Also, try to avoid putting comments inside a function body: if the<br />
function is so complex that you need to separately comment parts of it,<br />
you should probably" (... decompose it)<br />
<br />
Put a haddock comment on top of every exported function and data type!<br />
Make sure haddock accepts these comments.<br />
<br />
<br />
=== File Format ===<br />
<br />
<br />
All Haskell source files start with a haddock header of the form:<br />
<br />
<pre><br />
{- |<br />
Module : <File name or $Header$ to be replaced automatically><br />
Description : <Short text displayed on contents page><br />
Copyright : (c) <You> and <Your affiliation><br />
License : similar to LGPL, see LICENSE.txt<br />
<br />
Maintainer : Christian.Maeder@dfki.de<br />
Stability : provisional<br />
Portability : portable<br />
<br />
<module description starting at first column><br />
-}<br />
</pre><br />
<br />
A possible compiler pragma (like {-# OPTIONS -cpp #-}) may precede<br />
this header. The following hierarchical module name must of course<br />
match the file name.<br />
<br />
Make sure that the description is changed to meet the module (if the<br />
header was copied from elsewhere). Insert your email address as maintainer.<br />
<br />
Try to write portable (Haskell98) code. If you (indirectly) import<br />
a module that uses i.e. multi-parameter type classes and functional<br />
dependencies the code becomes "non-portable (MPTC with FD)".<br />
<br />
The \$Header\$ entry will be automatically expanded.<br />
<br />
Lines should not be longer than 80 (preferably 75)<br />
characters to avoid wrapped lines (for casual readers)!<br />
<br />
Don't leave trailing white space in your code in every line.<br />
<br />
Expand all your tabs to spaces to avoid the danger of wrongly expanding<br />
them (or a different display of tabs versus eight spaces). Possibly put<br />
something like the following in your ~/.emacs file.<br />
<br />
(custom-set-variables '(indent-tabs-mode nil))<br />
<br />
The last character in your file should be a newline! Under solaris<br />
you'll get a warning if this is not the case and sometimes last lines<br />
without newlines are ignored (i.e. "#endif" without newline). Emacs<br />
usually asks for a final newline.<br />
<br />
The whole module should not be too long (about 400 lines)<br />
<br />
<br />
=== Naming Conventions ===<br />
<br />
<br />
In Haskell types start with capital and functions with lowercase<br />
letters, so only avoid infix identifiers! Defining symbolic infix<br />
identifiers should be left to library writers only.<br />
<br />
(The infix identifier "\\" at the end of a line causes cpp preprocessor<br />
problems.)<br />
<br />
Names (especially global ones) should be descriptive and if you need<br />
long names write them as mixed case words (aka camelCase). (but "tmp"<br />
is to be preferred over "thisVariableIsATemporaryCounter")<br />
<br />
Also in the standard libraries, function names with multiple words are<br />
written using the camelCase convention. Similarly, type, typeclass and<br />
constructor names are written using the StudlyCaps convention.<br />
<br />
Some parts of our code use underlines (without unnecessary uppercase<br />
letters) for long identifiers to better reflect names given with<br />
hyphens in the requirement documentation. Also such names should be<br />
transliterated to camlCase identifiers possibly adding a (consistent)<br />
suffix or prefix to avoid conflicts with keywords. However, instead of<br />
a recurring prefix or suffix you may consider to use qualified imports<br />
and names.<br />
<br />
<br />
=== Good Programming Practice ===<br />
<br />
<br />
"Functions should be short and sweet, and do just one thing. They should<br />
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,<br />
as we all know), and do one thing and do that well."<br />
<br />
Most haskell functions should be at most a few lines, only case<br />
expression over large data types (that should be avoided, too) may need<br />
corresponding space.<br />
<br />
The code should be succinct (though not obfuscated), readable and easy to<br />
maintain (after unforeseeable changes). Don't exploit exotic language<br />
features without good reason.<br />
<br />
It's not fixed how deep you indent (4 or 8 chars). You can break the<br />
line after "do", "let", "where", and "case .. of". Make sure that<br />
renamings don't destroy your layout. (If you get to far to the right,<br />
the code is unreadable anyway and needs to be decomposed.)<br />
<br />
Bad:<br />
case foo of Foo -> "Foo"<br />
Bar -> "Bar"<br />
Good:<br />
case <longer expression> of<br />
Foo -> "Foo"<br />
Bar -> "Bar"<br />
<br />
Avoid the notation with braces and semicolons since the layout rule<br />
forces you to properly align your alternatives.<br />
<br />
Respect compiler warnings. Supply type signatures, avoid shadowing and<br />
unused variables. Particularly avoid non-exhaustive and<br />
overlapping patterns. Missing unreachable cases can be filled in using<br />
"error" with a fixed string "<ModuleName>.<function>" to indicate the<br />
error position (in case the impossible should happen). Don't invest<br />
time to "show" the offending value, only do this temporarily when<br />
debugging the code.<br />
<br />
Don't leave unused or commented-out code in your files! Readers don't<br />
know what to think of it.<br />
<br />
<br />
==== Case expressions ====<br />
<br />
Prefer case expressions over pattern binding declarations with<br />
multiple equations.<br />
<br />
Not always nice:<br />
longFunctionName (Foo: _ : _) = e1<br />
longFunctionName (Bar: _) = e2<br />
<br />
Better:<br />
longFunctionName arg = case arg of<br />
Foo : _ : _ -> e1<br />
Bar : _ -> e2<br />
_ -> error "ProgrammingGuidelines.longFunctionName"<br />
<br />
In<br />
http://research.microsoft.com/~simonpj/papers/haskell-retrospective/<br />
the first example is said to be written in [[declaration style]]. The<br />
equations look like written for a rewrite system (although their order<br />
matters of course).<br />
<br />
But this declarative style is only nice for toy examples and annoying<br />
if functions are renamed or if the number of arguments changes.<br />
<br />
The other extreme (according to SPJ) is [[expression style]]:<br />
longFunctionName = \ arg -> ...<br />
<br />
We don't propose this style either. We propose to use as much pattern<br />
matching (including as-patterns) on a single left-hand-side as appropriate.<br />
<br />
However, the expression style with a lambda term may come in handy, when<br />
setting record fields of a function type.<br />
<br />
We avoid lambda expressions if this is easily possibly using the<br />
Prelude functions const, flip, curry, uncurry or section notation or<br />
plain partial application. We do not indroduce an auxiliary function only to<br />
avoid the lambda, though.<br />
<br />
<br />
==== Partial functions ====<br />
<br />
For partial functions do document their preconditions (if not obvious)<br />
and make sure that partial functions are only called when<br />
preconditions are obviously fulfilled (i.e. by a case statement or a<br />
previous test). Particularly the call of "head" should be used with<br />
care or (even better) be made obsolete by a case statement.<br />
<br />
Usually a case statement (and the import of isJust and fromJust from<br />
Data.[[Maybe]]) can be avoided by using the "maybe" function:<br />
<br />
maybe (error "<ModuleName>.<function>") id $ Map.lookup key map<br />
<br />
Generally we require you to be more explicit about failure<br />
cases. Surely a missing (or an irrefutable) pattern would precisely<br />
report the position of a runtime error, but these are not so obvious<br />
when reading the code.<br />
<br />
==== Let or where expressions ====<br />
<br />
Do avoid mixing and nesting "let" and "where". (I prefer the<br />
expression-stylistic "let".) Use auxiliary top-level functions that<br />
you do not export. Export lists also support the detection of unused<br />
functions.<br />
<br />
<br />
==== Code reuse ====<br />
<br />
If you notice that you're doing the same task again, try to generalize<br />
it in order to avoid duplicate code. It is frustrating to change the<br />
same error in several places.<br />
<br />
<br />
==== Application notation ====<br />
<br />
Many parentheses can be eliminated using the infix application operator "$"<br />
with lowest priority. Try at least to avoid unnecessary parentheses in<br />
standard infix expression.<br />
<br />
f x : g x ++ h x<br />
<br />
a == 1 && b == 1 || a == 0 && b == 0<br />
<br />
Rather than putting a large final argument in parentheses (with a<br />
distant closing one) consider using "$" instead.<br />
<br />
"f (g x)" becomes "f $ g x" and consecutive applications<br />
"f (g (h x))" can be written as "f $ g $ h x" or "f . g $ h x".<br />
<br />
A function definition like<br />
"f x = g $ h x" can be abbreviated to "f = g . h".<br />
<br />
Note that the final argument may even be an infix- or case expression:<br />
<br />
map id $ c : l<br />
<br />
filter (const True) . map id $ case l of ...<br />
<br />
However, be aware that $-terms cannot be composed further in infix<br />
expressions.<br />
<br />
Probably wrong:<br />
f $ x ++ g $ x<br />
<br />
But the scope of an expression is also limited by the layout rule, so<br />
it is usually safe to use "$" on right hand sides.<br />
<br />
Ok:<br />
do f $ l<br />
++<br />
do g $ l<br />
<br />
Of course "$" can not be used in types. GHC has also some primitive<br />
functions involving the kind "#" that cannot be applied using "$".<br />
<br />
Last warning: always leave spaces around "$" (and other mixfix<br />
operators) since a clash with template haskell is possible.<br />
<br />
(Also write "\ t" instead of "\t" in lambda expressions)<br />
<br />
<br />
==== List Comprehensions ====<br />
<br />
Use these only when "short and sweet". Prefer map, filter, and foldr!<br />
<br />
Instead of:<br />
<br />
[toUpper c | c <- s]<br />
<br />
write:<br />
<br />
map toUpper s<br />
<br />
<br />
Consider:<br />
<br />
[toUpper c | s <- strings, c <- s]<br />
<br />
Here it takes some time for the reader to find out which value depends<br />
on what other value and it is not so clear how many times the interim<br />
values s and c are used. In contrast to that the following can't be clearer:<br />
<br />
map toUpper (concat strings)<br />
<br />
<br />
When using higher order functions you can switch easier to data<br />
structures different from list. Compare:<br />
<br />
map (1+) list<br />
<br />
and:<br />
<br />
Set.map (1+) set<br />
<br />
<br />
==== Types ====<br />
<br />
Prefer proper data types over type synonyms or tuples even if you have<br />
to do more constructing and unpacking. This will make it easier to<br />
supply class instances later on. Don't put class constraints on<br />
a data type, constraints belong only to the functions that manipulate<br />
the data.<br />
<br />
Using type synonyms consistently is difficult over a longer time,<br />
because this is not checked by the compiler. (The types shown by<br />
the compiler may be unpredictable: i.e. FilePath, String or [Char])<br />
<br />
Take care if your data type has many variants (unless it is an<br />
enumeration type.) Don't repeat common parts in every variant since<br />
this will cause code duplication.<br />
<br />
Bad (to handle arguments in sync):<br />
<br />
data Mode f p = Box f p | Diamond f p<br />
<br />
Good (to handle arguments only once):<br />
<br />
data BoxOrDiamond = Box | Diamond<br />
<br />
data Mode f p = Mode BoxOrDiamond f p<br />
<br />
<br />
Consider (bad):<br />
<br />
data Tuple a b = Tuple a b | Undefined<br />
<br />
versus (better):<br />
<br />
data Tuple a b = Tuple a b<br />
<br />
and using:<br />
<br />
Maybe (Tuple a b)<br />
<br />
(or another monad) whenever an undefined result needs to be propagated<br />
<br />
<br />
==== Records ====<br />
<br />
For (large) records avoid the use of the constructor directly and<br />
remember that the order and number of fields may change.<br />
<br />
Take care with (the rare case of) depend polymorphic fields:<br />
<br />
data Fields a = VariantWithTwo<br />
{ field1 :: a<br />
, field2 :: a }<br />
<br />
The type of a value v can not be changed by only setting field1:<br />
<br />
v { field1 = f }<br />
<br />
Better construct a new value:<br />
<br />
VariantWithTwo { field1 = f } -- leaving field2 undefined<br />
<br />
Or use a polymorphic element that is instantiated by updating:<br />
<br />
empty = VariantWithTwo { field1 = [], field2 = [] }<br />
<br />
empty { field1 = [f] }<br />
<br />
Several variants with identical fields may avoid some code duplication<br />
when selecting and updating, though possibly not in a few<br />
depended polymorphic cases.<br />
<br />
However, I doubt if the following is a really good alternative to the<br />
above data Mode with data BoxOrDiamond.<br />
<br />
<br />
data Mode f p =<br />
Box { formula :: f, positions :: p }<br />
| Diamond { formula :: f, positions :: p }<br />
<br />
<br />
==== IO ====<br />
<br />
Try to strictly separate IO, Monad and pure (without do) function<br />
programming (possibly via separate modules).<br />
<br />
Bad:<br />
x <- return y<br />
...<br />
<br />
Good:<br />
let x = y<br />
...<br />
<br />
<br />
Don't use Prelude.interact and make sure your program does not depend<br />
on the (not always obvious) order of evaluation. I.e. don't read and<br />
write to the same file:<br />
<br />
This will fail:<br />
<br />
do s <- readFile f<br />
writeFile f $ 'a' : s<br />
<br />
because of lazy IO! (Writing is starting before reading is finished.)<br />
<br />
<br />
==== Trace ====<br />
<br />
Tracing is for debugging purposes only and should not be used as<br />
feedback for the user. Clean code is not cluttered by trace calls.<br />
<br />
<br />
==== Imports ====<br />
<br />
Standard library modules like Char. List, Maybe, Monad, etc should be<br />
imported by their hierarchical module name, i.e. the base package (so<br />
that haddock finds them):<br />
<br />
import Data.List<br />
import Control.Monad<br />
import System.Environment<br />
<br />
The libraries for Set and Map are to be imported qualified:<br />
<br />
import qualified Data.Set as Set<br />
import qualified Data.Map as Map<br />
<br />
<br />
==== Glasgow extensions and Classes ====<br />
<br />
[[Use of language extensions|Stay away from extensions]] as long as possible. Also use classes with<br />
care because soon the desire for overlapping instances (like for lists<br />
and strings) may arise. Then you may want MPTC (multi-parameter type<br />
classes), functional dependencies (FD), undecidable and possibly incoherent<br />
instances and then you are "in the wild" (according to SPJ).<br />
<br />
=== Style in other languages ===<br />
<br />
* [http://www.cs.caltech.edu/~cs20/a/style.html OCaml style]<br />
<br />
=== Final remarks ===<br />
<br />
Despite guidelines, writing "correct code" (without formal proof<br />
support yet) still remains the major challenge. As motivation to<br />
follow these guidelines consider the points that are from the "C++<br />
Coding Standard", where I replaced "C++" with "Haskell".<br />
<br />
Good Points:<br />
<br />
* programmers can go into any code and figure out what's going on<br />
<br />
* new people can get up to speed quickly<br />
<br />
* people new to Haskell are spared the need to develop a personal style and defend it to the death<br />
<br />
* people new to Haskell are spared making the same mistakes over and over again<br />
<br />
* people make fewer mistakes in consistent environments<br />
<br />
* programmers have a common enemy :-)<br />
<br />
Bad Points:<br />
<br />
* the standard is usually stupid because it was made by someone who doesn't understand Haskell<br />
<br />
* the standard is usually stupid because it's not what I do<br />
<br />
* standards reduce creativity<br />
<br />
* standards are unnecessary as long as people are consistent<br />
<br />
* standards enforce too much structure<br />
<br />
* people ignore standards anyway<br />
<br />
<br />
<br />
[[Category:Style]]</div>Weihuhttps://wiki.haskell.org/index.php?title=Quasiquotation&diff=23118Quasiquotation2008-09-28T15:44:27Z<p>Weihu: Fixed two typos</p>
<hr />
<div>This is a tutorial for the quasiquoting facility described in<br />
[http://www.eecs.harvard.edu/~mainland/ghc-quasiquoting/mainland07quasiquoting.pdf Why It's Nice to be Quoted: Quasiquoting for Haskell]. Note that the syntax for<br />
quasiquotation has changed since the paper was written: now one writes<br />
<hask>[$expr|...|]</hask> instead of <hask>[:expr|...|]</hask>. Quasiquotation<br />
appeared in GHC 6.9 and is enabled with the <code>QuasiQuotes</code> language<br />
option (<code>-XQuasiQuotes</code> on the command line or <hask>{-# LANGUAGE QuasiQuotes #-}</hask> in a source file).<br />
<br />
We show how to build a quasiquoter for a simple mathematical expression<br />
language. Although the example is small, it demonstrates all aspects of building<br />
a quasiquoter. We do not mean to suggest that one gains much from a quasiquoter<br />
for such a small language relative to using abstract syntax directly except from<br />
a pedagogical point of view---this is just a tutorial!<br />
<br />
The tutorial is runnable if its contents is placed in files as follows:<br />
<br />
Place the contents of the [[#Syntax]] section in the file <code>Expr.hs</code><br />
with header<br />
<br />
<haskell><br />
{-# LANGUAGE DeriveDataTypeable #-}<br />
module Expr (Expr(..),<br />
BinOp(..),<br />
eval,<br />
parseExpr)<br />
where<br />
<br />
import Data.Generics<br />
import Text.ParserCombinators.Parsec<br />
</haskell><br />
<br />
Place the contents of the section [[#Parsing]] and [[#The Quasiquoter]] in a<br />
file <code>Expr/Quote.hs</code> with header<br />
<br />
<haskell><br />
module Expr.Quote (expr) where<br />
<br />
import Data.Generics<br />
import qualified Language.Haskell.TH as TH<br />
import Language.Haskell.TH.Quote<br />
<br />
import Expr<br />
</haskell><br />
<br />
= Syntax =<br />
<br />
Our simple expression language consists of integers, the standard operators<br />
+,x,*,/, and parenthesized expressions. We will write a single parser that takes<br />
concrete syntax for this language and transforms it to abstract syntax. Using<br />
the SYB approach to generic programming, we will then use this parser to produce<br />
expression and pattern quasiquoters. Our quasiquoter will allow us to write<br />
<hask>[$expr|1 + 3|]</hask> directly in Haskell source code instead of the<br />
corresponding abstract syntax.<br />
<br />
An obvious datatype for the abstract syntax of this simple language is:<br />
<br />
<haskell><br />
data Expr = IntExpr Integer<br />
| BinopExpr (Integer -> Integer -> Integer) Expr Expr<br />
deriving(Show)<br />
</haskell><br />
<br />
Unfortunately, this won't do for our quasiquoter. First of all, the SYB<br />
technique we use cannot handle function types in a generic way, so the BinopExpr<br />
constructor must be modified. SYB also requires that we derive Typeable and<br />
Data, a trivial change. Finally, we want to support antiquoting for two<br />
syntactic categories, expressions and integers. With antiquoting support, we can<br />
write [$expr|$x + $int:y|] where x and y are in-scope variables with types Expr<br />
and Integer, respectively. The final data types for our abstract syntax are:<br />
<br />
<haskell><br />
data Expr = IntExpr Integer<br />
| AntiIntExpr String<br />
| BinopExpr BinOp Expr Expr<br />
| AntiExpr String<br />
deriving(Show, Typeable, Data)<br />
<br />
data BinOp = AddOp<br />
| SubOp<br />
| MulOp<br />
| DivOp<br />
deriving(Show, Typeable, Data)<br />
</haskell><br />
<br />
An evaluator for our abstract syntax can be written as follows:<br />
<br />
<haskell><br />
eval :: Expr -> Integer<br />
eval (IntExpr n) = n<br />
eval (BinopExpr op x y) = (opToFun op) (eval x) (eval y)<br />
where<br />
opToFun AddOp = (+)<br />
opToFun SubOp = (-)<br />
opToFun MulOp = (*)<br />
opToFun DivOp = div<br />
</haskell><br />
<br />
= Parsing =<br />
<br />
We use Parsec to write a parser for our expression language. Note that we have<br />
(somewhat arbitrarily) chosen the syntax for antiquotaton to be as in the above<br />
example; a quasiquoter may choose whatever syntax she wishes.<br />
<br />
<haskell><br />
small = lower <|> char '_'<br />
large = upper<br />
idchar = small <|> large <|> digit <|> char '\''<br />
<br />
lexeme p = do{ x <- p; spaces; return x }<br />
symbol name = lexeme (string name)<br />
parens p = between (symbol "(") (symbol ")") p<br />
<br />
expr :: CharParser st Expr<br />
expr = term `chainl1` addop<br />
<br />
term :: CharParser st Expr<br />
term = factor `chainl1` mulop<br />
<br />
factor :: CharParser st Expr<br />
factor = parens expr <|> integer <|> try antiIntExpr <|> antiExpr<br />
<br />
mulop = do{ symbol "*"; return $ BinopExpr MulOp }<br />
<|> do{ symbol "/"; return $ BinopExpr DivOp }<br />
<br />
addop = do{ symbol "+"; return $ BinopExpr AddOp }<br />
<|> do{ symbol "-"; return $ BinopExpr SubOp }<br />
<br />
integer :: CharParser st Expr<br />
integer = lexeme $ do{ ds <- many1 digit ; return $ IntExpr (read ds) }<br />
<br />
ident :: CharParser s String<br />
ident = do{ c <- small; cs <- many idchar; return (c:cs) }<br />
<br />
antiIntExpr = lexeme $ do{ symbol "$int:"; id <- ident; return $ AntiIntExpr id }<br />
antiExpr = lexeme $ do{ symbol "$"; id <- ident; return $ AntiExpr id }<br />
</haskell><br />
<br />
The helper function parseExpr takes a source code position (consisting of a file<br />
name, line and column) and a string and returns a value of type Expr. This<br />
helper function also ensures that we can parse the whole string rather than just<br />
a prefix.<br />
<br />
<haskell><br />
parseExpr :: Monad m => (String, Int, Int) -> String -> m Expr<br />
parseExpr (file, line, col) s =<br />
case runParser p () "" s of<br />
Left err -> fail $ show err<br />
Right e -> return e<br />
where<br />
p = do pos <- getPosition<br />
setPosition $<br />
(flip setSourceName) file $<br />
(flip setSourceLine) line $<br />
(flip setSourceColumn) col $<br />
pos<br />
spaces<br />
e <- expr<br />
eof<br />
return e<br />
</haskell><br />
<br />
= The Quasiquoter =<br />
<br />
Remember, our quasiquoter allows us to write expression in our simple language,<br />
such as [$expr|2 * 3|], directly in Haskell source code. This requires that the<br />
variable expr be in-scope when the quasiquote is encountered, and that it is<br />
bound to a value of type Language.Haskell.TH.Quote.QuasiQuoter, which contains<br />
an expression quoter and a pattern quoter. Note that expr must obey the same<br />
stage restrictions as Template Haskell; in particular, it may not be defined in<br />
the same module where it is used as a quasiquoter, but must be imported.<br />
<br />
Our expression and pattern quoters are quoteExprExp and quoteExprPat,<br />
respectively, so our quasiquoter expr is written as follows:<br />
<br />
<haskell><br />
quoteExprExp :: String -> TH.ExpQ<br />
quoteExprPat :: String -> TH.PatQ<br />
<br />
expr :: QuasiQuoter<br />
expr = QuasiQuoter quoteExprExp quoteExprPat<br />
</haskell><br />
<br />
Our quasiquoters re-use the parser we wrote in the previous section, parseExpr,<br />
and make use of the generic functions dataToExpQ and dataToPatQ (described in<br />
the Haskell Workshop paper). These functions, from the Language.Haskell.TH.Quote<br />
package, take a Haskell value and reflect it back into the language as Template<br />
Haskell abstract syntax. The catch is that we don't want to handle all values<br />
generically: antiquoted values must be handled specially. Consider the AntiExpr<br />
constructor; we don't want this constructor to be mapped to Template Haskell<br />
abstract syntax for the AntiExpr constructor, but to abstract syntax for the<br />
Haskell variable named by the constructor's argument. The extQ combinator allows<br />
us to do this nicely by defining a function antiExprExp that handles<br />
antiquotations.<br />
<br />
<haskell><br />
quoteExprExp s = do loc <- TH.location<br />
let pos = (TH.loc_filename loc,<br />
fst (TH.loc_start loc),<br />
snd (TH.loc_start loc))<br />
expr <- parseExpr pos s<br />
dataToExpQ (const Nothing `extQ` antiExprExp) expr<br />
<br />
antiExprExp :: Expr -> Maybe (TH.Q TH.Exp)<br />
antiExprExp (AntiIntExpr v) = Just $ TH.appE (TH.conE (TH.mkName "IntExpr"))<br />
(TH.varE (TH.mkName v))<br />
antiExprExp (AntiExpr v) = Just $ TH.varE (TH.mkName v)<br />
antiExprExp _ = Nothing<br />
</haskell><br />
<br />
The corresponding code for patterns is:<br />
<br />
<haskell><br />
quoteExprPat s = do loc <- TH.location<br />
let pos = (TH.loc_filename loc,<br />
fst (TH.loc_start loc),<br />
snd (TH.loc_start loc))<br />
expr <- parseExpr pos s<br />
dataToPatQ (const Nothing `extQ` antiExprPat) expr<br />
<br />
antiExprPat :: Expr -> Maybe (TH.Q TH.Pat)<br />
antiExprPat (AntiIntExpr v) = Just $ TH.conP (TH.mkName "IntExpr")<br />
[TH.varP (TH.mkName v)]<br />
antiExprPat (AntiExpr v) = Just $ TH.varP (TH.mkName v)<br />
antiExprPat _ = Nothing<br />
</haskell><br />
<br />
= Examples =<br />
<br />
We can now try out a few examples by invoking ghci as follows: <code>ghci -XQuasiQuotes Expr/Quote</code><br />
<br />
<pre><br />
> [$expr|1 + 3 + 5|]<br />
BinopExpr AddOp (BinopExpr AddOp (IntExpr 1) (IntExpr 3)) (IntExpr 5) <br />
> eval [$expr|1 + 3 + 5|]<br />
9 <br />
</pre><br />
<br />
Taking advantage of our quasiquoter, we can re-write our evaluator so it uses<br />
concrete syntax:<br />
<br />
<haskell><br />
eval' :: Expr -> Integer<br />
eval' [$expr|$int:x|] = x<br />
eval' [$expr|$x + $y|] = eval' x + eval' y<br />
eval' [$expr|$x - $y|] = eval' x - eval' y<br />
eval' [$expr|$x * $y|] = eval' x * eval' y<br />
eval' [$expr|$x / $y|] = eval' x `div` eval' y<br />
</haskell><br />
<br />
Let's make sure it works as advertised:<br />
<br />
<pre><br />
> eval [$expr|1 + 2 + 3|] == eval' [$expr|1 + 2 + 3|]<br />
True <br />
> eval [$expr|1 + 3 * 5|] == eval' [$expr|1 + 3 * 5|]<br />
True <br />
</pre></div>Weihuhttps://wiki.haskell.org/index.php?title=Euler_problems/31_to_40&diff=23046Euler problems/31 to 402008-09-22T00:40:52Z<p>Weihu: </p>
<hr />
<div>== [http://projecteuler.net/index.php?section=problems&id=31 Problem 31] ==<br />
Investigating combinations of English currency denominations.<br />
<br />
Solution:<br />
<br />
This is the naive doubly recursive solution. Speed would be greatly improved by use of [[memoization]], dynamic programming, or the closed form.<br />
<haskell><br />
problem_31 = ways [1,2,5,10,20,50,100,200] !!200<br />
where ways [] = 1 : repeat 0<br />
ways (coin:coins) =n <br />
where n = zipWith (+) (ways coins) (take coin (repeat 0) ++ n)<br />
</haskell><br />
<br />
A beautiful solution, making usage of laziness and recursion to implement a dynamic programming scheme, blazingly fast despite actually generating the combinations and not only counting them :<br />
<haskell><br />
coins = [1,2,5,10,20,50,100,200]<br />
<br />
combinations = foldl (\without p -><br />
let (poor,rich) = splitAt p without<br />
with = poor ++ zipWith (++) (map (map (p:)) with)<br />
rich<br />
in with<br />
) ([[]] : repeat [])<br />
<br />
problem_31 = length $ combinations coins !! 200<br />
</haskell><br />
<br />
The above may be ''a beautiful solution'', but I couldn't understand it without major mental gymnastics. I would like to offer the following, which I hope will be easier to follow for ordinary ''mentats'' -- HenryLaxen 2008-02-22<br />
<haskell><br />
coins = [1,2,5,10,20,50,100,200]<br />
<br />
withcoins 1 x = [[x]]<br />
withcoins n x = concatMap addCoin [0 .. x `div` coins!!(n-1)]<br />
where addCoin k = map (++[k]) (withcoins (n-1) (x - k*coins!!(n-1)) )<br />
<br />
problem_31 = length $ withcoins (length coins) 200 <br />
</haskell><br />
<br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=32 Problem 32] ==<br />
Find the sum of all numbers that can be written as pandigital products.<br />
<br />
Solution:<br />
<haskell><br />
import Control.Monad<br />
<br />
combs 0 xs = [([],xs)]<br />
combs n xs = [(y:ys,rest) | y <- xs, (ys,rest) <- combs (n-1) (delete y xs)]<br />
<br />
l2n :: (Integral a) => [a] -> a<br />
l2n = foldl' (\a b -> 10*a+b) 0<br />
<br />
swap (a,b) = (b,a)<br />
<br />
explode :: (Integral a) => a -> [a]<br />
explode = unfoldr (\a -> if a==0 then Nothing else Just . swap $ quotRem a 10)<br />
<br />
pandigiticals =<br />
nub $ do (beg,end) <- combs 5 [1..9]<br />
n <- [1,2]<br />
let (a,b) = splitAt n beg<br />
res = l2n a * l2n b<br />
guard $ sort (explode res) == end<br />
return res<br />
<br />
problem_32 = sum pandigiticals<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=33 Problem 33] ==<br />
Discover all the fractions with an unorthodox cancelling method.<br />
<br />
Solution:<br />
<haskell><br />
import Data.Ratio<br />
problem_33 = denominator . product $ rs<br />
{-<br />
xy/yz = x/z<br />
(10x + y)/(10y+z) = x/z<br />
9xz + yz = 10xy<br />
-}<br />
rs = [(10*x+y)%(10*y+z) | x <- t, <br />
y <- t, <br />
z <- t,<br />
x /= y ,<br />
(9*x*z) + (y*z) == (10*x*y)]<br />
where t = [1..9]<br />
</haskell><br />
<br />
That is okay, but why not let the computer do the ''thinking'' for you? Isn't this a little more directly expressive of the problem? -- HenryLaxen 2008-02-34<br />
<haskell><br />
import Data.Ratio<br />
problem_33 = denominator $ product <br />
[ a%c | a<-[1..9], b<-[1..9], c<-[1..9],<br />
isCurious a b c, a /= b && a/= c]<br />
where isCurious a b c = ((10*a+b)%(10*b+c)) == (a%c)<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=34 Problem 34] ==<br />
Find the sum of all numbers which are equal to the sum of the factorial of their digits.<br />
<br />
Solution:<br />
<haskell><br />
import Data.Char<br />
problem_34 = sum [ x | x <- [3..100000], x == facsum x ]<br />
where facsum = sum . map (product . enumFromTo 1 . digitToInt) . show<br />
<br />
</haskell><br />
<br />
Another way:<br />
<br />
<haskell><br />
import Data.Array<br />
import Data.List<br />
<br />
{-<br />
<br />
The key comes in realizing that N*9! < 10^N when N >= 9, so we<br />
only have to check up to 9 digit integers. The other key is<br />
that addition is commutative, so we only need to generate<br />
combinations (with duplicates) of the sums of the various<br />
factorials. These sums are the only potential "curious" sums.<br />
<br />
-}<br />
<br />
fac n = a!n<br />
where a = listArray (0,9) (1:(scanl1 (*) [1..9]))<br />
<br />
-- subsets of size k, including duplicates<br />
combinationsOf 0 _ = [[]]<br />
combinationsOf _ [] = []<br />
combinationsOf k (x:xs) = map (x:) <br />
(combinationsOf (k-1) (x:xs)) ++ combinationsOf k xs<br />
<br />
intToList n = reverse $ unfoldr <br />
(\x -> if x == 0 then Nothing else Just (x `mod` 10, x `div` 10)) n<br />
<br />
isCurious (n,l) = sort (intToList n) == l<br />
<br />
-- Turn a list into the sum of the factorials of the digits<br />
factorialSum l = foldr (\x y -> (fac x) + y) 0 l<br />
<br />
possiblyCurious = map (\z -> (factorialSum z,z)) <br />
curious n = filter isCurious $ possiblyCurious $ combinationsOf n [0..9]<br />
problem_34 = sum $ (fst . unzip) $ concatMap curious [2..9]<br />
</haskell><br />
(The wiki formatting is messing up the unzip"&gt;unzip line above, it is correct in the version I typed in. It should of course just be fst . unzip)<br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=35 Problem 35] ==<br />
How many circular primes are there below one million?<br />
<br />
Solution:<br />
<haskell><br />
import Data.List (tails, (\\))<br />
<br />
primes :: [Integer]<br />
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]<br />
<br />
primeFactors :: Integer -> [Integer]<br />
primeFactors n = factor n primes<br />
where<br />
factor _ [] = []<br />
factor m (p:ps) | p*p > m = [m]<br />
| m `mod` p == 0 = p : factor (m `div` p) (p:ps)<br />
| otherwise = factor m ps<br />
<br />
isPrime :: Integer -> Bool<br />
isPrime 1 = False<br />
isPrime n = case (primeFactors n) of<br />
(_:_:_) -> False<br />
_ -> True<br />
<br />
permutations :: Integer -> [Integer]<br />
permutations n = take l $ map (read . take l) $ tails $ take (2*l -1) $ cycle s<br />
where<br />
s = show n<br />
l = length s<br />
<br />
circular_primes :: [Integer] -> [Integer]<br />
circular_primes [] = []<br />
circular_primes (x:xs)<br />
| all isPrime p = x : circular_primes xs<br />
| otherwise = circular_primes xs<br />
where<br />
p = permutations x<br />
<br />
problem_35 :: Int<br />
problem_35 = length $ circular_primes $ takeWhile (<1000000) primes<br />
</haskell><br />
<br />
Using isPrime from above, and observing that one that can greatly reduce the search space because no circular prime can contain an even number, nor a 5, since eventually such a digit will be at the end of the number, and<br />
hence composite, we get: (HenryLaxen 2008-02-27)<br />
<br />
<haskell><br />
canBeCircularPrimeList = [1,3,7,9]<br />
<br />
crossProduct 0 _ = [[]]<br />
crossProduct n l = [ [x]++y | x<- l, y <- crossProduct (n-1) l]<br />
<br />
listToInt n = foldl (\x y -> 10*x+y) 0 n<br />
rot n l = (drop n l) ++ (take n l)<br />
allrots l = map (\x -> rot x l) [0..(length l)-1]<br />
isCircular l = all (isPrime . listToInt) $ allrots l<br />
circular 1 = [[2],[3],[5],[7]] -- a slightly special case<br />
circular n = filter isCircular $ crossProduct n canBeCircularPrimeList<br />
<br />
problem_35 = length $ concatMap circular [1..6]<br />
</haskell><br />
<br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=36 Problem 36] ==<br />
Find the sum of all numbers less than one million, which are palindromic in base 10 and base 2.<br />
<br />
Solution:<br />
<haskell><br />
import Numeric<br />
import Data.Char<br />
<br />
showBin = flip (showIntAtBase 2 intToDigit) ""<br />
<br />
isPalindrome x = x == reverse x<br />
<br />
problem_36 = sum [x | x <- [1,3..1000000], isPalindrome (show x), isPalindrome (showBin x)]<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=37 Problem 37] ==<br />
Find the sum of all eleven primes that are both truncatable from left to right and right to left.<br />
<br />
Solution:<br />
<haskell><br />
import Data.List (tails, inits, nub)<br />
<br />
primes :: [Integer]<br />
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]<br />
<br />
primeFactors :: Integer -> [Integer]<br />
primeFactors n = factor n primes<br />
where<br />
factor _ [] = []<br />
factor m (p:ps) | p*p > m = [m]<br />
| m `mod` p == 0 = p : factor (m `div` p) (p:ps)<br />
| otherwise = factor m ps<br />
<br />
isPrime :: Integer -> Bool<br />
isPrime 1 = False<br />
isPrime n = case (primeFactors n) of<br />
(_:_:_) -> False<br />
_ -> True<br />
<br />
truncs :: Integer -> [Integer]<br />
truncs n = nub . map read $ (take l . tail . tails) s ++ (take l . tail . inits) s<br />
where<br />
l = length s - 1<br />
s = show n<br />
<br />
problem_37 = sum $ take 11 [x | x <- dropWhile (<=9) primes, all isPrime (truncs x)]<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=38 Problem 38] ==<br />
What is the largest 1 to 9 pandigital that can be formed by multiplying a fixed number by 1, 2, 3, ... ?<br />
<br />
Solution:<br />
<haskell><br />
import Data.List<br />
<br />
mult n i vs <br />
| length (concat vs) >= 9 = concat vs<br />
| otherwise = mult n (i+1) (vs ++ [show (n * i)])<br />
<br />
problem_38 = maximum . map read . filter ((['1'..'9'] ==) .sort) <br />
$ [mult n 1 [] | n <- [2..9999]]<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=39 Problem 39] ==<br />
If p is the perimeter of a right angle triangle, {a, b, c}, which value, for p ≤ 1000, has the most solutions?<br />
<br />
Solution:<br />
We use the well known formula to generate primitive Pythagorean triples. All we need are the perimeters, and they have to be scaled to produce all triples in the problem space.<br />
<haskell><br />
problem_39 = head $ perims !! indexMax<br />
where perims = group<br />
$ sort [n*p | p <- pTriples, n <- [1..1000 `div` p]]<br />
counts = map length perims<br />
Just indexMax = findIndex (== (maximum counts)) $ counts<br />
pTriples = [p |<br />
n <- [1..floor (sqrt 1000)],<br />
m <- [n+1..floor (sqrt 1000)],<br />
even n || even m,<br />
gcd n m == 1,<br />
let a = m^2 - n^2,<br />
let b = 2*m*n,<br />
let c = m^2 + n^2,<br />
let p = a + b + c,<br />
p < 1000]<br />
</haskell><br />
<br />
== [http://projecteuler.net/index.php?section=problems&id=40 Problem 40] ==<br />
Finding the nth digit of the fractional part of the irrational number.<br />
<br />
Solution:<br />
<haskell><br />
problem_40 = (d 1)*(d 10)*(d 100)*(d 1000)*(d 10000)*(d 100000)*(d 1000000)<br />
where n = concat [show n | n <- [1..]]<br />
d j = Data.Char.digitToInt (n !! (j-1))<br />
</haskell></div>Weihuhttps://wiki.haskell.org/index.php?title=Roll_your_own_IRC_bot&diff=22635Roll your own IRC bot2008-08-27T03:16:13Z<p>Weihu: </p>
<hr />
<div>This tutorial is designed as a practical guide to writing real world<br />
code in [http://haskell.org Haskell] and hopes to intuitively motivate<br />
and introduce some of the advanced features of Haskell to the novice<br />
programmer. Our goal is to write a concise, robust and elegant<br />
[http://haskell.org/haskellwiki/IRC_channel IRC] bot in Haskell.<br />
<br />
== Getting started ==<br />
<br />
You'll need a reasonably recent version of [http://haskell.org/ghc GHC]<br />
or [http://haskell.org/hugs Hugs]. Our first step is to get on the<br />
network. So let's start by importing the Network package, and the<br />
standard IO library and defining a server to connect to.<br />
<br />
<haskell><br />
import Network<br />
import System.IO<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
<br />
main = do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
t <- hGetContents h<br />
print t<br />
</haskell><br />
<br />
The key here is the <hask>main</hask> function. This is the entry point<br />
to a Haskell program. We first connect to the server, then set the<br />
buffering on the socket off. Once we've got a socket, we can then just<br />
read and print any data we receive.<br />
<br />
Put this code in the module <hask>1.hs</hask> and we can then run it.<br />
Use whichever system you like:<br />
<br />
Using runhaskell:<br />
<br />
$ runhaskell 1.hs<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or we can just compile it to an executable with GHC:<br />
<br />
$ ghc --make 1.hs -o tutbot<br />
Chasing modules from: 1.hs<br />
Compiling Main ( 1.hs, 1.o )<br />
Linking ...<br />
$ ./tutbot<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or using GHCi:<br />
<br />
$ ghci 1.hs<br />
*Main> main<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Or in Hugs:<br />
<br />
$ runhugs 1.hs<br />
"NOTICE AUTH :*** Looking up your hostname...\r\nNOTICE AUTH :***<br />
Checking ident\r\nNOTICE AUTH :*** Found your hostname\r\n ...<br />
<br />
Great! We're on the network.<br />
<br />
== Talking IRC ==<br />
<br />
Now we're listening to the server, we better start sending some<br />
information back. Three details are important: the nick, the user name,<br />
and a channel to join. So let's send those.<br />
<br />
<haskell><br />
import Network<br />
import System.IO<br />
import Text.Printf<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
chan = "#tutbot-testing"<br />
nick = "tutbot"<br />
<br />
main = do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
write h "NICK" nick<br />
write h "USER" (nick++" 0 * :tutorial bot")<br />
write h "JOIN" chan<br />
listen h<br />
<br />
write :: Handle -> String -> String -> IO ()<br />
write h s t = do<br />
hPrintf h "%s %s\r\n" s t<br />
printf "> %s %s\n" s t<br />
<br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
s <- hGetLine h<br />
putStrLn s<br />
where<br />
forever a = do a; forever a<br />
</haskell><br />
<br />
Now, we've done quite a few things here. Firstly, we import<br />
<hask>Text.Printf</hask>, which will be useful. We also set up a channel<br />
name and bot nickname. The <hask>main</hask> function has been extended<br />
to send messages back to the IRC server using a <hask>write</hask><br />
function. Let's look at that a bit more closely:<br />
<br />
<haskell><br />
write :: Handle -> String -> String -> IO ()<br />
write h s t = do<br />
hPrintf h "%s %s\r\n" s t<br />
printf "> %s %s\n" s t<br />
</haskell><br />
<br />
We've given <hask>write</hask> an explicit type to help document it, and<br />
we'll use explicit types signatures from now on, as they're just good<br />
practice (though of course not required, as Haskell uses type inference<br />
to work out the types anyway).<br />
<br />
The <hask>write</hask> function takes 3 arguments; a handle (our<br />
socket), and then two strings representing an IRC protocol action, and<br />
any arguments it takes. <hask>write</hask> then uses <hask>hPrintf</hask><br />
to build an IRC message and write it over the wire to the server. For<br />
debugging purposes we also print to standard output the message we send.<br />
<br />
Our second function, <hask>listen</hask>, is as follows:<br />
<br />
<haskell><br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
s <- hGetLine h<br />
putStrLn s<br />
where<br />
forever a = do a; forever a<br />
</haskell><br />
<br />
This function takes a Handle argument, and sits in an infinite loop<br />
reading lines of text from the network and printing them. We take<br />
advantage of two powerful features; lazy evaluation and higher order<br />
functions to roll our own loop control structure, <hask>forever</hask>,<br />
as a normal function! <hask>forever</hask> takes a chunk of code as an<br />
argument, evaluates it and recurses - an infinite loop function. It<br />
is very common to roll our own control structures in Haskell this way,<br />
using higher order functions. No need to add new syntax to the language, lisp-like macros or meta programming - you just write a normal<br />
function to implement whatever control flow you wish. We can also avoid<br />
<hask>do</hask>-notation, and directly write: <hask>forever a = a >> forever a</hask>.<br />
<br />
Let's run this thing:<br />
<br />
<haskell><br />
$ runhaskell 2.hs<br />
> NICK tutbot<br />
> USER tutbot 0 * :tutorial bot<br />
> JOIN #tutbot-testing<br />
NOTICE AUTH :*** Looking up your hostname...<br />
NOTICE AUTH :*** Found your hostname, welcome back<br />
NOTICE AUTH :*** Checking ident<br />
NOTICE AUTH :*** No identd (auth) response<br />
:orwell.freenode.net 001 tutbot :Welcome to the freenode IRC Network tutbot<br />
:orwell.freenode.net 002 tutbot :Your host is orwell.freenode.net<br />
...<br />
:tutbot!n=tutbot@aa.bb.cc.dd JOIN :#tutbot-testing<br />
:orwell.freenode.net MODE #tutbot-testing +ns<br />
:orwell.freenode.net 353 tutbot @ #tutbot-testing :@tutbot<br />
:orwell.freenode.net 366 tutbot #tutbot-testing :End of /NAMES list.<br />
</haskell><br />
<br />
And we're in business! From an IRC client, we can watch the bot connect:<br />
<br />
15:02 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:02 dons> hello<br />
<br />
And the bot logs to standard output:<br />
<br />
:dons!i=dons@my.net PRIVMSG #tutbot-testing :hello<br />
<br />
We can now implement some commands.<br />
<br />
== A simple interpreter ==<br />
<br />
Add these additional imports before changing the <hask>listen</hask> function.<br />
<br />
<haskell><br />
import Data.List<br />
import System.Exit<br />
</haskell><br />
<br />
<haskell><br />
listen :: Handle -> IO ()<br />
listen h = forever $ do<br />
t <- hGetLine h<br />
let s = init t<br />
if ping s then pong s else eval h (clean s)<br />
putStrLn s<br />
where<br />
forever a = a >> forever a<br />
<br />
clean = drop 1 . dropWhile (/= ':') . drop 1<br />
<br />
ping x = "PING :" `isPrefixOf` x<br />
pong x = write h "PONG" (':' : drop 6 x)<br />
</haskell><br />
<br />
We add 3 features to the bot here by modifying <hask>listen</hask>.<br />
Firstly, it responds to <hask>PING</hask> messages: <hask>if ping s then pong s ... </hask>.<br />
This is useful for servers that require pings to keep clients connected.<br />
Before we can process a command, remember the IRC protocol generates<br />
input lines of the form:<br />
<haskell><br />
:dons!i=dons@my.net PRIVMSG #tutbot-testing :!id foo<br />
</haskell><br />
so we need a <hask>clean</hask> function to simply drop the leading ':'<br />
character, and then everything up to the next ':', leaving just the<br />
actual command content. We then pass this cleaned up string to<br />
<hask>eval</hask>, which then dispatches bot commands.<br />
<br />
<haskell><br />
eval :: Handle -> String -> IO ()<br />
eval h "!quit" = write h "QUIT" ":Exiting" >> exitWith ExitSuccess<br />
eval h x | "!id " `isPrefixOf` x = privmsg h (drop 4 x)<br />
eval _ _ = return () -- ignore everything else<br />
</haskell><br />
<br />
So, if the single string "!quit" is received, we inform the server and<br />
exit the program. If a string beginning with "!id" appears, we echo any argument<br />
string back to the server (<hask>id</hask> is the Haskell identity<br />
function, which just returns its argument). Finally, if no other matches<br />
occur, we do nothing.<br />
<br />
We add the <hask>privmsg</hask> function - a useful wrapper over<br />
<hask>write</hask> for sending <hask>PRIVMSG</hask> lines to the server.<br />
<br />
<haskell><br />
privmsg :: Handle -> String -> IO ()<br />
privmsg h s = write h "PRIVMSG" (chan ++ " :" ++ s)<br />
</haskell><br />
<br />
Here's a transcript from our minimal bot running in channel:<br />
<br />
15:12 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:13 dons> !id hello, world!<br />
15:13 tutbot> hello, world!<br />
15:13 dons> !id very pleased to meet you.<br />
15:13 tutbot> very pleased to meet you.<br />
15:13 dons> !quit<br />
15:13 -- tutbot [n=tutbot@aa.bb.cc.dd] has quit [Client Quit]<br />
<br />
Now, before we go further, let's refactor the code a bit.<br />
<br />
== Roll your own monad ==<br />
<br />
A small annoyance so far has been that we've had to thread around our<br />
socket to every function that needs to talk to the network. The socket<br />
is essentially <em>immutable state</em>, that could be treated as a<br />
global read only value in other languages. In Haskell, we can implement<br />
such a structure using a state <em>monad</em>. Monads are a very powerful<br />
abstraction, and we'll only touch on them here. The interested reader is<br />
referred to [http://www.haskell.org/all_about_monads/html/index.html All About Monads]. We'll be<br />
using a custom monad specifically to implement a read-only global state<br />
for our bot.<br />
<br />
The key requirement is that we wish to be able to perform IO actions,<br />
as well as thread a small state value transparently through the program.<br />
As this is Haskell, we can take the extra step of partitioning our<br />
stateful code from all other program code, using a new type. <br />
<br />
So let's define a small state monad:<br />
<haskell><br />
data Bot = Bot { socket :: Handle }<br />
<br />
type Net = ReaderT Bot IO<br />
</haskell><br />
<br />
Firstly, we define a data type for the global state. In this case, it is<br />
the <hask>Bot</hask> type, a simple struct storing our network socket.<br />
We then layer this data type over our existing IO code, with a <em>monad<br />
transformer</em>. This isn't as scary as it sounds and the effect is<br />
that we can just treat the socket as a global read-only value anywhere<br />
we need it. We'll call this new io + state structure the<br />
<hask>Net</hask> monad. <hask>ReaderT</hask> is a <em>type<br />
constructor</em>, essentially a type function, that takes 2 types as<br />
arguments, building a result type: the <hask>Net</hask> monad type.<br />
<br />
We can now throw out all that socket threading and just grab the socket<br />
when we need it. The key steps are connecting to the server, followed by<br />
the initialisation of our new state monad and then to run the main bot loop<br />
with that state. We add a small function, which takes the intial bot<br />
state and evaluates the bot's <hask>run</hask> loop "in" the Net monad,<br />
using the Reader monad's <hask>runReaderT</hask> function:<br />
<br />
<haskell><br />
loop st = runReaderT run st<br />
</haskell><br />
<br />
where <hask>run</hask> is a small function to register the bot's nick,<br />
join a channel, and start listening for commands.<br />
<br />
While we're here, we can tidy up the main function a little by using<br />
<hask>Control.Exception.bracket</hask> to explicitly delimit the<br />
connection, shutdown and main loop phases of the program - a useful<br />
technique. We can also make the code a bit more robust by wrapping the<br />
main loop in an exception handler using <hask>catch</hask>:<br />
<br />
<haskell><br />
main :: IO ()<br />
main = bracket connect disconnect loop<br />
where<br />
disconnect = hClose . socket<br />
loop st = catch (runReaderT run st) (const $ return ())<br />
</haskell><br />
<br />
That is, the higher order function <hask>bracket</hask> takes 3<br />
arguments: a function to connect to the server, a function to<br />
disconnect and a main loop to run in between. We can use<br />
<hask>bracket</hask> whenever we wish to run some code before and after<br />
a particular action - like <hask>forever</hask>, this is another<br />
control structure implemented as a normal Haskell function.<br />
<br />
Rather than threading the socket around, we can now simply ask for it<br />
when needed. Note that the type of <hask>write</hask> changes - it is in<br />
the Net monad, which tells us that the bot must already by connected to<br />
a server (and thus it is ok to use the socket, as it is initialised).<br />
<br />
<haskell><br />
--<br />
-- Send a message out to the server we're currently connected to<br />
--<br />
write :: String -> String -> Net ()<br />
write s t = do<br />
h <- asks socket<br />
io $ hPrintf h "%s %s\r\n" s t<br />
io $ printf "> %s %s\n" s t<br />
</haskell><br />
<br />
In order to use both state and IO, we use the small <hask>io</hask><br />
function to <em>lift</em> an IO expression into the Net monad making<br />
that IO function available to code in the <hask>Net</hask> monad.<br />
<br />
<haskell><br />
io :: IO a -> Net a<br />
io = liftIO<br />
</haskell><br />
<br />
Similarly, we can combine IO actions with pure functions by lifting<br />
them into the IO monad. We can therefore simplify our <hask>hGetLine</hask><br />
call:<br />
<haskell><br />
do t <- io (hGetLine h)<br />
let s = init t<br />
</haskell><br />
by lifting <hask>init</hask> over IO:<br />
<haskell><br />
do s <- init `fmap` io (hGetLine h)<br />
</haskell><br />
<br />
The monadic, stateful, exception-handling bot in all its glory:<br />
<br />
<haskell><br />
import Data.List<br />
import Network<br />
import System.IO<br />
import System.Exit<br />
import Control.Monad.Reader<br />
import Control.Exception<br />
import Text.Printf<br />
import Prelude hiding (catch)<br />
<br />
server = "irc.freenode.org"<br />
port = 6667<br />
chan = "#tutbot-testing"<br />
nick = "tutbot"<br />
<br />
-- The 'Net' monad, a wrapper over IO, carrying the bot's immutable state.<br />
type Net = ReaderT Bot IO<br />
data Bot = Bot { socket :: Handle }<br />
<br />
-- Set up actions to run on start and end, and run the main loop<br />
main :: IO ()<br />
main = bracket connect disconnect loop<br />
where<br />
disconnect = hClose . socket<br />
loop st = catch (runReaderT run st) (const $ return ())<br />
<br />
-- Connect to the server and return the initial bot state<br />
connect :: IO Bot<br />
connect = notify $ do<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
return (Bot h)<br />
where<br />
notify a = bracket_<br />
(printf "Connecting to %s ... " server >> hFlush stdout)<br />
(putStrLn "done.")<br />
a<br />
<br />
-- We're in the Net monad now, so we've connected successfully<br />
-- Join a channel, and start processing commands<br />
run :: Net ()<br />
run = do<br />
write "NICK" nick<br />
write "USER" (nick++" 0 * :tutorial bot")<br />
write "JOIN" chan<br />
asks socket >>= listen<br />
<br />
-- Process each line from the server<br />
listen :: Handle -> Net ()<br />
listen h = forever $ do<br />
s <- init `fmap` io (hGetLine h)<br />
io (putStrLn s)<br />
if ping s then pong s else eval (clean s)<br />
where<br />
forever a = a >> forever a<br />
clean = drop 1 . dropWhile (/= ':') . drop 1<br />
ping x = "PING :" `isPrefixOf` x<br />
pong x = write "PONG" (':' : drop 6 x)<br />
<br />
-- Dispatch a command<br />
eval :: String -> Net ()<br />
eval "!quit" = write "QUIT" ":Exiting" >> io (exitWith ExitSuccess)<br />
eval x | "!id " `isPrefixOf` x = privmsg (drop 4 x)<br />
eval _ = return () -- ignore everything else<br />
<br />
-- Send a privmsg to the current chan + server<br />
privmsg :: String -> Net ()<br />
privmsg s = write "PRIVMSG" (chan ++ " :" ++ s)<br />
<br />
-- Send a message out to the server we're currently connected to<br />
write :: String -> String -> Net ()<br />
write s t = do<br />
h <- asks socket<br />
io $ hPrintf h "%s %s\r\n" s t<br />
io $ printf "> %s %s\n" s t<br />
<br />
-- Convenience.<br />
io :: IO a -> Net a<br />
io = liftIO<br />
</haskell><br />
<br />
Note that we threw in a new control structure, <hask>notify</hask>, for<br />
fun. Now we're almost done! Let's run this bot. Using runhaskell:<br />
<br />
$ runhaskell 4.hs<br />
<br />
or using GHC:<br />
<br />
$ ghc --make 4.hs -o tutbot<br />
Chasing modules from: 4.hs<br />
Compiling Main ( 4.hs, 4.o )<br />
Linking ...<br />
$ ./tutbot<br />
<br />
If you're using Hugs, you'll have to use the <hask>-98</hask> flag:<br />
<br />
$ runhugs -98 4.hs<br />
<br />
And from an IRC client we can watch it connect:<br />
<br />
15:26 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
15:28 dons> !id all good?<br />
15:28 tutbot> all good?<br />
15:28 dons> !quit<br />
15:28 -- tutbot [n=tutbot@aa.bb.cc.dd] has quit [Client Quit]<br />
<br />
So we now have a bot with explicit read-only monadic state, error<br />
handling, and some basic IRC operations. If we wished to add read-write<br />
state, we need only change the <hask>ReaderT</hask> transformer to<br />
<hask>StateT</hask>.<br />
<br />
== Extending the bot ==<br />
<br />
Let's implement a basic new command: uptime tracking. Conceptually, we<br />
need to remember the time the bot starts. Then, if a user requests, we<br />
work out the total running time and print it as a string. A nice way to<br />
do this is to extend the bot's state with a start time field:<br />
<br />
<haskell><br />
import System.Time<br />
</haskell><br />
<br />
<haskell><br />
data Bot = Bot { socket :: Handle, starttime :: ClockTime }<br />
</haskell><br />
<br />
We can then modify the initial <hask>connect</hask> function to also set<br />
the start time.<br />
<br />
<haskell><br />
connect :: IO Bot<br />
connect = notify $ do<br />
t <- getClockTime<br />
h <- connectTo server (PortNumber (fromIntegral port))<br />
hSetBuffering h NoBuffering<br />
return (Bot h t)<br />
</haskell><br />
<br />
We then add a new case to the <hask>eval</hask> function, to handle<br />
uptime requests:<br />
<br />
<haskell><br />
eval "!uptime" = uptime >>= privmsg<br />
</haskell><br />
<br />
This will just run the <hask>uptime</hask> function and send it back to<br />
the server. <hask>uptime</hask> itself is:<br />
<br />
<haskell><br />
uptime :: Net String<br />
uptime = do<br />
now <- io getClockTime<br />
zero <- asks starttime<br />
return . pretty $ diffClockTimes now zero<br />
</haskell><br />
<br />
That is, in the Net monad, find the current time and the start time, and<br />
then calculate the difference, returning that number as a string.<br />
Rather than use the normal representation for dates, we'll write our own<br />
custom formatter for dates:<br />
<br />
<haskell><br />
--<br />
-- Pretty print the date in '1d 9h 9m 17s' format<br />
--<br />
pretty :: TimeDiff -> String<br />
pretty td = join . intersperse " " . filter (not . null) . map f $<br />
[(years ,"y") ,(months `mod` 12,"m")<br />
,(days `mod` 28,"d") ,(hours `mod` 24,"h")<br />
,(mins `mod` 60,"m") ,(secs `mod` 60,"s")]<br />
where<br />
secs = abs $ tdSec td ; mins = secs `div` 60<br />
hours = mins `div` 60 ; days = hours `div` 24<br />
months = days `div` 28 ; years = months `div` 12<br />
f (i,s) | i == 0 = []<br />
| otherwise = show i ++ s<br />
</haskell><br />
<br />
And that's it. Running the bot with this new command:<br />
<br />
16:03 -- tutbot [n=tutbot@aa.bb.cc.dd] has joined #tutbot-testing<br />
16:03 dons> !uptime<br />
16:03 tutbot> 51s<br />
16:03 dons> !uptime<br />
16:03 tutbot> 1m 1s<br />
16:12 dons> !uptime<br />
16:12 tutbot> 9m 46s<br />
<br />
== Where to now? ==<br />
<br />
This is just a flavour of application programming in Haskell, and only<br />
hints at the power of Haskell's lazy evaluation, static typing, monadic<br />
effects and higher order functions. There is much, much more to be said<br />
on these topics. Some places to start:<br />
<br />
* The [[/Source|complete bot source]] (also [http://www.cse.unsw.edu.au/~dons/irc/bot.html mirrored here])<br />
* A [[/Transcript|full transcript]].<br />
* [[Haskell|Haskell.org]]<br />
* [[Example_code|More Haskell code]]<br />
* [[Books and tutorials|Learning Haskell]]<br />
* A gallery of [[Libraries_and_tools/Network|network apps]] in Haskell<br />
<br />
Or take the bot home and hack! Some suggestions:<br />
* Use <hask>forkIO</hask> to add a command line interface, and you've got yourself an irc client with 4 more lines of code.<br />
* Port some commands from [[Lambdabot]].<br />
<br />
Author: [http://www.cse.unsw.edu.au/~dons Don Stewart]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Code]]</div>Weihuhttps://wiki.haskell.org/index.php?title=Haskell_in_education&diff=15287Haskell in education2007-08-28T02:14:10Z<p>Weihu: Fixed a link</p>
<hr />
<div>[[Category:Education]]<br />
This is a collection of material of interest to those teaching or<br />
taking courses that use Haskell. There is also a more general site,<br />
http://www.cs.kun.nl/fple/, devoted to all functional languages. The proceedings of the latest<br />
[http://www.informatik.uni-kiel.de/~mh/publications/reports/fdpe02/ International Workshop on Functional and Declarative Programming in Education (FDPE)] are now available.<br />
Some of the lecture notes and<br />
other course material found in these web pages are excellent<br />
supplements to the available text books.<br />
If you would like to use lecture<br />
notes, assignments, or other material found in these course web pages<br />
please contact the author for permission.<br />
<br />
Most of the entries are years old. When you add your own new<br />
material to this page, please also say when the course was run for the last time.<br />
<br />
The results of a survey of university courses using Haskell in the academic year 2005-2006 can be found [http://www.cs.chalmers.se/~rjmh/Wash/Survey/teaching.htm here]. Also, some news were added during the 2006-2007 academic year.<br />
<br />
== Haskell as a first language ==<br />
<br />
These courses teach Haskell to students with no background in programming.<br />
<br />
<b>Instructor:</b> [mailto:page@ou.edu Rex Page] <br />
University of<br />
Oklahoma<br><br />
<b>Course:</b> Introduction to Computer Programming<br><br />
<b>Student background:</b> High-school mathematics<br><br />
<b>Materials:</b> Projects, Exams, Downloadable textbook: Rex Page, <br />
&quot;Two<br />
Dozen Short Lessons in Haskell&quot;<br><br />
<b>Web page:</b> http://www.cs.ou.edu/~rlpage/fpclassSpring97/<br />
<br />
<b>Comments:</b><br />
<blockquote><br />
These materials arose from a course offered for three consecutive<br />
semesters as<br />
an alternative to our usual first course in programming. Most of the<br />
students<br />
who took the course graduated in the past two years, and many of them<br />
cited it<br />
in the exit interview with the department chair as the most influential<br />
course<br />
in the entire academic career.<br />
<p>All materials for two offerings of the course are available through<br />
the web<br />
page. This includes individual projects, team projects, project<br />
solutions,<br />
exams, supplied software (connected with certain projects), tips for<br />
students<br />
taking the course, FAQs addressing questions that students asked during<br />
the<br />
semester, and a short textbook which served as the primary text in the<br />
course.</p><br />
<p>The first 10 to 11 weeks of the course use Haskell. Students are<br />
required to<br />
write nine programs in Haskell, three of which are team projects that<br />
combine<br />
software developed in individual projects. Different members of a team<br />
are<br />
assigned different individual projects, and the team efforts combine<br />
their<br />
solutions into a working piece of software.</p><br />
<p>In the early part of the course, students use operators like map,<br />
foldr, zip,<br />
and iterate to express computations. Explicit recursion is introduced<br />
after some<br />
experience with these common patterns of computation. Examples and<br />
problems<br />
address non-numeric applications, for the most part. Both interactive<br />
and file<br />
I/O are covered, but general purpose monads are not.</p><br />
<p>The last 5 to 6 weeks of the course use C, and most of the projects<br />
in that<br />
part of the course duplicate the function of earlier pieces of software<br />
that the<br />
students have written in Haskell.</p><br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:Jonathan.Hill@comlab.ox.ac.uk Jonathan Hill]<br />
Oxford University Computing Laboratory<br><br />
<b>Course:</b> Functional Programming for the Integrated Graduate Development Programme in Software Engineering at Oxford University.<br><br />
<b>Student background:</b> Discrete mathematics (the course is a part time MSc for people from industry; most are from IBM or Nortel).<br><br />
<b>Materials:</b> Gofer (an old version, with a stripped down prelude---no parameter classes!); Own course material<br><br />
<b>Web page:</b> http://www.comlab.ox.ac.uk/igdp/text/course06.html<br />
Note: Web pages not accessible. May be ... moved ? <br />
<br />
<br />
<b>Instructor:</b> [mailto:gmh@cs.nott.ac.uk Graham Hutton]<br />
Department of Computer Science, University of Nottingham<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> None<br><br />
<b>Materials:</b> Hugs 1.3; Richard Bird, Introduction to Functional Programming using Haskell (second edition), Prentice Hall, 1998. Handwritten slides and exercises; copies available on request.<br><br />
<b>Web page:</b> http://www.cs.nott.ac.uk/Modules/9899/G51FUN.html<br />
<br />
<br />
<b>Instructor:</b> [mailto:prins@cs.unc.edu" Jan Prins]<br />
UNC Chapel Hill<br><br />
<b>Course:</b> Introduction to Functional Programming<br><br />
<b>Student background:</b> solid background in high-school science and mathematics<br><br />
<b>Materials:</b> Hugs 1.4 incl. Active Haskell, FRAN and Haskore; Simon Thompson, "Haskell: The Art of Functional Programming"<br><br />
<b>Web page:</b> http://www.cs.unc.edu/~prins/Classes/15/<br><br />
<b>Comments:</b><br />
<blockquote><br />
(Introductory programming course for CS and math/science majors, typically Freshman and Sophomores. Class size ~60)<br />
<br />
Our undergraduate computing environment is now largely<br />
PCs running Windows NT. We use NTEmacs as the programming<br />
environment with a slightly modified version of Emacs hugs<br />
mode with hugs running as a subprocess. The combined<br />
hugs/NTEmacs/Active Haskell distribution (available through<br />
course home page) is installed on 400+ public Win NT machines<br />
on campus and some unknown number of student-owned Win 95/98<br />
machines.<br />
<br />
This arrangement is new this semester, but so far has been<br />
working well. Keystroke-oriented interactive applications<br />
may be problematic with hugs running in NTEmacs shell mode.<br />
<br />
I'm planning assignments using Fran and Active Haskell and<br />
will try teaching the "brief introduction to imperative<br />
programming" at the end of the class using monads. I would<br />
be interested in talking with anyone who has experience or<br />
suggestions along these lines.<br />
<br />
I took a cue from Paul Hudak and others and have occasional<br />
appearances of MS Agents during lectures to wake students up!<br />
<br />
This is my first time teaching this course, and I would<br />
enjoy talking to others teaching at a similar level. A<br />
cursory search on the web didn't reveal many courses<br />
in this category.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:dave@cs.chalmers.se David Sands]<br />
University of Gothenburg & Chalmers University of Technology<br><br />
<b>Course:</b> Programmering för Naturvetare<br><br />
<b>Student background:</b> New students<br><br />
<b>Materials:</b> hugs 1.4; Simon Thompson<br><br />
<b>Web page:</b> http://www.md.chalmers.se/Cs/Grundutb/Kurser/nptah/<br><br />
<b>Comments:</b><br />
<blockquote><br />
This is the first part of a first course in programming. About 16<br />
lectures, each 2x45 mins plus weekly exercise classes and three<br />
assessed programming exercises. Most of my materials are in English.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:M.A.Rodrigues@dcs.hull.ac.uk Marcos A Rodrigues]<br />
The University of Hull, Hull, UK<br><br />
<b>Course:</b> Functional and Logic Programming<br><br />
<b>Student background:</b> none<br><br />
<b>Materials:</b> hugs 1.4; Haskell: the Craft of Functional Programming. Thompson S., Addison Wesley, 1996.<br><br />
<br />
<b>Instructor:</b> [mailto:Torsten.Grust@uni-konstanz.de Torsten Grust]<br />
University of Konstanz (Germany)<br> <br />
<b>Course:</b> Deklarative Programmierung (Declarative Programming, in german)<br><br />
<b>Student background:</b> basic math, no programming background required<br><br />
<b>Materials:</b> Hugs 1.4; (~300) slides available from the course web page;<br />
Jeroen Fokker's classroom text: Functional Programming<br />
http://www.cs.uu.nl/~jeroen/courses/fp-eng.ps.gz</a>;<br />
Richard Bird, Phil Wadler: Introduction to Functional Programming; Simon Peyton-Jones: Implementation of Functional Programming Languages<br><br />
<b>Web page:</b> http://www.fmi.uni-konstanz.de/dbis/Courses-old/Courses-ss98/decl-ss98.html<br><br />
<b>Comments:</b><br />
<blockquote><br />
The course is in German only (sorry about that). It additionally<br />
features an introduction to logical programming and Prolog.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:richardb@cse.unsw.edu.au Richard Buckland]<br />
University of New South Wales<br><br />
<b>Course:</b> Computing 1A<br><br />
<b>Student background:</b> Mixed, some have no computing<br />
background. This is our cs1 subject.<br><br />
<b>Materials:</b> Hugs 1.4; Simon Thompson<br><br />
<b>Web page:</b> http://www.cse.unsw.edu.au/~cs1011<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:robert@techfak.uni-bielefeld Robert Giegerich], Stefan Posch, University Bielefeld, Germany<br><br />
<b>Course:</b> Introduction to Computer Science<br><br />
<b>Student background:</b> Completed High School (Abitur)<br><br />
<b>Materials:</b> Hugs; Class Notes by Robert Giegerich and Ralf Hinze<br><br />
<b>Comments:</b><br />
<blockquote><br />
Our first semester course<br />
uses Haskell as a vehicle to fundamental aspects of computation:<br />
algorithmics, specification and verification, efficiency analysis,<br />
programming methods. This works wonderfully. We do not require previous<br />
or additional programming experience. Haskell is quickly learned, <br />
to the necessary degreee; we make no attempt to cover the full language.<br />
This is NOT a Haskell course! Haskell allows us to speak about concepts<br />
of computer science WITHOUT a lot of language learning. And Haskell<br />
even helps to keep out detrimental habits from previous programming<br />
experience, as well as motivational problems resulting from the widely<br />
differing previous experiences of our incoming students.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:hj@sm.luth.se Håkan Jonsson] Luleå University of Technology, Sweden<br><br />
<b>Course:</b> SMD001, functional programming<br><br />
<b>Student background:</b> <br />
None. This is the very first programming course <br />
our students take.<br><br />
<b>Materials:</b> <br />
Materials: Simon Thompson's Haskell book + 7 laboratory/programming <br />
assignments using Hugs.<br />
<br><br />
<b>Web page:</b>http://www.sm.luth.se/csee/courses/smd/001/ (mostly Swedish)<br> <br />
<br />
<br />
<b>Instructor:</b> [mailto:Clem.Baker-Finch@cs.anu.edu.au Clem Baker-Finch, Australian National University<br><br />
<b>Course:</b>CE1 <br><br />
<b>Student background:</b> No programming background was<br />
assumed.<br />
<br><br />
<b>Materials:</b> Based on Haskell 1.3; Hugs; Simon Thompson 1st ed. <br />
<br><br />
<b>Web page:</b> http://cs.anu.edu.au/~Clem.Baker-Finch/CE1/<br> <br />
<b>Comments:</b><br />
<blockquote><br />
The forces of evil (the O-O crowd) prevailed in<br />
the programming languages argument and it hasn't been taught since. <br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:lyndon@cs.uwa.edu.au Lyndon While] The University of Western Australia<br><br />
<b>Course:</b> Foundations of Computer Science<br><br />
<b>Student background:</b> None<br><br />
<b>Materials:</b> hugs 98; Thompson.<br><br />
<b>Web page:</b> http://undergraduate.cs.uwa.edu.au/courses/230.123<br><br />
<br />
<br />
----<br />
<br />
== Haskell as a second language ==<br />
<br />
These courses teach Haskell to students that have already learned<br />
another language.<br />
<br />
<b>Instructor:</b> [mailto:page@ou.edu Rex Page]<br />
University of Oklahoma<br><br />
<b>Course:</b> Discrete Mathematics<br><br />
<b>Student background:</b> High-school mathematics, introductory programming<br />
course (any language)<br><br />
<b>Materials:</b> Lecture notes, Projects, Exams, Solutions, Proof checking<br />
tools, etc.; text: Hall and O'Donnell, &quot;Discrete Mathematics with a<br />
Computer&quot;<br><br />
<br />
<b>Web page:</b> http://www.cs.ou.edu/~beseme/<br><br />
<b>Comments:</b><br />
<blockquote><br />
Lecture notes comprise over 350 animated slides (all both PowerPoint and<br />
PDF<br />
formats). About two-thirds of the material centers around mathematical logic.<br />
After the introduction of predicates, all of the examples in the logic<br />
portion<br />
of the course involve reasoning about properties of software, most of which is<br />
expressed in Haskell (a few are conventional looping functions).<br />
<p>Software examples include sum, sequence concatenation, logical operations on<br />
sequences, the Russian peasant algorithm, insertion and lookup in AVL <br />
trees, and<br />
other computations. Most of the properties verified relate to aspects of <br />
program<br />
correctness, but resource utilization properties are also verified in <br />
some<br />
cases. Several semesters worth of exams (finals and exams given during <br />
the term)<br />
are provided. The slides have matured through several offerings of the course.</p><br />
<p>The remaining third of the course discusses other standard topics<br />
in discrete<br />
mathematics, such as sets, functions, relations, trees, and counting.<br />
The web<br />
page provides access to a preview of the material. Exams and solutions are<br />
protected by a login procedure (to increase the comfort level of<br />
instructors<br />
wishing to use them in courses). The web page provides a link through<br />
which<br />
instructors may gain access to the full website.</p><br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:labra@lsi.uniovi.es Jose Emilio Labra Gayo],<br />
Dept. of Computer Science (EUITIO) University of Oviedo<br><br />
<b>Course:</b> Logic and Functional Programming<br><br />
<b>Student background:</b> The course is oriented towards third year undergraduate students in computer science. Usually, the students have been<br />
introduced to imperative languages like Pascal and Object <br />
Oriented Languages like C++<br><br />
<b>Materials:</b> Hugs; R. Bird "Introd. to FP using Haskell" (2nd Ed), J. E. Labra Gayo. "Introduction to the Haskell Language" (in spanish).<br><br />
<b>Web page:</b> http://lsi.uniovi.es/~labra/plf.html (in spanish).<br />
My FP page: http://lsi.uniovi.es/~labra/FuncProg.html<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:fruehr@willamette.edu Fritz Ruehr]<br />
Willamette University, Salem, Oregon, USA (a small Liberal Arts College, about 1 hour from Portland & OGI)<br><br />
<b>Course:</b> CS 451 Topics in Computer Science: Functional Programming<br><br />
<b>Student background:</b> Data structures (I may also have required discrete math)<br><br />
<b>Materials:</b> Hugs 1.4 beta (I also taught Scheme); Haskell: The Craft of Functional Programming by Simon Thompson (I also used my own on-line lecture notes and labs and Kent Dybvig's text on Scheme)<br><br />
<b>Web page:</b> http://www.willamette.edu/~fruehr/451/<br><br />
<b>Comments:</b><br />
<blockquote><br />
The notes and labs I have on-line are in pretty rough form: many slide <br />
points are just one-line topical stubs I used as reminders in lecture.<br />
Many of the on-line materials are not linked into the (out of date)<br />
home page.<br />
<br />
I hope to have the course approved for next Fall as a regular offering<br />
(i.e., not as a "special topic") and should have more extensive<br />
on-line materials up by then.<br />
<br />
Teaching "bi-lingually" in Haskell and Scheme seemed like a good idea<br />
at the time, but next time around I will use Haskell as the main vehicle,<br />
perhaps taking some time near the end of the course to highlight some<br />
other languages (Scheme, ML, Clean).<br />
<br />
Some of my students used Conal Elliot's Fran and Paul Hudak's Haskore<br />
and liked them a lot; I was nice to have some significantly-sized<br />
applications that seemed more practical and fun to show off at the end<br />
of the course (I should have demonstrated these things at the beginning<br />
of the course to help with motivation). Next time around I would like to<br />
have a "beginner's prelude" or similar available to avoid problems with<br />
classes in type inference, Int vs. Integer, etc. These problems were a<br />
constant annoyance during lectures.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:J.Hamer@cs.auckland.ac.nz John Hamer],<br />
University of Auckland<br><br />
<b>Course:</b> Logic and Functional Programming<br><br />
<b>Student background:</b> Year 2 programming + some discrete maths<br><br />
<b>Materials:</b> Hugs 98, Haskell School of Expression, Page "Two Dozen Short Lessons in Haskell",<br><br />
<b>Web page:</b> http://www.cs.auckland.ac.nz/compsci360fc<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:ham@cs.utexas.edu Hamilton Richards],<br />
University of Teaxs at Austin<br><br />
<b>Course:</b> CS307 Foundations of Computer Science<br><br />
<b>Student background:</b> (1) A score of at least 560 on the SAT<br />
II Subject Test in Mathematics Level I or Level IC, or a score of at least<br />
530 on the SAT II Subject Test in Mathematics Level IIC, or a grade of at<br />
least C in Mathematics 305G (pre-calculus); (2) One year of programming in<br />
high school, or a grade of at least C in CS 304P (an introductory course<br />
that does not count for credit towards a CS degree), or consent of<br />
instructor.<br><br />
<b>Materials:</b> Hugs 98; Simon Thompson, Haskell: The Craft of<br />
Functional Programming. <br><br />
<b>Web page:</b> http://www.cs.utexas.edu/users/ham/UTCS/CS307/<br><br />
<b>Comments:</b><br />
<blockquote><br />
Students who succeed in this<br />
course are well prepared for the rest of our CS curriculum, which is more<br />
theoretical than most.<br />
</blockquote><br />
<br />
<b>Instructor:</b> [mailto:lengauer@fmi.uni-passau.de Chris Lengauer]<br />
University of Passau<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> two years of CS study<br><br />
<b>Materials:</b> hugs; Richard Bird's new text (PHI)<br><br />
<b>Web page:</b> not reachable from outside Passau<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:cunningham@cs.olemiss.edu Conrad Cunningham]<br />
University of Mississippi<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> official -- senior or graduate standing; actual -- introductory programming, data structures, and discrete math<br><br />
<b>Materials:</b> Hugs on Unix and MS Windows systems;<br />
Mostly use the instructor's own set of lecture notes. Also Simon Thompson's HASKELL: THE CRAFT OF FUNCTIONAL PROGRAMMING. Previously used the Bird and Wadler textbook<br><br />
<b>Web page:</b> http://www.cs.olemiss.edu/~hcc/csci555/<br><br />
<b>Comments:</b><br />
<blockquote><br />
Although I am not a researcher in FP, I enjoy teaching the FP course.<br />
Most of the students take to the course after a few weeks. Hugs works<br />
reasonably well, but, of course, more pedagogically oriented error messages<br />
and other support tools would be helpful.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:leavens@cs.iastate.edu Gary T. Leavens],<br />
Iowa State University<br><br />
<b>Course:</b> Programming Languages 1<br><br />
<b>Student background:</b> undergraduate course in compilers or programming languaages<br><br />
<b>Materials:</b> Hugs 1.4; Thompson's Haskell: The Craft of Programming<br><br />
<b>Web page:</b> http://www.cs.iastate.edu/~leavens/ComS541.html<br><br />
<b>Comments:</b><br />
<blockquote><br />
Be sure to tell your students how to debug programs.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:jtod@dcs.gla.ac.uk John O'Donnell]<br />
University of Glasgow<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> Programming (in Ada), Algorithmic Foundations<br><br />
<b>Materials:</b> Hugs; Simon Thompson's book on Haskell<br><br />
<b>Web page:</b> http://www.dcs.gla.ac.uk/courses/teaching/level2/modules/#FP2<br><br />
<br />
<b>Instructor:</b> [mailto:chitil@informatik.rwth-aachen.de Olaf Chitil],<br />
RWTH Aachen, Germany<br><br />
<b>Course:</b> Functional Programming in Haskell<br><br />
<b>Student background:</b> basic programming skills (not necessarily in a<br />
functional language)<br><br />
<b>Materials:</b> Hugs 1.4; Hugs user manual, slide copies;<br />
additionally the `Gentle Introduction to Haskell', probably Bird's `Introduction<br />
to Functional Programming using Haskell' in the future.<br><br />
<b>Web page:</b> http://www-i2.informatik.rwth-aachen.de/Praktikum/SWP/ (in German)<br><br />
<b>Comments:</b><br />
<blockquote><br />
The course starts with 4 full time days of learning Haskell. During the semester<br />
the students (in groups of 2 students) have to implement a compiler and an<br />
abstract machine for a simple imperative language. They are given parts of the<br />
system and a manual on how to do the remaining parts (they have no prior<br />
knowledge on compiler construction).<br />
The most difficult construct for students to understand is the monad. I<br />
introduce IO without mentioning monads. Later I explain how to build a simple<br />
exception handling system based on the type `Maybe a' / `Error a'. Only<br />
subsequently I give the general definition of monads and present the list monad<br />
and a simple state monad. However, I fear that just to understand the bind<br />
operator `>>=' requires people to be quite comfortable with higher-order<br />
functions.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [http://web.comlab.ox.ac.uk/oucl/people/richard.bird.html Richard Bird], Oxford Brookes University<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> Elementary structured programming<br><br />
<b>Web page:</b> http://web.comlab.ox.ac.uk/oucl/courses/topics00-01/fp/<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:paul.hudak@yale.edu Paul Hudak],<br />
Yale University, Dept of Computer Science<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> at least one programming course<br><br />
<b>Materials:</b> Hugs; my own textbook, which is under preparation<br><br />
<b>Web page:</b> none<br><br />
<br />
<br />
<b>Instructor:</b> [mailto:abf@cs.ucc.ie Alex Ferguson]<br />
University College Cork<br><br />
<b>Course:</b> Functional and Logic Programming<br><br />
<b>Student background:</b> Final year undergraduate<br />
<br><br />
<b>Materials:</b> Final year undergraduate<br />
Materials: Hugs 98; ghc; Simon Thompson, "Haskell: The Craft of<br />
Functional Programming" (2nd ed.)<br />
<br><br />
<b>Web page:</b> http://yeats.ucc.ie/~abf/CS4001/<br> <br />
<b>Comments:</b><br />
<blockquote><br />
This is the declarative programming option for 4th year<br />
undergrads, who have Java as a first programming language, and some<br />
knowledge of C and C++. The current final year have had some exposure<br />
to Haskell in first year, though this is no longer the case for our<br />
current intake.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:lky@nada.kth.se Leif Kusoffsky],<br />
Royal Institute of Technology, Stockholm<br><br />
<b>Course:</b> Functional Programming 2D1370<br><br />
<b>Student background:</b> The course is oriented towards third year<br />
undergraduate students in computer science. The students<br />
have been introduced to imperative languages like<br />
C and Object Oriented Languages like Java<br />
<br><br />
<b>Materials:</b> Hugs; Hudak : The Haskell School of Expression<br />
<br><br />
<br />
<br />
<b>Instructor:</b> Jeremy Bobbio -- INSIA<br><br />
<b>Course:</b> Functional and Logic Programming<br><br />
<b>Student background:</b> One year CS<br />
<br><br />
<b>Materials:</b> <br />
Hugs, GHC, Paul Hudak's Haskell School of Education<br />
<br><br />
<b>Web page:</b> http://etudiants.insia.org/~jbobbio/pafp/ (french)<br> <br />
<br />
<br />
<b>Instructor:</b> [mailto:antkaij@mit.jyu.fi Antti-Juhani Kaijanaho]<br />
University of Jyväskylä<br><br />
<b>Course:</b> Functional Programming 1 & 2<br><br />
<b>Student background:</b> third-year undergraduate and up<br />
<br><br />
<b>Materials:</b><br />
GHC, Gtk2HS<br />
<br><br />
<b>Web page:</b> [http://www.mit.jyu.fi/antkaij/opetus/fo/2005-2006/index.en.html]<br />
<br><br />
<b>Last run:</b> 2005&ndash;2006<br />
<br><br />
<!--<b>Comments:</b><br />
<blockquote><br />
(I'll write this later)<br />
</blockquote>--><br />
<br />
<b>Instructor:</b> [mailto:djd@comp.leeds.ac.uk David Duke]<br />
University of Leeds, School of Computing<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> Second and third year undergraduate<br />
<br><br />
<b>Materials:</b> ghc; Graham Hutton "Programming in Haskell"<br />
<br><br />
<b>Web page:</b> www.comp.leeds.ac.uk/se23/<br> <br />
<b>Comments:</b><br />
<blockquote><br />
This is an optional course that students currently can take in <br />
second or third year (from 2008/9 it will be third-years only).<br />
Students will have previously used Python and Java.<br />
Although the emphasis is on learning to solve problems within<br />
the functional paradigm, and how to develop solutions within<br />
Haskell, I also like to show students what is "under the<br />
bonnet" and conclude the module with an introduction to<br />
implementation issues, using material derived from<br />
"Implementing Functional Languages" by Simon Peyton Jones and <br />
David Lester. <br />
</blockquote><br />
<br />
<b>Instructor:</b> [mailto:popavdan@yahoo.com Popa V. Dan]<br />
University of Bacau, Romania <br><br />
<b>Course:</b> "Limbaje formale si automate" (Formal languages and automata) <br><br />
<b>Student background:</b> second-year undergraduate <br />
<br><br />
<b>Materials:</b> Hugs 98 (2002 revised version) included in Mandriva (Formely Mandrake) 10.0 Linux Distribution<br />
<br><br />
<b>Web page:</b> Not yet. Try the page of the "ro" community on www.haskell.org<br />
<br> [http://www.haskell.org/haskellwiki/Ro/Haskell Ro/Haskell webpage is here] <br><br />
<b>First run:</b> 2006&ndash;2007<br />
<br><br />
<br />
Haskell is used as an implementation languages in student's laboratories.<br />
The ideea was to provide a language powerfull enough to be able to express <br />
how to build a parser starting from a grammmar. The students are able<br />
to build small (monadic) interpreters for "while-languages" using a <br />
recommanded monad and a recommanded back-end. The labs are focusing on the <br />
grammar of the languages, on the modular (monadic) parsing as a tool for <br />
verifying and processing inputs which are not validable by finite state <br />
automata but by context free grammmars. Adaptability of the language, <br />
especially obtained manipulating and improving syntax is also a target.<br />
<br />
Support (concerning Haskell): "O introducere in Haskell prin exemple" by<br />
Dan Popa, published in january 31,2007 by <br />
[http://www.edusoft.ro Edusoft](in romanian) Contact the author if needed .<br />
<br />
Other recommanded books: "Gentle Introd to Haskell 98" and YAHT <br />
Recomanded papers: All about monadic parsing. <br />
Special message for Graham Hutton, Erik Meijer and P. Wadler and all <br />
other authors with similar interests from the Haskell <br />
community:<br />
<br />
Thank you very much for your papers concerning Monadic parsing and <br />
interpreters ! <br />
<br />
<br />
<br />
----<br />
<br />
== Comparative programming languages ==<br />
<br />
These courses teach general programming language principles, with<br />
Haskell as an example of a functional language.<br />
<br />
<b>Instructor: </b> Ruediger Marcus Flaig, University of Heidelberg (Germany)<br />
<br><br />
<b>Course:</b> An introduction to programming in bioinformatics <br><br />
<b>Student background:</b> different, but generally low<br><br />
<b>Materials:</b> Hugs-98 and lots of other stuff<br />
<br><br />
<b>Web page:</b> http://www.sanctacaris.net/rc.html<br> <br />
<b>Comments:</b><br />
<blockquote><br />
This course is designed to introduce life science students,<br />
that is to say, going-to-be biologists, physicians, biotechnologists<br />
and maybe others, to solving real-life problems (such as DNA sequence<br />
handling and analysis). Emphasis will be on paradigms (imperative /<br />
OO, functional, declarative). Although -- in order not to frighten<br />
people -- the official announcement mentions only Python, Haskell will<br />
be presented as THE purely functional language, and all solutions may<br />
be presented in either Python, Haskell or Java. I am very curious<br />
about the feedback I'll get, and maybe next term we shall focus more<br />
on Haskell. What I'd really need, though, is some life science related<br />
package for Haskell, such as BIOPYTHON and BIORUBY. <br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:ham@cs.utexas.edu Hamilton Richards],<br />
University of Texas (Austin)<br><br />
<b>Course:</b> Programming Languages<br><br />
<b>Student background:</b> <br><br />
<b>Materials:</b> Hugs 1.4; Sethi, Davie.<br><br />
<b>Web page:</b> http://www.cs.utexas.edu/users/ham/UTCS/CS345/<br><br />
<b>Comments:</b><br />
<blockquote><br />
I'm using Haskell in a programming-languages course, but it's distributed<br />
somewhat piecemeal through the course. Probably adds up to something like<br />
3-4 weeks (out of 15).<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [http://www.cs.waikato.ac.nz/~marku Mark Utting]<br />
University of Waikato (New Zealand)<br />
<b>Course:</b> Programming Languages<br><br />
<b>Student background:</b> Two years of C++ and 1 year of Haskell<br><br />
<b>Materials:</b> Textbook "Programming Languages", Louden.<br />
<b>Web page:</b> http://www.cs.waikato.ac.nz/~marku/313<br><br />
<b>Comments:</b><br />
<blockquote><br />
The course covers at least two languages in each of the<br />
main paradigms (object-oriented, functional and logic programming),<br />
plus history, semantics and implementation issues.<br />
The Haskell section is about 2 weeks long and usually focusses on <br />
programming with higher-order functions and how that enables the<br />
language to be extended in application-specific ways<br />
(parser combinators, html-generation combinators etc.)<br />
</blockquote><br />
<br />
----<br />
<br />
== Advanced functional programming using Haskell ==<br />
<br />
These courses deal with the advanced issues such as semantics, type<br />
systems, or compilers. Includes a other advanced courses taught using<br />
Haskell. <br />
<br />
<b>Instructor:</b> [mailto:rjmh@cs.chalmers.se John Hughes]<br />
Chalmers University, Gothenburg<br><br />
<b>Course:</b> Advanced Functional Programming<br><br />
<b>Student background:</b> General CS maturity; from this year most students have already used Haskell in introductory courses.<br><br />
<b>Materials:</b> Mainly hbc.; Papers (see web page)<br><br />
<b>Web page:</b> http://www.cs.chalmers.se/~rjmh/AFP<br><br />
<b>Comments:</b><br />
<blockquote><br />
The goal is to teach students how to solve substantial problems in a<br />
functional language --- `functional programming in anger', one might say. The<br />
emphasis is on design and use of suitable combinator libraries to simplify<br />
applications. Material covered includes monad design, use of CPS style,<br />
libraries for parsing, pretty-printing, and GUIs (presently fudgets). <br />
<br />
The course is taught in a `problem based' manner: lectures are few, while<br />
students solve three substantial programming problems during the term, with<br />
plenty of backup via group meetings. I adopted this teaching form three years<br />
ago, and it has led students to develop far better practical skills than most<br />
obtained from my earlier `lectures and exercises' courses, and I believe to<br />
use Haskell much more after the course's end.<br />
<br />
This course is optional in the third or fourth year, and is taken by a<br />
small-to-medium sized group of students.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:Olof.Johanssson@cs.umu.se Olof Johansson], Umeå Univesity, Department of Computing Science<br><br />
<b>Course:</b> Programming language semantics<br><br />
<b>Student background:</b> two terms of computer science studies and specificaly a course Programming language concepts<br><br />
<b>Materials:</b> Hugs and some HBC and GHC; Watt, Programming language, Syntax and Semantics<br><br />
<b>Web page:</b> http://www.cs.umu.se/local/kurser/TDBC05 (Only in swedish)<br> <br />
<br />
<br />
<b>Instructor:</b> [mailto:lyndon@cs.uwa.edu.au Lyndon While]<br />
The University of Western Australia<br><br />
<b>Course:</b> Functional Programming<br><br />
<b>Student background:</b> OOP, plus most of them have used Haskell previously<br><br />
<b>Materials:</b> hugs 98; none of the recent books really fit<br><br />
<b>Web page:</b> http://undergraduate.cs.uwa.edu.au/courses/230.301<br><br />
<b>Instructor:</b> [mailto:F.A.Rabhi@dcs.hull.ac.uk Fethi Rabhi],<br />
University of Hull (UK)<br><br />
<b>Course:</b> AI Problem Solving Techniques (using Haskell and Prolog)<br><br />
<b>Student background:</b> Haskell and Prolog programming<br><br />
<b>Materials:</b> HUGS; Thompson'96, own notes (soon to be published as a book).<br><br />
<b>Web page:</b> none<br><br />
<b>Comments:</b><br />
<blockquote><br />
It is very hard to justify learning Haskell unless it can be<br />
demonstrated in very practical situations (hence the provision<br />
of the above course).<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:karczma@info.unicaen.fr Jerzy Karczmarczuk]<br />
University of Caen, Caen (France)<br> No links in the fr-Haskell page. Why not ?<br />
<b>Course:</b> Compilation<br><br />
<b>Student background:</b> General CS knowledge; students (should...) know Scheme and imperative languages, also some theory of languages and automata.<br><br />
<b>Materials:</b> <br />
Hugs, GHC, now also GHCi, and their documentation. Handouts: (still a little incomplete)<br />
Impossible to find the foolowing matterials.Files can not be found. <br />
* http://users.info.unicaen.fr/~karczma/matrs/Maitcomp/compilation_a.pdf<br />
* http://users.info.unicaen.fr/~karczma/matrs/Maitcomp/compilation_b.pdf<br />
* http://users.info.unicaen.fr/~karczma/matrs/Maitcomp/compilation_c.pdf<br />
<b>Comments:</b><br />
<blockquote><br />
This is a compulsory semestrial course in fourth year. Weekly: 1.5h<br />
course, 2.5H practice.<br />
One, but comprehensive assignment, taking 2 months or more.<br />
askell is our main coding tool. A little time is devoted by necessity<br />
to the language<br />
itself, but also from the perspective: "how would you compile such a<br />
language".<br />
"Standard stuff", such as parsing combinators, etc.is covered, but we<br />
don't begin with that.<br />
We start with the construction of small interpreters: from recursive<br />
Lisp-style to postfix,<br />
(Forth/PostScript style) constructing this last by partial evaluation<br />
(intuitively).<br />
We introduce control structures as lazy functions, operation<br />
sequencing through continuations,<br />
monads not only for parsing, but also for exceptions and<br />
non-determinism.<br />
We discuss (simply) the type inference. The code generator assembles a<br />
linear code by lazy<br />
concatenation of chunks which makes it trivial to deal with loops and<br />
cross-referencing<br />
fragments. Algorithms of garbage collection are presented (not<br />
implemented, though...) in<br />
a purely functional style.<br />
<br />
Students' opinion: "Frightening at first. Learning curve steep, but<br />
much less time spent on debugging, coding proficiency comes fast. Good for<br />
understanding what the compilation is about, but difficult to make a<br />
complete running program with all the I/O, etc.<br />
</blockquote><br />
<br />
<br />
<b>Instructor:</b> [mailto:jeffm@cse.uconn.edu Jeffrey A. Meunier], University of Connecticut<br><br />
<b>Course:</b> CSE240 Intermediate Computer Systems<br><br />
<b>Student background:</b> computer/microprocessor organization<br />
<br><br />
<b>Materials:</b> Hugs (Feb 2001); Bird ``Introduction to Functional<br />
Programming''; Furber ``ARM System-on-Chip Architecture''<br />
<br><br />
<b>Web page:</b> http://www.engr.uconn.edu/~jeffm/Classes/CSE240-Spring-2001/index.html<br> <br />
<b>Comments:</b><br />
<blockquote><br />
This is a course in the low level programming of microprocessor systems.<br />
The course will focus on the development of an emulator (virtual<br />
machine, or VM) for a small computer system based on a modern RISC<br />
microprocessor (the ARM CPU) using a high level programming language<br />
(Haskell), and assembly language programming of the VM. Development of<br />
the VM will occur in stages, starting with the simple direct-execution<br />
(stream-based) model, gradually moving to a more realistic memory-mapped<br />
model, including exception handlers, concurrent processes, and<br />
asynchronous external devices.<br />
</blockquote><br />
<br />
<b>Instructor:</b> Gabriele Keller<br />
The University of New South Wales<br><br />
<b>Course:</b> Concepts of Programming Languages<br><br />
<b>Student background:</b> Most of them have used Haskell in first year<br><br />
<b>Materials:</b> GHC, TaPL and `Programming Languages: Theory and Practice', papers<br><br />
<b>Web page:</b> http://www.cse.unsw.edu.au/~cs3161<br><br />
<b>Last run:</b> 2006<br><br />
<b>Comments:</b><br />
<blockquote><br />
Expose students to a theory of programming languages based on type<br />
theory and operational semantics as a mathematically sound framework<br />
which allows us to investigate the properties of a large number of<br />
programming language features, including:<br />
<br />
* on semantics of different programming languages and programming paradigms: imperative, object oriented, and declarative.<br />
* theoretical foundations of programming languages: syntax, operatational, axiomatic and denotational semantics.<br />
* implementation aspects of central language features, such as dynamic and strong typing, polymorphism, overloading and automatic memory management<br />
<br />
Assignments are in GHC/Haskell, and in the past have included implementing a<br />
mini-Haskell type checker, type inference and interpreter.<br />
</blockquote><br />
<br />
<b>Instructor:</b> Manuel Chakravarty<br />
The University of New South Wales<br><br />
<b>Course:</b> Advanced Functional Programming<br><br />
<b>Student background:</b> Most of them have used Haskell in first year<br><br />
<b>Materials:</b> GHC, papers (see the website)<br><br />
<b>Web page:</b> http://www.cse.unsw.edu.au/~cs4132<br><br />
<b>Last run:</b>2004<br><br />
<b>Comments:</b><br />
<blockquote><br />
To provide students with an understanding of the theory and practice of<br />
the design, use, and implementation of functional programming languages,<br />
such as Haskell<br />
<br />
This includes selected topics from the following areas:<br />
<br />
* Foundations: lambda calculus, semantics, and type systems.<br />
* Design: side-effects, exceptions, concurrency, and parallelism.<br />
* Implementation: abstract machines, program transformation, and memory management. <br />
* Programming techniques: combinator libraries, monads, generic programming, and meta programming.<br />
* Applications: domain specific languages, graphics, web programming, reactive systems, and scientific programming.<br />
</blockquote><br />
<br />
[[Category:Community]]</div>Weihuhttps://wiki.haskell.org/index.php?title=Unboxed_type&diff=15239Unboxed type2007-08-23T23:38:28Z<p>Weihu: Fixed a link</p>
<hr />
<div>'''Unboxed types''' are [[type]]s that represent raw values. Unboxed types have [[kind]] <TT>#</TT>.<br />
<br />
Note that unboxed types of different storage behaviours (four bytes, eight bytes etc.) are all lumped together under kind <tt>#</tt>. As a result, [[type variable]]s must have kinds which are <tt>#</tt>-free.<br />
<br />
[[Category:Language]]<br />
<br />
==From the old Wiki==<br />
<br />
One might imagine numbers naively represented in Haskell "as pointer to a heap-allocated object which is either an unevaluated closure or is a "box" containing the number's actual value, which has now overwritten the closure" [3. below]. [[GHC]] (and other implementations?) allow direct access to the value inside the box, or "Unboxed" values.<br />
<br />
In GHC, by convention(?), unboxed values have a hash mark as a suffix to their name. For instance, the unboxed reprsentation of <code>42</code> is <code>42#</code>. There are some restrictions to their use. In particular, you can't pass them to polymorphic functions (like <hask>show</hask> for instance).<br />
<br />
In this example, <hask>I#</hask> is a constructor that takes an unboxed integer and returns the <hask>Int</hask> that we know and love.<br />
<br />
<haskell><br />
module Main where<br />
import GHC.Exts<br />
<br />
showUnboxedInt :: Int# -> String<br />
showUnboxedInt n = (show $ I# n) ++ "#"<br />
</haskell><br />
Here we wrap the unboxed Int <hask>n</hask> with the <hask>I#</hask> constructor and show the regular-old <hask>Int</hask>, whith a hash mark on the end.<br />
<br />
=== Unboxed Tuples and Arrays ===<br />
<br />
...<br />
<br />
=== When to use Unboxed Types ===<br />
<br />
...<br />
<br />
=== See Also ===<br />
<br />
#See the [http://www.haskell.org/ghc/docs/latest/html/users_guide/primitives.html discussion on primitives] in the [http://www.haskell.org/ghc/docs/latest/html/users_guide/users-guide.html GHC's User's Guide].<br />
#See the [http://www.haskell.org/ghc/docs/latest/html/libraries/base/GHC-Exts.html GHC.Exts] module.<br />
#See SPJ's paper [http://research.microsoft.com/Users/simonpj/Papers/unboxed-values.ps.Z Unboxed values as first class citizens].<br />
<br />
----<br />
This page is a work in progress by IsaacJones. More input welcome :)</div>Weihuhttps://wiki.haskell.org/index.php?title=Functional_dependencies&diff=15233Functional dependencies2007-08-22T20:02:42Z<p>Weihu: Fixed a link</p>
<hr />
<div>[[Category:Glossary]]<br />
[[Category:Language extensions]]<br />
Functional dependencies are used to constrain the parameters of type classes. They let you state that in a [[multi-parameter type class]], one of the [[parameter]]s can be determined from the others, so that the [[parameter]] determined by the others can, for example, be the return type but none of the argument types of some of the methods.<br />
<br />
==Examples==<br />
Suppose you want to implement some code to perform simple [[linear algebra]]:<br />
<haskell><br />
data Vector = Vector Int Int deriving (Eq, Show)<br />
data Matrix = Matrix Vector Vector deriving (Eq, Show)<br />
</haskell><br />
You want these to behave as much like numbers as possible. So you might start by overloading Haskell's Num class:<br />
<haskell><br />
instance Num Vector where<br />
Vector a1 b1 + Vector a2 b2 = Vector (a1+a2) (b1+b2)<br />
Vector a1 b1 - Vector a2 b2 = Vector (a1-a2) (b1-b2)<br />
{- ... and so on ... -}<br />
<br />
instance Num Matrix where<br />
Matrix a1 b1 + Matrix a2 b2 = Matrix (a1+a2) (b1+b2)<br />
Matrix a1 b1 - Matrix a2 b2 = Matrix (a1-a2) (b1-b2)<br />
{- ... and so on ... -}<br />
</haskell><br />
The problem comes when you want to start multiplying quantities. You really need a multiplication function which overloads to different types:<br />
<haskell><br />
(*) :: Matrix -> Matrix -> Matrix<br />
(*) :: Matrix -> Vector -> Vector<br />
(*) :: Matrix -> Int -> Matrix<br />
(*) :: Int -> Matrix -> Matrix<br />
{- ... and so on ... -}<br />
</haskell><br />
How do we specify a type class which allows all these possibilities?<br />
<br />
We could try this:<br />
<haskell><br />
class Mult a b c where<br />
(*) :: a -> b -> c<br />
<br />
instance Mult Matrix Matrix Matrix where<br />
{- ... -}<br />
<br />
instance Mult Matrix Vector Vector where<br />
{- ... -}<br />
</haskell><br />
That, however, isn't really what we want. As it stands, even a simple expression like this has an ambiguous type unless you supply an additional type declaration on the intermediate expression:<br />
<haskell><br />
m1, m2, m3 :: Matrix<br />
(m1 * m2) * m3 -- type error; type of (m1*m2) is ambiguous<br />
(m1 * m2) :: Matrix * m3 -- this is ok<br />
</haskell><br />
After all, nothing is stopping someone from coming along later and adding another instance:<br />
<haskell><br />
instance Mult Matrix Matrix (Maybe Char) where<br />
{- whatever -}<br />
</haskell><br />
The problem is that <hask>c</hask> shouldn't really be a free type variable. When you know the types of the things that you're multiplying, the result type should be determined from that information alone.<br />
<br />
You can express this by specifying a functional dependency, or fundep for short:<br />
<haskell><br />
class Mult a b c | a b -> c where<br />
(*) :: a -> b -> c<br />
</haskell><br />
This tells Haskell that <hask>c</hask> is uniquely determined from <hask>a</hask> and <hask>b</hask>.<br />
<br />
Fundeps have lots more uses than just implementing C++-style function overloading, of course. See [http://web.cecs.pdx.edu/~mpj/pubs/fundeps.html the paper] by Mark P. Jones for further details.<br />
<br />
Fundeps are not standard Haskell 98. (Nor are [[multi-parameter type class]]es, for that matter.) They are, however, supported at least in [[GHC]] and [[Hugs]] and will almost certainly end up in Haskell'.<br />
<br />
[[User:AndrewBromage]]</div>Weihuhttps://wiki.haskell.org/index.php?title=Language_and_library_specification&diff=15171Language and library specification2007-08-20T05:48:05Z<p>Weihu: Added a link</p>
<hr />
<div>{{unknown copyright}}<br />
[[Category:Language]]<br />
== The Haskell 98 report ==<br />
<br />
The Haskell 98 Report has undergone an extensive process of revision since its publication in January 1999. This process converged in January 2003, producing the Revised Report. <br />
<br />
The Revised Report is published by Cambridge University Press, as a book [http://www.cambridge.org/uk/catalogue/catalogue.asp?isbn=0521826144 "Haskell 98 language and libraries: the Revised Report"], and also as a<br />
Special Issue of the Journal of Functional Programming 13(1) Jan 2003.<br />
<br />
The text and sources of the Report are neverthless still available online. Note that these documents are intended to define Haskell and are not appropriate for learning Haskell. For the latter have a look at the [[Books|Haskell bookshelf]].<br />
<br />
* [http://haskell.org/onlinereport/ The Haskell 98 Report (Revised)]<br />
** [http://haskell.org/definition/haskell98-report-html.tar.gz HTML] (tar + gzip) [202K]<br />
** [http://haskell.org/definition/haskell98-report.ps.gz Postscript] (gzip) [330K]<br />
** [http://haskell.org/definition/haskell98-report.pdf PDF] [820K]<br />
** [http://haskell.org/definition/haskell98-report.pdf.gz PDF] (gzip) [650K]<br />
** [http://www.haskell.ru/ A translation of the full report into Russian]<br />
** [http://abaris.zoo.cs.uu.nl:8080/wiki/pub/FP/CourseLiterature/haskellsyntax-main.pdf Syntax diagrams for Haskell], by Jeroen Fokker. The accompanying text is in Dutch, but the syntax diagrams are legible in any language.<br />
<br />
[http://haskell.org/definition/haskell98-bugs.html A complete list of all changes] made to both reports between the Jan 1999 publication and the Revised Report (Dec 2002).<br />
<br />
The source for the Report is in a [http://cvs.haskell.org/cgi-bin/cvsweb.cgi/haskell-report/report publicly visible CVS repository]. If you render the report in a new way that others may wish to use, please let us know and we'll add it to this web page. If you have any other ways to package the report please let us know and we'll add them. <br />
<br />
The report still has minor bugs. There are tracked at the [http://haskell.org/definition/haskell98-revised-bugs.html Haskell 98 bugs page]. Report any new bugs to [mailto:Malcolm.Wallace@cs.york.ac.uk Malcolm Wallace].<br />
<br />
== Addenda to the report ==<br />
<br />
A number of conservative extensions to the<br />
base language Haskell 98 in the form of addenda to the<br />
language definition are under way. These extensions strive<br />
to complement the base language in areas that have not been<br />
covered during the design of Haskell 98, but which are<br />
perceived to be of crucial importance in some application<br />
areas. An effort is made to design these extensions to have<br />
minimal impact on existing Haskell 98 programs.<br />
<br />
The benefit of a H98 Addendum over any random language<br />
extension provided by some Haskell implementation is that a<br />
H98 Addendum is a standardised design, and programs coded<br />
against such an addendum can be expected to be portable<br />
across implementations that support this standard.<br />
Generally, implementations of H98 are not required to<br />
implement all H98 Addenda, but if such an implementation<br />
does provide a feature that is covered by an addendum, it is<br />
expected that this extension conforms to that addendum (in<br />
the same way as it is expected to abide by the H98 language<br />
definition).<br />
<br />
Finalised:<br />
#[http://www.cse.unsw.edu.au/~chak/haskell/ffi/ Foreign Function Interface] (FFI)<br />
<br />
Candidates:<br />
#[http://www.haskell.org/hierarchical-modules/ Hierarchical modules]<br />
<br />
== The next revision of the language ==<br />
<br />
Work started in late 2005 on the next revision of the Haskell language. A committee has been formed, and it aims to present a candidate for a new standard by late 2006. The working-title for the revised language is Haskell' (Haskell-prime). The work of the committee is public, being recorded on a<br />
separate [http://hackage.haskell.org/trac/haskell-prime Haskell-prime wiki], and there is a public mailing list for discussion as well.<br />
<br />
== Related work ==<br />
<br />
;[http://haskell.org/ghc/docs/latest/html/libraries/haskell-src/Language-Haskell-Parser.html Language.Haskell]<br />
:A lexer, parser and pretty printer for Haskell, available in the haskell-src library<br />
<br />
;[http://www.pms.informatik.uni-muenchen.de/mitarbeiter/panne/haskell_libs/hsparser.html HParser]<br />
:A parser for Haskell written purely in Haskell (using the Happy parser generator).<br />
<br />
;[http://citeseer.ist.psu.edu/jones99typing.html Typing Haskell in Haskell]<br />
:A Haskell program that implements a Haskell typechecker, thus providing a mathematically rigorous specification in a notation that is familiar to Haskell users. Its web page is cached [http://web.archive.org/web/20060516235636/www.cse.ogi.edu/~mpj/thih/ here].<br />
<br />
== Historic development of Haskell ==<br />
<br />
The Haskell 98 report was released in February 1999; it is a<br />
refinement and simplification of Haskell 1.4. See the [http://haskell.cs.yale.edu/definition/aboutHaskell98.html Haskell 98 page] for more details on<br />
Haskell 98 and changes from Haskell 1.4.<br />
<br />
The definition of<br />
Haskell version 1.4 was finished in April 1997. It contains just minor<br />
changes with respect to version 1.3 from May 1996, whereas the step<br />
from version 1.2 to version 1.3 was quite large. <br />
<br />
* Original Haskell 98 report<br />
** [http://haskell.org/definition/original-haskell98-report-html.tar.gz HTML] (tar + gzip) [160K]<br />
** [http://haskell.org/definition/original-haskell98-report.ps.gz Postscript] (gzip) [300k]<br />
* Original Haskell 98 library report<br />
** [http://haskell.org/definition/original-haskell98-library-html.tar.gz HTML] (tar + gzip) [76k]<br />
** [http://haskell.org/definition/original-haskell98-library.ps.gz Postscript] (gzip) [160K]<br />
* Haskell 1.4 report<br />
** [http://haskell.org/definition/haskell-report-1.4-html.tar.gz HTML] (tar + gzip) [125K]<br />
** [http://haskell.org/definition/haskell-report-1.4.ps.gz Postscript] (gzip) [230k]<br />
* Haskell 1.4 library report<br />
** [http://haskell.org/definition/haskell-library-1.4-html.tar.gz HTML] (tar + gzip) [60k]<br />
** [http://haskell.org/definition/haskell-library-1.4.ps.gz Postscript] (gzip) [100K]<br />
** [http://haskell.org/definition/from13to14.html Changes from 1.3]<br />
* Haskell 1.3 report (May 1996)<br />
** [http://haskell.org/definition/haskell-report-1.3.ps.gz Postscript] (gzip) [140 pages, 225 K]<br />
** [http://haskell.org/definition/from12to13.html Changes from 1.2]<br />
** [http://www.cs.chalmers.se/~augustss/convert.html A short guide on converting programs from Haskell 1.2 to 1.3]<br />
* Haskell 1.2 report (March 1992)<br />
** [http://haskell.org/definition/haskell-report-1.2.ps.gz Postscript] (gzip) [176 pages, 230 K]<br />
* Haskell 1.1 report<br />
** [http://haskell.org/definition/haskell-report-1.1.tar.gz Tarball] (gzip) [469 K]<br />
* Haskell 1.0 report<br />
** [http://haskell.org/definition/haskell-report-1.0.ps.gz Postscript] (gzip) [133 pages, 230 K]<br />
** [http://haskell.org/definition/haskell-report-1.0.tar.gz Tarball] (gzip) [125 K]<br />
<br />
Old definitions of the semantics of Haskell:<br />
<br />
;[http://research.microsoft.com/~simonpj/Papers/static-semantics.dvi.gz The Static Semantics of Haskell]<br />
:Simon Peyton Jones and Philip Wadler, Unpublished Technical Report, University of Glasgow, 1991, 49 pages.<br />
<br />
;[http://citeseer.ist.psu.edu/hammond92dynamic.html A Dynamic Semantics for Haskell (Draft)]<br />
:Kevin Hammond and Cordelia Hall, University of Glasgow, 1992, 23 pages.</div>Weihuhttps://wiki.haskell.org/index.php?title=Talk:History_of_Haskell/Version_1&diff=4823Talk:History of Haskell/Version 12006-07-16T21:42:23Z<p>Weihu: </p>
<hr />
<div>== Comments on "The History of Haskell" (draft) ==<br />
<br />
Please use the Wiki to add your comments here. Include your name and the date. You can do this with four tildes, like this: <nowiki>~~~~</nowiki>.<br />
<br />
To edit the page, you need to log in: click the login link at the bottom of the window. If you don't already have an account, the login page lets you create one in 30 seconds. See [[HaskellWiki:Contributing]].<br />
<br />
-----------------<br />
<br />
== Administration ==<br />
<br />
[[User:Simonpj|Simonpj]] 18:51, 14 July 2006 (UTC) Simon PJ. Here is an example comment<br />
<br />
[[User:BerniePope|BerniePope]] I hope you don't mind, but I've taken the liberty of breaking this up into sections, so that it is easier to find out what has been said already. This seems to be especially useful for typos etc. Please feel free to add other sections if you think they are necessary. I've also made the page numbers bold, and put them into page order (where possible).<br />
<br />
== Title suggestions ==<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 20:38, 14 July 2006 (UTC) Other ideas for a title: ''The History of Haskell: Unsuccessfully Avoiding Success'' or something using the motto "Avoid success at all costs." Or perhaps ''Success Considered Harmful, or, A History of Haskell'' or ''Doomed to Succeed'' quoting Hoare (although this sounds somewhat self-congratulatory).<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:19, 15 July 2006 (UTC) I really like the "eager to be lazy" title.<br />
<br />
== Typos, spelling, grammar, formatting and expression ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Typo: '''page 2''', column 2, "Rod Bustall" should be "Rod Burstall".<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Spelling: '''page 3''', column 1, "confernce".<br />
<br />
On '''page 4''' after the list of goals, it seems that the following sentence ("We agreed to base it on an existing language,<br />
namely OL.") should be preceeded by a line break (it now starts on the same line as the sixth goal).<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 22:00, 14 July 2006 (UTC) '''page 9''' Section 3.8, last paragraph, syntax error: should be "Miranda is still in use today: it '''is''' still taught in some institutions", missing word. (Sec 4.2 ''This tradition was honed by Moses Schonfinkel and Haskell Curry, and came to be called currying.'' I half expected a joke following this, saying ''[it was] called currying, luckily, and not '''schonfinkeling'''.'') Same section, typo: ''is a list of lists'' should be ''in a list of lists.''<br />
:That joke would have been surpassed by reality, because the german word for ''currying'' '''is''' ''schönfinkeln''. See [http://de.wikipedia.org/wiki/Sch%C3%B6nfinkeln Schönfinkeln]. --[[User:MarcVanWoerkom|MarcVanWoerkom]] 18:49, 16 July 2006 (UTC)<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Expression. '''page 9'''. It says "Haskell did not adopt Miranda's abstract data types, using '''its''' module system instead." It is not clear whose module system it is using. Perhaps it should read "using '''a''' module system instead." ?<br />
<br />
[[User:BerniePope|BerniePope]] 15:56, 15 July 2006 (UTC) Tense. '''page 12'''. Section 5.1, algebraic data types. It says "In general, every algebraic data type specified...", should that be "specifies" ? or perhaps even better "In general, algebraic data types specify" ?<br />
<br />
[[User:Ruiz|Ruiz]] 12:04, 16 July 2006 (UTC) Comment. '''page 12'''. If I am not mistaken, the Fermat's Last Theorem example only generates (1,1,z) triplets.<br />
<br />
[[User:BerniePope|BerniePope]] 16:15, 15 July 2006 (UTC) Tense. '''page 13'''. Section 5.3 Abstract types. It says "This had the advantage ...". Perhaps it should be: "This has the advantage", since Miranda still exists, and the advantage still holds. Later in the same paragraph the expression about adopting the feature in Haskell is a bit awkward. Perhaps it could read: "It is not clear how to adapt Miranda's method of defining abstract data types to type classes, and that is one reason we chose a different solution." ?<br />
<br />
[[User:BerniePope|BerniePope]] 16:27, 15 July 2006 (UTC) Typo. Section 5.6, '''page 14''' and in Bibliography. Godel's name in citation missing the 'o'.<br />
<br />
[[User:BerniePope|BerniePope]] 05:41, 16 July 2006 (UTC) Comment. '''page 15''', column 1. "practical comprehensibility" is a bit of a mouthful. Perhaps "pragmatism" would suffice?<br />
<br />
[[User:BerniePope|BerniePope]] 06:11, 16 July 2006 (UTC) Typo (possibly). '''page 16'''. Section 6.4, multi-parameter type classes. "They gave the following example: second.". Should the "second" be there?<br />
<br />
[[User:BerniePope|BerniePope]] 06:56, 16 July 2006 (UTC) Typo, '''page 16'''. The code "n = (x + y)", perhaps drop the redundant parens?<br />
<br />
[[User:BerniePope|BerniePope]] 07:19, 16 July 2006 (UTC) '''page 17'''. Choice of identifier. In the code "f (MkT x f) = f x". Perhaps the inner or outer "f" should be renamed? Also, is there a more compelling example than this one?<br />
<br />
[[User:Weihu|Weihu]] 17:33, 16 July 2006 (UTC) '''page 17'''. Duplication of words. "The the type qualification in this case" => "The type qualification in this case".<br />
<br />
[[User:BerniePope|BerniePope]] 07:16, 16 July 2006 (UTC) Typo. '''page 17'''. "patter-matching" -> "pattern-matching".<br />
<br />
[[User:BerniePope|BerniePope]] 07:26, 16 July 2006 (UTC) Expression. '''page 17'''. Perhaps drop "rather than explicitly". This is implied by the previous "happens implicitly".<br />
<br />
[[User:BerniePope|BerniePope]] 07:38, 16 July 2006 (UTC) Typo. '''page 18'''. In lexically scoped type variables, it says the type of xcons is "forall a. a -> a". Do you mean: "forall a . [a] -> [a]"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:39, 16 July 2006 (UTC) Typesetting. '''page 22'''. Sometimes the "IO monad" is written where "IO" is in typewriter font, and other times it is in times roman, and other times it is written "I/O". This may be an intentional distinction, but maybe the notation can be unified?<br />
<br />
[[User:Weihu|Weihu]] 20:36, 16 July 2006 (UTC) Word missing. '''page 22'''. "So readFile a function that" => "So readFile is a function that".<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 04:27, 15 July 2006 (UTC) '''page 25'''. Section 9.2 misspelling "existance" should be "existence" third to last paragraph. Sec. 9.5 , '''page 27''', second to last paragraph. ''test bad'' should be ''test bed''.<br />
<br />
[[User:BerniePope|BerniePope]] 12:33, 16 July 2006 (UTC) Typo. '''page 28'''. Section 10.2, paragraph 2. "who had by thus time" -> "who had by this time".<br />
<br />
[[User:BerniePope|BerniePope]] 13:22, 16 July 2006 (UTC) Missing word. '''page 30'''. Section 10.4.2 Observational debugging. It says "to track down bug location" -> "to track down the bug location".<br />
<br />
[[User:Weihu|Weihu]] 21:35, 15 July 2006 (UTC) Typo: '''page 31''', column 2, "a central them" should be "a central theme".<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:18, 15 July 2006 (UTC) Section 11.2.3 '''page 34''' typo "unsagePerformIO".<br />
<br />
[[User:Weihu|Weihu]] 21:42, 16 July 2006 (UTC) '''page 35''': "invariably based on a imperative widget" => "invariably based on an imperative widget".<br />
<br />
Typo on '''page 39''': Another example is that Linspire’s ''toold'' must handle legacy data formats. --[[User:NeilMitchell|Neil Mitchell]] 15:23, 14 July 2006 (UTC)<br />
<br />
[[User:BerniePope|BerniePope]] 13:06, 16 July 2006 (UTC) Overall. Capitalisation in headings seems to be inconsistent.<br />
<br />
== General comments ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 7'''. Section 3.3, third paragraph. Rather than talk about "div" (are the first quote marks backwards?), perhaps you could say - "for example, Miranda's type system allows floating point values to be given to functions which are only defined on the integer subset of num, thus turning a static error into a dynamic one."<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 10'''. Section 4.1, layout. It says "The rules are simple ...". I think this is a contentious issue. Recent discussions on the Haskell Prime mailing list [http://www.haskell.org//pipermail/haskell-prime/2006-March/000898.html] suggested a contrary view. How many Haskellers actually know the rules? Perhaps it would be more accurate to say that experience shows it is not hard to adopt a style of programming which stays within the rules.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Footnote 2 on '''page 10''' says the Scheme authors took a more Draconian approach with respect to operators, though it doesn't actually say what that means. On the off chance that someone reading the paper doesn't know Scheme, it might be worth elaborating on that point.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.4. Near the end of the section you give an example of "where" being attached to a declaration. I think the example function "f" is rather obscure, perhaps there is a better example? Maybe one from the Prelude? Also, there seems to be another point you could make here. Due to laziness we get some more freedom in the way that we write where clauses. For instance, the thing being defined in the where clause may only be well defined in a subset of the alternatives. But that doesn't matter because we will only evaluate the thing if and when it is needed, not before.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.5, list comprehensions. Perhaps it is worth noting the Haskell does not have the diagonalisation operator like Miranda. It may also be worth remarking on why this is so. Surely it was considered.<br />
<br />
[[User:BerniePope|BerniePope]] 16:05, 15 July 2006 (UTC) Comment. '''page 13'''. Section 5.3 Abstract types. It says that the type has one constructor. Is it really necessary to limit the type to just one constructor? Surely it is enough that the constructors of the type are not exported, regardless of how many there are?<br />
<br />
[[User:BerniePope|BerniePope]] 05:28, 16 July 2006 (UTC) Comment. '''page 14'''. Section 6.1, Type classes. Perhaps it should mention that '''eqInt''' is primitive equality on integers, maybe as a comment in the code.<br />
<br />
[[User:BerniePope|BerniePope]] 05:54, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Monomorphism restriction. This marks one of the most unusual aspects of the language, especially in the Language Report. In particular, it is motivated by operational semantics --- sharing --- but the rest of the Report is largely silent on the issue. I think the Report says something to the effect of "programmers expect sharing to be preserved", but there is not much else in the Report to back this statement up. Perhaps you could tie this back to the discussion in Section 3.4 (Haskell has no formal semantics). Also, I think it would be reasonable to say "GHC provides a flag to suppress the restriction", without actually naming the flag.<br />
<br />
[[User:BerniePope|BerniePope]] 06:02, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Higher kinded polymorphism. It says "Here, the type variable m has kind *->*". It seems like the reader is already supposed to know what a kind is at this point. Perhaps the section could provide a little introduction to the concept of kinds first. Another thing about kinds is that they are sort of shadowy figures that seem to lurk in the background of Haskell. For instance they have no syntactic counterpart in Haskell 98. It can be quite daunting for beginners when they get a kind error.<br />
<br />
[[User:BerniePope|BerniePope]] 07:30, 16 July 2006 (UTC) Comment. '''page 17'''. Section 6.6 Implicit parameters. Perhaps contrast this approach to a Reader monad?<br />
<br />
[[User:BerniePope|BerniePope]] 07:44, 16 July 2006 (UTC) Comment. '''page 18'''. Arrows. It doesn't really say what arrows are, except that they are like monads, but more general. Perhaps this could be elaborated, maybe with some mention of the intuition that arrows generalise things which are somehow composable? Perhaps an example of an arrow which cannot be done with a monad?<br />
<br />
[[User:BerniePope|BerniePope]] 08:14, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says that "Checking that the laws hold provides a reassuring sanity check when defining a new monad." Perhaps you could elaborate on exactly what we are checking, and subsequently reassured about. It says earlier that the laws show associativity and identity, but is there a more "programmer oriented" view of what this means? <br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says monads were helpful in structuring programs, including "the Haskell compiler itself". This sounds like there was a single Haskell compiler. Perhaps it should be "exisiting Haskell compilers"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. One of the ongoing issues with monads is combining them together. Perhaps you could mention some of the attempts at doing this, such as monad transformers.<br />
<br />
[[User:BerniePope|BerniePope]] 13:04, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.3 Controlling Evaluation Order. The last paragraph suggests that we can wait until the program is written, then profile, then add seqs as necessary. While this is true, many programs are never really finished. Adding seq to code is one thing, but maintaining code with seq in it is another, perhaps more difficult problem. Also, you might be able to make a link here to the material on speculative evaluation, since that also solves some space/strictness issues.<br />
<br />
[[User:BerniePope|BerniePope]] 13:14, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.4 Debugging and tracing. It says that hbc and GHC provide trace. Hugs also has trace (perhaps nhc98 does as well?).<br />
<br />
[[User:Hoan|Hoan]] 12:45, 15 July 2006 (UTC) On '''page 33''' it says that Ruby on Rails is a continuation based framework. I think thats wrong. PS. Its a riveting read.<br />
<br />
[[User:BerniePope|BerniePope]] 07:57, 16 July 2006 (UTC) Overall. Names of people. I've noticed that sometimes people are referred to by their whole name, whilst others are referred to by just their family name. Perhaps there is an underlying method here, but it wasn't clear to me. Perhaps it is that the first reference gets a full name, and subsequent ones are just the family name? Is that always the case?</div>Weihuhttps://wiki.haskell.org/index.php?title=Talk:History_of_Haskell/Version_1&diff=4822Talk:History of Haskell/Version 12006-07-16T20:36:46Z<p>Weihu: </p>
<hr />
<div>== Comments on "The History of Haskell" (draft) ==<br />
<br />
Please use the Wiki to add your comments here. Include your name and the date. You can do this with four tildes, like this: <nowiki>~~~~</nowiki>.<br />
<br />
To edit the page, you need to log in: click the login link at the bottom of the window. If you don't already have an account, the login page lets you create one in 30 seconds. See [[HaskellWiki:Contributing]].<br />
<br />
-----------------<br />
<br />
== Administration ==<br />
<br />
[[User:Simonpj|Simonpj]] 18:51, 14 July 2006 (UTC) Simon PJ. Here is an example comment<br />
<br />
[[User:BerniePope|BerniePope]] I hope you don't mind, but I've taken the liberty of breaking this up into sections, so that it is easier to find out what has been said already. This seems to be especially useful for typos etc. Please feel free to add other sections if you think they are necessary. I've also made the page numbers bold, and put them into page order (where possible).<br />
<br />
== Title suggestions ==<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 20:38, 14 July 2006 (UTC) Other ideas for a title: ''The History of Haskell: Unsuccessfully Avoiding Success'' or something using the motto "Avoid success at all costs." Or perhaps ''Success Considered Harmful, or, A History of Haskell'' or ''Doomed to Succeed'' quoting Hoare (although this sounds somewhat self-congratulatory).<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:19, 15 July 2006 (UTC) I really like the "eager to be lazy" title.<br />
<br />
== Typos, spelling, grammar, formatting and expression ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Typo: '''page 2''', column 2, "Rod Bustall" should be "Rod Burstall".<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Spelling: '''page 3''', column 1, "confernce".<br />
<br />
On '''page 4''' after the list of goals, it seems that the following sentence ("We agreed to base it on an existing language,<br />
namely OL.") should be preceeded by a line break (it now starts on the same line as the sixth goal).<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 22:00, 14 July 2006 (UTC) '''page 9''' Section 3.8, last paragraph, syntax error: should be "Miranda is still in use today: it '''is''' still taught in some institutions", missing word. (Sec 4.2 ''This tradition was honed by Moses Schonfinkel and Haskell Curry, and came to be called currying.'' I half expected a joke following this, saying ''[it was] called currying, luckily, and not '''schonfinkeling'''.'') Same section, typo: ''is a list of lists'' should be ''in a list of lists.''<br />
:That joke would have been surpassed by reality, because the german word for ''currying'' '''is''' ''schönfinkeln''. See [http://de.wikipedia.org/wiki/Sch%C3%B6nfinkeln Schönfinkeln]. --[[User:MarcVanWoerkom|MarcVanWoerkom]] 18:49, 16 July 2006 (UTC)<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Expression. '''page 9'''. It says "Haskell did not adopt Miranda's abstract data types, using '''its''' module system instead." It is not clear whose module system it is using. Perhaps it should read "using '''a''' module system instead." ?<br />
<br />
[[User:BerniePope|BerniePope]] 15:56, 15 July 2006 (UTC) Tense. '''page 12'''. Section 5.1, algebraic data types. It says "In general, every algebraic data type specified...", should that be "specifies" ? or perhaps even better "In general, algebraic data types specify" ?<br />
<br />
[[User:Ruiz|Ruiz]] 12:04, 16 July 2006 (UTC) Comment. '''page 12'''. If I am not mistaken, the Fermat's Last Theorem example only generates (1,1,z) triplets.<br />
<br />
[[User:BerniePope|BerniePope]] 16:15, 15 July 2006 (UTC) Tense. '''page 13'''. Section 5.3 Abstract types. It says "This had the advantage ...". Perhaps it should be: "This has the advantage", since Miranda still exists, and the advantage still holds. Later in the same paragraph the expression about adopting the feature in Haskell is a bit awkward. Perhaps it could read: "It is not clear how to adapt Miranda's method of defining abstract data types to type classes, and that is one reason we chose a different solution." ?<br />
<br />
[[User:BerniePope|BerniePope]] 16:27, 15 July 2006 (UTC) Typo. Section 5.6, '''page 14''' and in Bibliography. Godel's name in citation missing the 'o'.<br />
<br />
[[User:BerniePope|BerniePope]] 05:41, 16 July 2006 (UTC) Comment. '''page 15''', column 1. "practical comprehensibility" is a bit of a mouthful. Perhaps "pragmatism" would suffice?<br />
<br />
[[User:BerniePope|BerniePope]] 06:11, 16 July 2006 (UTC) Typo (possibly). '''page 16'''. Section 6.4, multi-parameter type classes. "They gave the following example: second.". Should the "second" be there?<br />
<br />
[[User:BerniePope|BerniePope]] 06:56, 16 July 2006 (UTC) Typo, '''page 16'''. The code "n = (x + y)", perhaps drop the redundant parens?<br />
<br />
[[User:BerniePope|BerniePope]] 07:19, 16 July 2006 (UTC) '''page 17'''. Choice of identifier. In the code "f (MkT x f) = f x". Perhaps the inner or outer "f" should be renamed? Also, is there a more compelling example than this one?<br />
<br />
[[User:Weihu|Weihu]] 17:33, 16 July 2006 (UTC) '''page 17'''. Duplication of words. "The the type qualification in this case" => "The type qualification in this case".<br />
<br />
[[User:BerniePope|BerniePope]] 07:16, 16 July 2006 (UTC) Typo. '''page 17'''. "patter-matching" -> "pattern-matching".<br />
<br />
[[User:BerniePope|BerniePope]] 07:26, 16 July 2006 (UTC) Expression. '''page 17'''. Perhaps drop "rather than explicitly". This is implied by the previous "happens implicitly".<br />
<br />
[[User:BerniePope|BerniePope]] 07:38, 16 July 2006 (UTC) Typo. '''page 18'''. In lexically scoped type variables, it says the type of xcons is "forall a. a -> a". Do you mean: "forall a . [a] -> [a]"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:39, 16 July 2006 (UTC) Typesetting. '''page 22'''. Sometimes the "IO monad" is written where "IO" is in typewriter font, and other times it is in times roman, and other times it is written "I/O". This may be an intentional distinction, but maybe the notation can be unified?<br />
<br />
[[User:Weihu|Weihu]] 20:36, 16 July 2006 (UTC) Word missing. '''page 22'''. "So readFile a function that" => "So readFile is a function that".<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 04:27, 15 July 2006 (UTC) '''page 25'''. Section 9.2 misspelling "existance" should be "existence" third to last paragraph. Sec. 9.5 , '''page 27''', second to last paragraph. ''test bad'' should be ''test bed''.<br />
<br />
[[User:BerniePope|BerniePope]] 12:33, 16 July 2006 (UTC) Typo. '''page 28'''. Section 10.2, paragraph 2. "who had by thus time" -> "who had by this time".<br />
<br />
[[User:BerniePope|BerniePope]] 13:22, 16 July 2006 (UTC) Missing word. '''page 30'''. Section 10.4.2 Observational debugging. It says "to track down bug location" -> "to track down the bug location".<br />
<br />
[[User:Weihu|Weihu]] 21:35, 15 July 2006 (UTC) Typo: '''page 31''', column 2, "a central them" should be "a central theme".<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:18, 15 July 2006 (UTC) Section 11.2.3 '''page 34''' typo "unsagePerformIO".<br />
<br />
Typo on '''page 39''': Another example is that Linspire’s ''toold'' must handle legacy data formats. --[[User:NeilMitchell|Neil Mitchell]] 15:23, 14 July 2006 (UTC)<br />
<br />
[[User:BerniePope|BerniePope]] 13:06, 16 July 2006 (UTC) Overall. Capitalisation in headings seems to be inconsistent.<br />
<br />
== General comments ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 7'''. Section 3.3, third paragraph. Rather than talk about "div" (are the first quote marks backwards?), perhaps you could say - "for example, Miranda's type system allows floating point values to be given to functions which are only defined on the integer subset of num, thus turning a static error into a dynamic one."<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 10'''. Section 4.1, layout. It says "The rules are simple ...". I think this is a contentious issue. Recent discussions on the Haskell Prime mailing list [http://www.haskell.org//pipermail/haskell-prime/2006-March/000898.html] suggested a contrary view. How many Haskellers actually know the rules? Perhaps it would be more accurate to say that experience shows it is not hard to adopt a style of programming which stays within the rules.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Footnote 2 on '''page 10''' says the Scheme authors took a more Draconian approach with respect to operators, though it doesn't actually say what that means. On the off chance that someone reading the paper doesn't know Scheme, it might be worth elaborating on that point.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.4. Near the end of the section you give an example of "where" being attached to a declaration. I think the example function "f" is rather obscure, perhaps there is a better example? Maybe one from the Prelude? Also, there seems to be another point you could make here. Due to laziness we get some more freedom in the way that we write where clauses. For instance, the thing being defined in the where clause may only be well defined in a subset of the alternatives. But that doesn't matter because we will only evaluate the thing if and when it is needed, not before.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.5, list comprehensions. Perhaps it is worth noting the Haskell does not have the diagonalisation operator like Miranda. It may also be worth remarking on why this is so. Surely it was considered.<br />
<br />
[[User:BerniePope|BerniePope]] 16:05, 15 July 2006 (UTC) Comment. '''page 13'''. Section 5.3 Abstract types. It says that the type has one constructor. Is it really necessary to limit the type to just one constructor? Surely it is enough that the constructors of the type are not exported, regardless of how many there are?<br />
<br />
[[User:BerniePope|BerniePope]] 05:28, 16 July 2006 (UTC) Comment. '''page 14'''. Section 6.1, Type classes. Perhaps it should mention that '''eqInt''' is primitive equality on integers, maybe as a comment in the code.<br />
<br />
[[User:BerniePope|BerniePope]] 05:54, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Monomorphism restriction. This marks one of the most unusual aspects of the language, especially in the Language Report. In particular, it is motivated by operational semantics --- sharing --- but the rest of the Report is largely silent on the issue. I think the Report says something to the effect of "programmers expect sharing to be preserved", but there is not much else in the Report to back this statement up. Perhaps you could tie this back to the discussion in Section 3.4 (Haskell has no formal semantics). Also, I think it would be reasonable to say "GHC provides a flag to suppress the restriction", without actually naming the flag.<br />
<br />
[[User:BerniePope|BerniePope]] 06:02, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Higher kinded polymorphism. It says "Here, the type variable m has kind *->*". It seems like the reader is already supposed to know what a kind is at this point. Perhaps the section could provide a little introduction to the concept of kinds first. Another thing about kinds is that they are sort of shadowy figures that seem to lurk in the background of Haskell. For instance they have no syntactic counterpart in Haskell 98. It can be quite daunting for beginners when they get a kind error.<br />
<br />
[[User:BerniePope|BerniePope]] 07:30, 16 July 2006 (UTC) Comment. '''page 17'''. Section 6.6 Implicit parameters. Perhaps contrast this approach to a Reader monad?<br />
<br />
[[User:BerniePope|BerniePope]] 07:44, 16 July 2006 (UTC) Comment. '''page 18'''. Arrows. It doesn't really say what arrows are, except that they are like monads, but more general. Perhaps this could be elaborated, maybe with some mention of the intuition that arrows generalise things which are somehow composable? Perhaps an example of an arrow which cannot be done with a monad?<br />
<br />
[[User:BerniePope|BerniePope]] 08:14, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says that "Checking that the laws hold provides a reassuring sanity check when defining a new monad." Perhaps you could elaborate on exactly what we are checking, and subsequently reassured about. It says earlier that the laws show associativity and identity, but is there a more "programmer oriented" view of what this means? <br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says monads were helpful in structuring programs, including "the Haskell compiler itself". This sounds like there was a single Haskell compiler. Perhaps it should be "exisiting Haskell compilers"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. One of the ongoing issues with monads is combining them together. Perhaps you could mention some of the attempts at doing this, such as monad transformers.<br />
<br />
[[User:BerniePope|BerniePope]] 13:04, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.3 Controlling Evaluation Order. The last paragraph suggests that we can wait until the program is written, then profile, then add seqs as necessary. While this is true, many programs are never really finished. Adding seq to code is one thing, but maintaining code with seq in it is another, perhaps more difficult problem. Also, you might be able to make a link here to the material on speculative evaluation, since that also solves some space/strictness issues.<br />
<br />
[[User:BerniePope|BerniePope]] 13:14, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.4 Debugging and tracing. It says that hbc and GHC provide trace. Hugs also has trace (perhaps nhc98 does as well?).<br />
<br />
[[User:Hoan|Hoan]] 12:45, 15 July 2006 (UTC) On '''page 33''' it says that Ruby on Rails is a continuation based framework. I think thats wrong. PS. Its a riveting read.<br />
<br />
[[User:BerniePope|BerniePope]] 07:57, 16 July 2006 (UTC) Overall. Names of people. I've noticed that sometimes people are referred to by their whole name, whilst others are referred to by just their family name. Perhaps there is an underlying method here, but it wasn't clear to me. Perhaps it is that the first reference gets a full name, and subsequent ones are just the family name? Is that always the case?</div>Weihuhttps://wiki.haskell.org/index.php?title=Talk:History_of_Haskell/Version_1&diff=4820Talk:History of Haskell/Version 12006-07-16T17:33:41Z<p>Weihu: </p>
<hr />
<div>== Comments on "The History of Haskell" (draft) ==<br />
<br />
Please use the Wiki to add your comments here. Include your name and the date. You can do this with four tildes, like this: <nowiki>~~~~</nowiki>.<br />
<br />
To edit the page, you need to log in: click the login link at the bottom of the window. If you don't already have an account, the login page lets you create one in 30 seconds. See [[HaskellWiki:Contributing]].<br />
<br />
-----------------<br />
<br />
== Administration ==<br />
<br />
[[User:Simonpj|Simonpj]] 18:51, 14 July 2006 (UTC) Simon PJ. Here is an example comment<br />
<br />
[[User:BerniePope|BerniePope]] I hope you don't mind, but I've taken the liberty of breaking this up into sections, so that it is easier to find out what has been said already. This seems to be especially useful for typos etc. Please feel free to add other sections if you think they are necessary. I've also made the page numbers bold, and put them into page order (where possible).<br />
<br />
== Title suggestions ==<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 20:38, 14 July 2006 (UTC) Other ideas for a title: ''The History of Haskell: Unsuccessfully Avoiding Success'' or something using the motto "Avoid success at all costs." Or perhaps ''Success Considered Harmful, or, A History of Haskell'' or ''Doomed to Succeed'' quoting Hoare (although this sounds somewhat self-congratulatory).<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:19, 15 July 2006 (UTC) I really like the "eager to be lazy" title.<br />
<br />
== Typos, spelling, grammar, formatting and expression ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Typo: '''page 2''', column 2, "Rod Bustall" should be "Rod Burstall".<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Spelling: '''page 3''', column 1, "confernce".<br />
<br />
On '''page 4''' after the list of goals, it seems that the following sentence ("We agreed to base it on an existing language,<br />
namely OL.") should be preceeded by a line break (it now starts on the same line as the sixth goal).<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 22:00, 14 July 2006 (UTC) '''page 9''' Section 3.8, last paragraph, syntax error: should be "Miranda is still in use today: it '''is''' still taught in some institutions", missing word. (Sec 4.2 ''This tradition was honed by Moses Schonfinkel and Haskell Curry, and came to be called currying.'' I half expected a joke following this, saying ''[it was] called currying, luckily, and not '''schonfinkeling'''.'') Same section, typo: ''is a list of lists'' should be ''in a list of lists.''<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Expression. '''page 9'''. It says "Haskell did not adopt Miranda's abstract data types, using '''its''' module system instead." It is not clear whose module system it is using. Perhaps it should read "using '''a''' module system instead." ?<br />
<br />
[[User:BerniePope|BerniePope]] 15:56, 15 July 2006 (UTC) Tense. '''page 12'''. Section 5.1, algebraic data types. It says "In general, every algebraic data type specified...", should that be "specifies" ? or perhaps even better "In general, algebraic data types specify" ?<br />
<br />
[[User:Ruiz|Ruiz]] 12:04, 16 July 2006 (UTC) Comment. '''page 12'''. If I am not mistaken, the Fermat's Last Theorem example only generates (1,1,z) triplets.<br />
<br />
[[User:BerniePope|BerniePope]] 16:15, 15 July 2006 (UTC) Tense. '''page 13'''. Section 5.3 Abstract types. It says "This had the advantage ...". Perhaps it should be: "This has the advantage", since Miranda still exists, and the advantage still holds. Later in the same paragraph the expression about adopting the feature in Haskell is a bit awkward. Perhaps it could read: "It is not clear how to adapt Miranda's method of defining abstract data types to type classes, and that is one reason we chose a different solution." ?<br />
<br />
[[User:BerniePope|BerniePope]] 16:27, 15 July 2006 (UTC) Typo. Section 5.6, '''page 14''' and in Bibliography. Godel's name in citation missing the 'o'.<br />
<br />
[[User:BerniePope|BerniePope]] 05:41, 16 July 2006 (UTC) Comment. '''page 15''', column 1. "practical comprehensibility" is a bit of a mouthful. Perhaps "pragmatism" would suffice?<br />
<br />
[[User:BerniePope|BerniePope]] 06:11, 16 July 2006 (UTC) Typo (possibly). '''page 16'''. Section 6.4, multi-parameter type classes. "They gave the following example: second.". Should the "second" be there?<br />
<br />
[[User:BerniePope|BerniePope]] 06:56, 16 July 2006 (UTC) Typo, '''page 16'''. The code "n = (x + y)", perhaps drop the redundant parens?<br />
<br />
[[User:BerniePope|BerniePope]] 07:19, 16 July 2006 (UTC) '''page 17'''. Choice of identifier. In the code "f (MkT x f) = f x". Perhaps the inner or outer "f" should be renamed? Also, is there a more compelling example than this one?<br />
<br />
[[User:Weihu|Weihu]] 17:33, 16 July 2006 (UTC) '''page 17'''. Duplication of words. "The the type qualification in this case" => "The type qualification in this case".<br />
<br />
[[User:BerniePope|BerniePope]] 07:16, 16 July 2006 (UTC) Typo. '''page 17'''. "patter-matching" -> "pattern-matching".<br />
<br />
[[User:BerniePope|BerniePope]] 07:26, 16 July 2006 (UTC) Expression. '''page 17'''. Perhaps drop "rather than explicitly". This is implied by the previous "happens implicitly".<br />
<br />
[[User:BerniePope|BerniePope]] 07:38, 16 July 2006 (UTC) Typo. '''page 18'''. In lexically scoped type variables, it says the type of xcons is "forall a. a -> a". Do you mean: "forall a . [a] -> [a]"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:39, 16 July 2006 (UTC) Typesetting. '''page 22'''. Sometimes the "IO monad" is written where "IO" is in typewriter font, and other times it is in times roman, and other times it is written "I/O". This may be an intentional distinction, but maybe the notation can be unified?<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 04:27, 15 July 2006 (UTC) '''page 25'''. Section 9.2 misspelling "existance" should be "existence" third to last paragraph. Sec. 9.5 , '''page 27''', second to last paragraph. ''test bad'' should be ''test bed''.<br />
<br />
[[User:BerniePope|BerniePope]] 12:33, 16 July 2006 (UTC) Typo. '''page 28'''. Section 10.2, paragraph 2. "who had by thus time" -> "who had by this time".<br />
<br />
[[User:BerniePope|BerniePope]] 13:22, 16 July 2006 (UTC) Missing word. '''page 30'''. Section 10.4.2 Observational debugging. It says "to track down bug location" -> "to track down the bug location".<br />
<br />
[[User:Weihu|Weihu]] 21:35, 15 July 2006 (UTC) Typo: '''page 31''', column 2, "a central them" should be "a central theme".<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:18, 15 July 2006 (UTC) Section 11.2.3 '''page 34''' typo "unsagePerformIO".<br />
<br />
Typo on '''page 39''': Another example is that Linspire’s ''toold'' must handle legacy data formats. --[[User:NeilMitchell|Neil Mitchell]] 15:23, 14 July 2006 (UTC)<br />
<br />
[[User:BerniePope|BerniePope]] 13:06, 16 July 2006 (UTC) Overall. Capitalisation in headings seems to be inconsistent.<br />
<br />
== General comments ==<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 7'''. Section 3.3, third paragraph. Rather than talk about "div" (are the first quote marks backwards?), perhaps you could say - "for example, Miranda's type system allows floating point values to be given to functions which are only defined on the integer subset of num, thus turning a static error into a dynamic one."<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 10'''. Section 4.1, layout. It says "The rules are simple ...". I think this is a contentious issue. Recent discussions on the Haskell Prime mailing list [http://www.haskell.org//pipermail/haskell-prime/2006-March/000898.html] suggested a contrary view. How many Haskellers actually know the rules? Perhaps it would be more accurate to say that experience shows it is not hard to adopt a style of programming which stays within the rules.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Footnote 2 on '''page 10''' says the Scheme authors took a more Draconian approach with respect to operators, though it doesn't actually say what that means. On the off chance that someone reading the paper doesn't know Scheme, it might be worth elaborating on that point.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.4. Near the end of the section you give an example of "where" being attached to a declaration. I think the example function "f" is rather obscure, perhaps there is a better example? Maybe one from the Prelude? Also, there seems to be another point you could make here. Due to laziness we get some more freedom in the way that we write where clauses. For instance, the thing being defined in the where clause may only be well defined in a subset of the alternatives. But that doesn't matter because we will only evaluate the thing if and when it is needed, not before.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. '''page 12'''. Section 4.5, list comprehensions. Perhaps it is worth noting the Haskell does not have the diagonalisation operator like Miranda. It may also be worth remarking on why this is so. Surely it was considered.<br />
<br />
[[User:BerniePope|BerniePope]] 16:05, 15 July 2006 (UTC) Comment. '''page 13'''. Section 5.3 Abstract types. It says that the type has one constructor. Is it really necessary to limit the type to just one constructor? Surely it is enough that the constructors of the type are not exported, regardless of how many there are?<br />
<br />
[[User:BerniePope|BerniePope]] 05:28, 16 July 2006 (UTC) Comment. '''page 14'''. Section 6.1, Type classes. Perhaps it should mention that '''eqInt''' is primitive equality on integers, maybe as a comment in the code.<br />
<br />
[[User:BerniePope|BerniePope]] 05:54, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Monomorphism restriction. This marks one of the most unusual aspects of the language, especially in the Language Report. In particular, it is motivated by operational semantics --- sharing --- but the rest of the Report is largely silent on the issue. I think the Report says something to the effect of "programmers expect sharing to be preserved", but there is not much else in the Report to back this statement up. Perhaps you could tie this back to the discussion in Section 3.4 (Haskell has no formal semantics). Also, I think it would be reasonable to say "GHC provides a flag to suppress the restriction", without actually naming the flag.<br />
<br />
[[User:BerniePope|BerniePope]] 06:02, 16 July 2006 (UTC) Comment. '''page 15'''. Section 6.2 Higher kinded polymorphism. It says "Here, the type variable m has kind *->*". It seems like the reader is already supposed to know what a kind is at this point. Perhaps the section could provide a little introduction to the concept of kinds first. Another thing about kinds is that they are sort of shadowy figures that seem to lurk in the background of Haskell. For instance they have no syntactic counterpart in Haskell 98. It can be quite daunting for beginners when they get a kind error.<br />
<br />
[[User:BerniePope|BerniePope]] 07:30, 16 July 2006 (UTC) Comment. '''page 17'''. Section 6.6 Implicit parameters. Perhaps contrast this approach to a Reader monad?<br />
<br />
[[User:BerniePope|BerniePope]] 07:44, 16 July 2006 (UTC) Comment. '''page 18'''. Arrows. It doesn't really say what arrows are, except that they are like monads, but more general. Perhaps this could be elaborated, maybe with some mention of the intuition that arrows generalise things which are somehow composable? Perhaps an example of an arrow which cannot be done with a monad?<br />
<br />
[[User:BerniePope|BerniePope]] 08:14, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says that "Checking that the laws hold provides a reassuring sanity check when defining a new monad." Perhaps you could elaborate on exactly what we are checking, and subsequently reassured about. It says earlier that the laws show associativity and identity, but is there a more "programmer oriented" view of what this means? <br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. It says monads were helpful in structuring programs, including "the Haskell compiler itself". This sounds like there was a single Haskell compiler. Perhaps it should be "exisiting Haskell compilers"?<br />
<br />
[[User:BerniePope|BerniePope]] 08:22, 16 July 2006 (UTC) Comment. '''page 20'''. Section 7.2 Monads. One of the ongoing issues with monads is combining them together. Perhaps you could mention some of the attempts at doing this, such as monad transformers.<br />
<br />
[[User:BerniePope|BerniePope]] 13:04, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.3 Controlling Evaluation Order. The last paragraph suggests that we can wait until the program is written, then profile, then add seqs as necessary. While this is true, many programs are never really finished. Adding seq to code is one thing, but maintaining code with seq in it is another, perhaps more difficult problem. Also, you might be able to make a link here to the material on speculative evaluation, since that also solves some space/strictness issues.<br />
<br />
[[User:BerniePope|BerniePope]] 13:14, 16 July 2006 (UTC) Comment. '''page 29'''. Section 10.4 Debugging and tracing. It says that hbc and GHC provide trace. Hugs also has trace (perhaps nhc98 does as well?).<br />
<br />
[[User:Hoan|Hoan]] 12:45, 15 July 2006 (UTC) On '''page 33''' it says that Ruby on Rails is a continuation based framework. I think thats wrong. PS. Its a riveting read.<br />
<br />
[[User:BerniePope|BerniePope]] 07:57, 16 July 2006 (UTC) Overall. Names of people. I've noticed that sometimes people are referred to by their whole name, whilst others are referred to by just their family name. Perhaps there is an underlying method here, but it wasn't clear to me. Perhaps it is that the first reference gets a full name, and subsequent ones are just the family name? Is that always the case?</div>Weihuhttps://wiki.haskell.org/index.php?title=Talk:History_of_Haskell/Version_1&diff=4787Talk:History of Haskell/Version 12006-07-15T21:35:49Z<p>Weihu: </p>
<hr />
<div>== Comments on "The History of Haskell" (draft) ==<br />
<br />
Please use the Wiki to add your comments here. Include your name and the date. You can do this with four tildes, like this: <nowiki>~~~~</nowiki>.<br />
<br />
To edit the page, you need to log in: click the login link at the bottom of the window. If you don't already have an account, the login page lets you create one in 30 seconds. See [[HaskellWiki:Contributing]].<br />
<br />
-----------------<br />
<br />
<br />
[[User:Simonpj|Simonpj]] 18:51, 14 July 2006 (UTC) Simon PJ. Here is an example comment<br />
<br />
Typo on page 39: Another example is that Linspire’s ''toold'' must handle legacy data formats. --[[User:NeilMitchell|Neil Mitchell]] 15:23, 14 July 2006 (UTC)<br />
<br />
On page 4 after the list of goals, it seems that the following sentence ("We agreed to base it on an existing language,<br />
namely OL.") should be preceeded by a line break (it now starts on the same line as the sixth goal).<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 20:38, 14 July 2006 (UTC) Other ideas for a title: ''The History of Haskell: Unsuccessfully Avoiding Success'' or something using the motto "Avoid success at all costs." Or perhaps ''Success Considered Harmful, or, A History of Haskell'' or ''Doomed to Succeed'' quoting Hoare (although this sounds somewhat self-congratulatory).<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 22:00, 14 July 2006 (UTC) Section 3.8, last paragraph, syntax error: should be "Miranda is still in use today: it '''is''' still taught in some institutions", missing word. (Sec 4.2 ''This tradition was honed by Moses Schonfinkel and Haskell Curry, and came to be called currying.'' I half expected a joke following this, saying ''[it was] called currying, luckily, and not '''schonfinkeling'''.'') Same section, typo: ''is a list of lists'' should be ''in a list of lists.''<br />
<br />
[[User:JaredUpdike|JaredUpdike]] 04:27, 15 July 2006 (UTC) Section 9.2 misspelling "existance" should be "existence" third to last paragraph. Sec. 9.5 second to last paragraph. ''test bad'' should be ''test bed''.<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:18, 15 July 2006 (UTC) Section 11.2.3 page 34 typo "unsagePerformIO".<br />
<br />
[[User:GaneshSittampalam|GaneshSittampalam]] 09:19, 15 July 2006 (UTC) I really like the "eager to be lazy" title.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Typo: page 2, column 2, "Rod Bustall" should be "Rod Burstall".<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Spelling: page 3, column 1, "confernce".<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Suggestion. Section 3.3, third paragraph. Rather than talk about "div" (are the first quote marks backwards?), perhaps you could say - "for example, Miranda's type system allows floating point values to be given to functions which are only defined on the integer subset of num, thus turning a static error into a dynamic one."<br />
<br />
[[User:Hoan|Hoan]] 12:45, 15 July 2006 (UTC) On page 33 it says that Ruby on Rails is a continuation based framework. I think thats wrong. PS. Its a riveting read.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Expression. page 9. It says "Haskell did not adopt Miranda's abstract data types, using '''its''' module system instead." It is not clear whose module system it is using. Perhaps it should read "using '''a''' module system instead." ?<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Section 4.1, layout. It says "The rules are simple ...". I think this is a contentious issue. Recent discussions on the Haskell Prime mailing list [http://www.haskell.org//pipermail/haskell-prime/2006-March/000898.html] suggested a contrary view. How many Haskellers actually know the rules? Perhaps it would be more accurate to say that experience shows it is not hard to adopt a style of programming which stays within the rules.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Footnote 2 on page 10 says the Scheme authors took a more Draconian approach with respect to operators, though it doesn't actually say what that means. On the off chance that someone reading the paper doesn't know Scheme, it might be worth elaborating on that point.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Section 4.4. Near the end of the section you give an example of "where" being attached to a declaration. I think the example function "f" is rather obscure, perhaps there is a better example? Maybe one from the Prelude? Also, there seems to be another point you could make here. Due to laziness we get some more freedom in the way that we write where clauses. For instance, the thing being defined in the where clause may only be well defined in a subset of the alternatives. But that doesn't matter because we will only evaluate the thing if and when it is needed, not before.<br />
<br />
[[User:BerniePope|BerniePope]] 15:42, 15 July 2006 (UTC) Comment. Section 4.5, list comprehensions. Perhaps it is worth noting the Haskell does not have the diagonalisation operator like Miranda. It may also be worth remarking on why this is so. Surely it was considered.<br />
<br />
[[User:BerniePope|BerniePope]] 15:56, 15 July 2006 (UTC) Tense. Section 5.1, algebraic data types. It says "In general, every algebraic data type specified...", should that be "specifies" ? or perhaps even better "In general, algebraic data types specify" ?<br />
<br />
[[User:BerniePope|BerniePope]] 16:05, 15 July 2006 (UTC) Comment. Section 5.3 Abstract types. It says that the type has one constructor. Is it really necessary to limit the type to just one constructor? Surely it is enough that the constructors of the type are not exported, regardless of how many there are?<br />
<br />
[[User:BerniePope|BerniePope]] 16:15, 15 July 2006 (UTC) Tense. Section 5.3 Abstract types. It says "This had the advantage ...". Perhaps it should be: "This has the advantage", since Miranda still exists, and the advantage still holds. Later in the same paragraph the expression about adopting the feature in Haskell is a bit awkward. Perhaps it could read: "It is not clear how to adapt Miranda's method of defining abstract data types to type classes, and that is one reason we chose a different solution." ?<br />
<br />
[[User:BerniePope|BerniePope]] 16:27, 15 July 2006 (UTC) Typo. Section 5.6, page 14 and in Bibliography. Godel's name in citation missing the 'o'.<br />
<br />
[[User:Weihu|Weihu]] 21:35, 15 July 2006 (UTC) Typo: page 31, column 2, "a central them" should be "a central theme".</div>Weihuhttps://wiki.haskell.org/index.php?title=History_of_Haskell&diff=4786History of Haskell2006-07-15T21:31:13Z<p>Weihu: fixed a typo</p>
<hr />
<div>== The History of Haskell (draft) ==<br />
<br />
Simon Peyton Jones, Phil Wadler, Paul Hudak, and John Hughes<br />
<br />
<br />
Haskell is over 15 years old now, and the four of us have been writing a paper to submit to the [http://research.ihost.com/hopl/ History of Programming Languages conference (HOPL'07)]. We now have a reasonably complete draft, and would like to invite your feedback on it. <br />
<br />
* The draft paper in [http://research.microsoft.com/~simonpj/tmp/history.ps Postscript], and [http://research.microsoft.com/~simonpj/tmp/history.pdf PDF]<br />
<br />
== Giving feedback ==<br />
We have to submit a final version for the beginning of September, so it would be great if you could comment before the middle of August. You can do so in two ways:<br />
* Send us email personally (simonpj@microsoft.com, wadler@inf.ed.ac.uk, paul.hudak@yale.edu, rjmh@cs.chalmers.se)<br />
* Add comments to [[Talk:History of Haskell|the "Talk" page]].<br />
<br />
If you like, you can instead send email to the Haskell Cafe mailing list, but we are less likely to follow that closely.<br />
<br />
== Things to think about ==<br />
Writing a paper like this is a big task, and one that is very different to the sort of research papers that we usually write. So we would really appreciate your help in making it better. Here are something thoughts and questions that we invite you to bear in mind as you read it:<br />
<br />
* We experienced a tremendous tension between<br />
** On the one hand, comprehensiveness and doing justice to all those who have contributed to Haskell<br />
** On the other, keeping the paper "alive". We don't want it to become a boring catalogue of everything that has ever happened to Haskell.<br />
: Please don't feel slighted if we have not mentioned your own fantastic work. Instead, politely correct us. And bear in mind that the above tension means that we just can't include everything.<br />
<br />
* We are interested in feedback at all levels: accuracy, coverage, structure, tone, fairness, level of detail; as well as spelling and grammar. Of these, spelling and grammar are the least important!<br />
<br />
* The applications section is particularly patchy. One possibility would be to include a much longer list of applications and application libraries, but given in much less detail. Please send us suggestions: the name of the application, who wrote it, roughly how big it is, and (where posssible) a citation of some kind that gives more detail.</div>Weihu