CheatSheet 2.5 → 2.6
raw patch · 3 files changed
+1550/−1545 lines, 3 files
Files
- CheatSheet.cabal +1/−1
- CheatSheet.lhs +1549/−1544
- CheatSheet.pdf binary
CheatSheet.cabal view
@@ -1,7 +1,7 @@ Name: CheatSheet License: BSD3 License-File: LICENSE-Version: 2.5+Version: 2.6 Homepage: http://cheatsheet.codeslower.com Maintainer: Justin Bailey <jgbailey@codeslower.com> Author: Justin Bailey <jgbailey@codeslower.com>
CheatSheet.lhs view
@@ -1,1544 +1,1549 @@-\documentclass[11pt]{article}-%include lhs2TeX.fmt-\usepackage[T1]{fontenc}-\usepackage[sc]{mathpazo}-\linespread{1.05}-\usepackage{helvet}--\usepackage{multicol}-\usepackage{float}-\usepackage[landscape, top=0.2in, bottom=1in, left=0.2in, right=0.2in, dvips]{geometry}-\usepackage{verbatim}-\usepackage{fancyhdr}-\usepackage{paralist}-\usepackage[hide]{todo}--\usepackage{hyperref}-\usepackage[all]{hypcap} % Must be after hyperref-% \usepackage{setspace}-\hypersetup{colorlinks}--\pagestyle{fancy}-\fancyhf{}-\lfoot{\copyright\ 2010 Justin Bailey.}-\cfoot{\thepage}-\rfoot{\href{mailto:jgbailey@@codeslower.com}{\tt jgbailey@@codeslower.com}}-\renewcommand\footrulewidth{0.4pt}--\makeatletter-% Copied from article.cls; second-to-last parameter changed to -\parindent.-\renewcommand\subsubsection{\@@startsection{subsubsection}{3}{\z@@}%- {-3.25ex \@@plus -1ex \@@minus -.2ex}%- {-\parindent}%- {\normalfont\normalsize\bfseries}}-\makeatother--\newcommand{\hd}[1]{\section*{\textsf{#1}}}-\newcommand{\shd}[1]{\subsection*{\textsf{#1}}}-\newcommand{\sshd}[1]{\subsubsection*{\textsf{#1}}}-\setlength{\columnsep}{18.0pt}-\setlength{\columnseprule}{0.4pt}-\begin{document}-% \doublespacing-\begin{multicols}{3}-\section*{\textsf{\LARGE Haskell Cheat Sheet\normalsize}}\label{preamble}--This cheat sheet lays out the fundamental elements of the Haskell language:-syntax, keywords and other elements. It is presented as both an executable-Haskell file and a printable document. Load the source into your favorite-interpreter to play with code samples shown.--\begin{comment}--> {-# LANGUAGE MultiParamTypeClasses #-}->-> module CheatSheet where->-> import Data.Char (isUpper, isLower, toUpper, toLower, isSpace, GeneralCategory(..))-> import System.IO (readFile)-> import System.Directory (doesFileExist)-> import qualified Data.Set as Set-> import qualified Data.Char as Char--\end{comment}--\hd{Basic Syntax}\label{syntax}--\shd{Comments}\label{comments}-- A single line comment starts with `@--@' and extends to the end of the line.- Multi-line comments start with '@{-@' and extend to '@-}@'. Comments can be- nested.-- Comments above function definitions should start with `@{- |@' and those next- to parameter types with `@-- ^@' for compatibility with- Haddock, a system for documenting- Haskell code.--\shd{Reserved Words}\label{reserved-words}-- The following words are reserved in Haskell. It is a syntax error to give a- variable or a function one of these names.-- \setlength{\columnsep}{10.0pt}- \setlength{\columnseprule}{0.0pt}- \begin{multicols}{3}- \begin{compactitem}- \item @case@- \item @class@- \item @data@- \item @deriving@- \item @do@- \item @else@- \item @if@- \item @import@- \item @in@- \item @infix@- \item @infixl@- \item @infixr@- \item @instance@- \item @let@- \item @of@- \item @module@- \item @newtype@- \item @then@- \item @type@- \item @where@- \end{compactitem}- \end{multicols}- \setlength{\columnsep}{18.0pt}- \setlength{\columnseprule}{0.4pt}--\shd{Strings}\label{strings}-- \begin{compactitem}- \item @"abc"@ -- Unicode string, sugar for @['a','b','c']@.- \item @'a'@ -- Single character.- \end{compactitem}-- \sshd{Multi-line Strings}\label{multi-line-strings}-- Normally, it is a syntax error if a string has any newline characters.- That is, this is a syntax error:--< string1 = "My long-< string."-- Backslashes (`@\@') can ``escape'' a newline:--> string1 = "My long \-> \string."-- The area between the backslashes is ignored. Newlines \emph{in} the- string must be represented explicitly:--> string2 = "My long \n\-> \string."-- That is, @string1@ evaluates to:--< My long string.-- While @string2@ evaluates to:--< My long-< string.-- \sshd{Escape Codes} The following escape codes can be used in characters or strings:- \begin{compactitem}- \item @\n@, @\r@, @\f@, etc. -- The standard codes for newline, carriage return, form feed, etc. are supported.- \item @\72@, @\x48@, @\o110@ -- A character with the value 72 in decimal, hex and octal, respectively.- \item @\&@ -- The ``null'' escape character, it is used so numeric escape codes can appear next to numeric literals. Equivalent to ``'' and therefore cannot be used in character literals.- \todo{Control characters, ascii codes such as NUL}- \end{compactitem}---\shd{Numbers}\label{numbers}-- \begin{compactitem}- \item @1@ -- Integer or floating point value.- \item @1.0, 1e10@ -- Floating point value.- \item @0o1, 0O1@ -- Octal value.- \item @0x1, 0X1@ -- Hexadecimal value.- \item @-1@ -- Negative number; the minus sign (``@-@'') cannot be separated from the number.- \end{compactitem}--\shd{Enumerations}\label{enumerations}-- \begin{compactitem}- \item @[1..10]@ -- List of numbers -- \texttt{1, 2, {\ensuremath\mathellipsis}, 10}.- \item @[100..]@ -- Infinite list of numbers -- \texttt{100, 101, 102, {\ensuremath\mathellipsis}\ }.- \item @[110..100]@ -- Empty list, but @[110, 109 .. 100]@ will give a list from 110 to 100.- \item @[0, -1 ..]@ -- Negative integers.- \item @[-110..-100]@ -- Syntax error; need @[-110.. -100]@ for negatives.- \item @[1,3..99], [-1,3..99]@ -- List from 1 to 99 by 2, -1 to 99 by 4.- \end{compactitem}-- \noindent In fact, any value which is in the @Enum@ class can be used:-- \begin{compactitem}- \item @['a' .. 'z']@ -- List of characters -- \texttt{a, b, {\ensuremath\mathellipsis}, z}.- \item @['z', 'y' .. 'a']@ -- \texttt{z, y, x, {\ensuremath\mathellipsis}, a}.- \item @[1.0, 1.5 .. 2]@ -- @[1.0,1.5,2.0]@.- \item @[UppercaseLetter ..]@ -- List of @GeneralCategory@ values (from @Data.Char@).- \end{compactitem}--\shd{Lists \& Tuples}\label{lists-tuples}-- \begin{compactitem}- \item @[]@ -- Empty list.- \item @[1,2,3]@ -- List of three numbers.- \item @1 : 2 : 3 : []@ -- Alternate way to write lists using ``cons'' (@:@) and ``nil'' (@[]@).- \item @"abc"@ -- List of three characters (strings are lists).- \item @'a' : 'b' : 'c' : []@ -- List of characters (same as @"abc"@).- \item @(1,"a")@ -- 2-element tuple of a number and a string.- \item @(head, tail, 3, 'a')@ -- 4-element tuple of two functions, a number and a character.- \end{compactitem}--\shd{``Layout'' rule, braces and semi-colons.}\label{layout}-- Haskell can be written using braces and semi-colons, just like C. However, no- one does. Instead, the ``layout'' rule is used, where spaces represent scope.- The general rule is: always indent. When the compiler complains, indent more.-- \sshd{Braces and semi-colons}\label{braces-semicolons}-- Semi-colons terminate an expression, and braces represent scope. They can be- used after several keywords: @where@, @let@, @do@ and @of@. They cannot be- used when defining a function body. For example, the below will not compile.--< square2 x = { x * x; }-- However, this will work fine:--> square2 x = result-> where { result = x * x; }-- \sshd{Function Definition}\label{layout-function-definition}-- Indent the body at least one space from the function name:--< square x =-< x * x-- Unless a @where@ clause is present. In that case, indent the where clause at- least one space from the function name and any function bodies at least one- space from the @where@ keyword:--< square x =-< x2-< where x2 =-< x * x-- \sshd{Let}\label{layout-let}-- Indent the body of the let at least one space from the first definition in the- @let@. If @let@ appears on its own line, the body of any definition must- appear in the column after the let:--< square x =-< let x2 =-< x * x-< in x2-- As can be seen above, the @in@ keyword must also be in the same column as- @let@. Finally, when multiple definitions are given, all identifiers must- appear in the same column.--\hd{Declarations, Etc.}\label{declarations}-- The following section details rules on function declarations, list- comprehensions, and other areas of the language.--\shd{Function Definition}\label{function-definition}-- Functions are defined by declaring their name, any arguments, and an equals- sign:--> square x = x * x-- \emph{All} functions names must start with a lowercase letter or ``@_@''. It- is a syntax error otherwise.-- \sshd{Pattern Matching}\label{pattern-matching}-- Multiple ``clauses'' of a function can be defined by ``pattern-matching'' on- the values of arguments. Here, the @agree@ function has four separate- cases:--> -- Matches when the string "y" is given.-> agree1 "y" = "Great!"-> -- Matches when the string "n" is given.-> agree1 "n" = "Too bad."-> -- Matches when string beginning-> -- with 'y' given.-> agree1 ('y':_) = "YAHOO!"-> -- Matches for any other value given.-> agree1 _ = "SO SAD."-- Note that the `@_@' character is a wildcard and matches any value.-- Pattern matching can extend to nested values. Assuming this data declaration:--< data Bar = Bil (Maybe Int) | Baz-- \noindent and recalling the \hyperref[maybe]{definition of @Maybe@} from- page~\pageref{maybe} we can match on nested @Maybe@ values when @Bil@ is- present:--< f (Bil (Just _)) = ...-< f (Bil Nothing) = ...-< f Baz = ...-- Pattern-matching also allows values to be assigned to variables. For example,- this function determines if the string given is empty or not. If not, the- value bound to @str@ is converted to lower case:--> toLowerStr [] = []-> toLowerStr str = map toLower str-- Note that @str@ above is similer to @_@ in that it will match anything; the- only difference is that the value matched is also given a name.-- \sshd{{\ensuremath $n + k$} Patterns}\label{plus-patterns}-- This (sometimes controversial) pattern-matching facility makes it easy to match- certain kinds of numeric expressions. The idea is to define a base case (the- ``$n$'' portion) with a constant number for matching, and then to define other- matches (the ``$k$'' portion) as additives to the base case. Here is a rather- inefficient way of testing if a number is even or not:--> isEven 0 = True-> isEven 1 = False-> isEven (n + 2) = isEven n-- \sshd{Argument Capture}\label{argument-capture}-- Argument capture is useful for pattern-matching a value \emph{and} using it,- without declaring an extra variable. Use an `|@|' symbol in between the- pattern to match and the variable to bind the value to. This facility is- used below to bind the head of the list in @l@ for display, while also- binding the entire list to @ls@ in order to compute its length:--> len ls@(l:_) = "List starts with " ++-> show l ++ " and is " ++-> show (length ls) ++ " items long."-> len [] = "List is empty!"-- \sshd{Guards}\label{function-guards}-- Boolean functions can be used as ``guards'' in function definitions along with- pattern matching. An example without pattern matching:--> which n-> | n == 0 = "zero!"-> | even n = "even!"-> | otherwise = "odd!"-- Notice @otherwise@ -- it always evaluates to @True@ and can be used to specify- a ``default'' branch.-- Guards can be used with patterns. Here is a function that determines if the- first character in a string is upper or lower case:--> what [] = "empty string!"-> what (c:_)-> | isUpper c = "upper case!"-> | isLower c = "lower case"-> | otherwise = "not a letter!"-- \sshd{Matching \& Guard Order}\label{function-matching-order}-- Pattern-matching proceeds in top to bottom order. Similarly, guard expressions- are tested from top to bottom. For example, neither of these functions would- be very interesting:--> allEmpty _ = False-> allEmpty [] = True->-> alwaysEven n-> | otherwise = False-> | n `div` 2 == 0 = True-- \sshd{Record Syntax}\label{matching-record-syntax}-- Normally pattern matching occurs based on the position of arguments in the- value being matched. Types declared with record syntax, however, can match- based on those record names. Given this data type:--> data Color = C { red-> , green-> , blue :: Int }--\begin{comment}--> deriving (Show, Eq)--\end{comment}-- \noindent we can match on @green@ only:--> isGreenZero (C { green = 0 }) = True-> isGreenZero _ = False-- Argument capture is possible with this syntax, although it gets clunky.- Continuing the above, we now define a @Pixel@ type and a function to replace- values with non-zero @green@ components with all black:--> data Pixel = P Color--\begin{comment}--> deriving (Show, Eq)--\end{comment}--> -- Color value untouched if green is 0-> setGreen (P col@(C { green = 0 })) = P col-> setGreen _ = P (C 0 0 0)-- \sshd{Lazy Patterns}\label{lazy-patterns}-- This syntax, also known as \emph{irrefutable} patterns, allows pattern matches- which always succeed. That means any clause using the pattern will succeed,- but if it tries to actually use the matched value an error may occur. This is- generally useful when an action should be taken on the \emph{type} of a- particular value, even if the value isn't present.-- For example, define a class for default values:--> class Def a where-> defValue :: a -> a-- The idea is you give @defValue@ a value of the right type and it gives you- back a default value for that type. Defining instances for basic types is- easy:--> instance Def Bool where-> defValue _ = False->-> instance Def Char where-> defValue _ = ' '-- @Maybe@ is a littler trickier, because we want to get a default value for the- type, but the constructor might be @Nothing@. The following definition would- work, but it's not optimal since we get @Nothing@ when @Nothing@ is passed in.--< instance Def a => Def (Maybe a) where-< defValue (Just x) = Just (defValue x)-< defValue Nothing = Nothing-- We'd rather get a {\tt Just (\rm\emph{default value}\tt)\rm} back instead.- Here is where a lazy pattern saves us -- we can pretend that we've matched- @Just x@ and use that to get a default value, even if @Nothing@ is given:--> instance Def a => Def (Maybe a) where-> defValue ~(Just x) = Just (defValue x)-- As long as the value @x@ is not actually evaluated, we're safe. None of the- base types need to look at @x@ (see the ``@_@'' matches they use), so things- will work just fine.-- One wrinkle with the above is that we must provide type annotations in the- interpreter or the code when using a @Nothing@ constructor. @Nothing@ has type- @Maybe a@ but, if not enough other information is available, Haskell must be- told what @a@ is. Some example default values:--> -- Return "Just False"-> defMB = defValue (Nothing :: Maybe Bool)-> -- Return "Just ' '"-> defMC = defValue (Nothing :: Maybe Char)--\shd{List Comprehensions}\label{list-comprehensions}-- A list comprehension consists of four types of elements: \emph{generators},- \emph{guards}, \emph{local bindings}, and \emph{targets}. A list comprehension- creates a list of target values based on the generators and guards given. This- comprehension generates all squares:--> squares = [x * x | x <- [1..]]-- @x <- [1..]@ generates a list of all @Integer@ values and puts them in @x@,- one by one. @x * x@ creates each element of the list by multiplying @x@ by- itself.-- Guards allow certain elements to be excluded. The following shows how divisors- for a given number (excluding itself) can be calculated. Notice how @d@ is- used in both the guard and target expression.--> divisors n =-> [d | d <- [1..(n `div` 2)]-> , n `mod` d == 0]-- Local bindings provide new definitions for use in the generated expression or- subsequent generators and guards. Below, @z@ is used to represent the minimum- of @a@ and @b@:--> strange = [(a,z) | a <-[1..3]-> , b <-[1..3]-> , c <- [1..3]-> , let z = min a b-> , z < c ]-- Comprehensions are not limited to numbers. Any list will do. All upper case- letters can be generated:--> ups =-> [c | c <- [minBound .. maxBound]-> , isUpper c]-- Or, to find all occurrences of a particular break value @br@ in a list @word@- (indexing from 0):--> idxs word br =-> [i | (i, c) <- zip [0..] word-> , c == br]-- A unique feature of list comprehensions is that pattern matching failures do- not cause an error; they are just excluded from the resulting list.--\shd{Operators}\label{operators}-- There are very few predefined ``operators'' in Haskell---most that appear- predefined are actually syntax (e.g., ``@=@''). Instead, operators are simply- functions that take two arguments and have special syntactic support. Any- so-called operator can be applied as a prefix function using parentheses:--< 3 + 4 == (+) 3 4-- To define a new operator, simply define it as a normal function, except the- operator appears between the two arguments. Here's one which inserts a- comma between two strings and ensures no extra spaces appear:--> first ## last =-> let trim s = dropWhile isSpace-> (reverse (dropWhile isSpace-> (reverse s)))-> in trim last ++ ", " ++ trim first--< > " Haskell " ## " Curry "-< Curry, Haskell-- Of course, full pattern matching, guards, etc. are available in this form.- Type signatures are a bit different, though. The operator ``name'' must appear- in parentheses:--> (##) :: String -> String -> String-- Allowable symbols which can be used to define operators are:--< # $ % & * + . / < = > ? @ \ ^ | - ~-- However, there are several ``operators'' which cannot be redefined. They are:- @<-@, @->@ and @=@. The last, @=@, cannot be redefined by itself, but can be- used as part of multi-character operator. The ``bind'' function, @>>=@, is one- example.-- \sshd{Precedence \& Associativity}\label{fixity}-- The precedence and associativity, collectively called \emph{fixity}, of any- operator can be set through the @infix@, @infixr@ and @infixl@ keywords. These- can be applied both to top-level functions and to local definitions. The- syntax is:--\bigskip- \textbraceleft\texttt{infix} || \texttt{infixr} || \texttt{infixl}\textbraceright\ \emph{precedence op}-\bigskip-- \noindent where \emph{precedence} varies from 0 to 9. \emph{Op} can actually- be any function which takes two arguments (i.e., any binary operation).- Whether the operator is left or right associative is specified by @infixl@ or- @infixr@, respectively. Such @infix@ declarations have no associativity.-- Precedence and associativity make many of the rules of arithmetic work ``as- expected.'' For example, consider these minor updates to the precedence of- addition and multiplication:--> infixl 8 `plus1`-> plus1 a b = a + b-> infixl 7 `mult1`-> mult1 a b = a * b-- The results are surprising:--< > 2 + 3 * 5-< 17-< > 2 `plus1` 3 `mult1` 5-< 25-- Reversing associativity also has interesting effects. Redefining division as- right associative:--> infixr 7 `div1`-> div1 a b = a / b-- We get interesting results:--< > 20 / 2 / 2-< 5.0-< > 20 `div1` 2 `div1` 2-< 20.0--\shd{Currying}\label{currying}-- In Haskell, functions do not have to get all of their arguments at once. For- example, consider the @convertOnly@ function, which only converts certain- elements of string depending on a test:--> convertOnly test change str =-> map (\c -> if test c-> then change c-> else c) str-- Using @convertOnly@, we can write the @l33t@ function which converts certain- letters to numbers:--> l33t = convertOnly isL33t toL33t-> where-> isL33t 'o' = True-> isL33t 'a' = True-> -- etc.-> isL33t _ = False-> toL33t 'o' = '0'-> toL33t 'a' = '4'-> -- etc.-> toL33t c = c-- Notice that @l33t@ has no arguments specified. Also, the final argument to- @convertOnly@ is not given. However, the type signature of @l33t@ tells the- whole story:--< l33t :: String -> String-- That is, @l33t@ takes a string and produces a string. It is a ``constant'', in- the sense that @l33t@ always returns a value that is a function which takes a- string and produces a string. @l33t@ returns a ``curried'' form of- @convertOnly@, where only two of its three arguments have been supplied.-- This can be taken further. Say we want to write a function which only changes- upper case letters. We know the test to apply, @isUpper@, but we don't want to- specify the conversion. That function can be written as:--> convertUpper = convertOnly isUpper-- which has the type signature:--< convertUpper :: (Char -> Char)-< -> String -> String-- That is, @convertUpper@ can take two arguments. The first is the conversion- function which converts individual characters and the second is the string to- be converted.-- A curried form of any function which takes multiple arguments can be created.- One way to think of this is that each ``arrow'' in the function's signature- represents a new function which can be created by supplying one more argument.-- \sshd{Sections}\label{sections}-- Operators are functions, and they can be curried like any other. For example, a- curried version of ``@+@'' can be written as:--< add10 = (+) 10-- However, this can be unwieldy and hard to read. ``Sections'' are curried- operators, using parentheses. Here is @add10@ using sections:--> add10 = (10 +)-- The supplied argument can be on the right or left, which indicates what- position it should take. This is important for operations such as- concatenation:--> onLeft str = (++ str)-> onRight str = (str ++)-- Which produces quite different results:--< > onLeft "foo" "bar"-< "barfoo"-< > onRight "foo" "bar"-< "foobar"--\shd{``Updating'' values and record syntax}\label{updating}-- Haskell is a pure language and, as such, has no mutable state. That is, once a- value is set it never changes. ``Updating'' is really a copy operation, with- new values in the fields that ``changed.'' For example, using the @Color@ type- defined earlier, we can write a function that sets the @green@ field to zero- easily:--> noGreen1 (C r _ b) = C r 0 b-- The above is a bit verbose and can be rewritten using record syntax. This kind- of ``update'' only sets values for the field(s) specified and copies the rest:--> noGreen2 c = c { green = 0 }-- Here we capture the @Color@ value in @c@ and return a new @Color@ value. That- value happens to have the same value for @red@ and @blue@ as @c@ and it's- @green@ component is 0. We can combine this with pattern matching to set the- @green@ and @blue@ fields to equal the @red@ field:--> makeGrey c@(C { red = r }) =-> c { green = r, blue = r }-- Notice we must use argument capture (``|c@|'') to get the @Color@ value and- pattern matching with record syntax (``|C { red = r}|'') to get the inner- @red@ field.--\shd{Anonymous Functions}\label{anonymous-functions}-- An anonymous function (i.e., a \emph{lambda expression} or \emph{lambda} for- short), is a function without a name. They can be defined at any time like so:--< \c -> (c, c)-- which defines a function that takes an argument and returns a tuple- containing that argument in both positions. They are useful for simple- functions which don't need a name. The following determines if a string- consists only of mixed case letters and whitespace.--> mixedCase str =-> all (\c -> isSpace c ||-> isLower c ||-> isUpper c) str-- Of course, lambdas can be the returned from functions too. This classic- returns a function which will then multiply its argument by the one originally- given:--> multBy n = \m -> n * m-- For example:--< > let mult10 = multBy 10-< > mult10 10-< 100--\shd{Type Signatures}\label{type-signatures}-- Haskell supports full type inference, meaning in most cases no types have to- be written down. Type signatures are still useful for at least two reasons.-- \begin{description}- \item{\emph{Documentation}}---Even if the compiler can figure out the types- of your functions, other programmers or even yourself might not be able to- later. Writing the type signatures on all top-level functions is considered- very good form.-- \item{\emph{Specialization}}---Typeclasses allow functions with overloading.- For example, a function to negate any list of numbers has the signature:--< negateAll :: Num a => [a] -> [a]-- However, for efficiency or other reasons you may only want to allow @Int@- types. You would accomplish that with a type signature:--< negateAll :: [Int] -> [Int]- \end{description}-- Type signatures can appear on top-level functions and nested @let@ or @where@- definitions. Generally this is useful for documentation, although in some- cases they are needed to prevent polymorphism. A type signature is first the- name of the item which will be typed, followed by a @::@, followed by the- types. An example of this has already been seen above.-- Type signatures do not need to appear directly above their implementation.- They can be specified anywhere in the containing module (yes, even below!).- Multiple items with the same signature can also be defined together:--> pos, neg :: Int -> Int--< ...--> pos x | x < 0 = negate x-> | otherwise = x->-> neg y | y > 0 = negate y-> | otherwise = y-- \sshd{Type Annotations}\label{type-annotations}-- Sometimes Haskell cannot determine what type is meant. The classic- demonstration of this is the so-called ``@show . read@'' problem:--< canParseInt x = show (read x)-- Haskell cannot compile that function because it does not know the type of @read x@.- We must limit the type through an annotation:--> canParseInt x = show (read x :: Int)-- Annotations have the same syntax as type signatures, but may adorn- any expression. Note that the annotation above is on the expression- @read x@, not on the variable @x@. Only function application (e.g.,- @read x@) binds tighter than annotations. If that was not the case,- the above would need to be written @(read x) :: Int@.--\shd{Unit}\label{unit}-- @()@ -- ``unit'' type and ``unit'' value. The value and type that represents- no useful information.--\hd{Keywords}\label{keywords}-- Haskell keywords are listed below, in alphabetical order.--\shd{Case}\label{case}-- @case@ is similar to a @switch@ statement in C\# or Java, but can match a- pattern: the shape of the value being inspected. Consider a simple data type:--> data Choices = First String | Second |-> Third | Fourth--\begin{comment}--> deriving (Show, Eq)--\end{comment}-- \noindent @case@ can be used to determine which choice was given:--> whichChoice ch =-> case ch of-> First _ -> "1st!"-> Second -> "2nd!"-> _ -> "Something else."-- As with pattern-matching in function definitions, the `@_@' token is a- ``wildcard'' matching any value.-- \sshd{Nesting \& Capture}\label{nesting-capture}-- Nested matching and binding are also allowed. For example, here is the definition-of the @Maybe@ type:--< data Maybe a = Just a | Nothing-\label{maybe}-- Using @Maybe@ we can determine if any choice was given using a nested match:--> anyChoice1 ch =-> case ch of-> Nothing -> "No choice!"-> Just (First _) -> "First!"-> Just Second -> "Second!"-> _ -> "Something else."-- Binding can be used to manipulate the value matched:--> anyChoice2 ch =-> case ch of-> Nothing -> "No choice!"-> Just score@(First "gold") ->-> "First with gold!"-> Just score@(First _) ->-> "First with something else: "-> ++ show score-> _ -> "Not first."-- \sshd{Matching Order}\label{case-matching-order}-- Matching proceeds from top to bottom. If @anyChoice1@ is reordered as follows,- the first pattern will always succeed:--> anyChoice3 ch =-> case ch of-> _ -> "Something else."-> Nothing -> "No choice!"-> Just (First _) -> "First!"-> Just Second -> "Second!"-- \sshd{Guards}\label{case-guards}-- Guards, or conditional matches, can be used in cases just like function- definitions. The only difference is the use of the @->@ instead of @=@. Here- is a simple function which does a case-insensitive string match:--> strcmp s1 s2 = case (s1, s2) of-> ([], []) -> True-> (s1:ss1, s2:ss2)-> | toUpper s1 == toUpper s2 ->-> strcmp ss1 ss2-> | otherwise -> False-> _ -> False--\shd{Class}\label{class}-- A Haskell function is defined to work on a certain type or set of types and- cannot be defined more than once. Most languages support the idea of- ``overloading'', where a function can have different behavior depending on the- type of its arguments. Haskell accomplishes overloading through @class@ and- @instance@ declarations. A @class@ defines one or more functions that can be- applied to any types which are members (i.e., instances) of that class. A- class is analogous to an interface in Java or C\#, and instances to a concrete- implementation of the interface.-- A class must be declared with one or more type variables. Technically, Haskell- 98 only allows one type variable, but most implementations of Haskell support- so-called \emph{multi-parameter type classes}, which allow more than one type- variable.-- We can define a class which supplies a flavor for a given type:--> class Flavor a where-> flavor :: a -> String-- Notice that the declaration only gives the type signature of the function---no- implementation is given here (with some exceptions, see- \hyperref[defaults]{``Defaults''} on page~\pageref{defaults}). Continuing, we- can define several instances:--> instance Flavor Bool where-> flavor _ = "sweet"->-> instance Flavor Char where-> flavor _ = "sour"-- Evaluating @flavor True@ gives:--< > flavor True-< "sweet"-- While @flavor 'x'@ gives:--< > flavor 'x'-< "sour"--\sshd{Defaults}\label{defaults}-- Default implementations can be given for functions in a class. These are- useful when certain functions can be defined in terms of others in the class.- A default is defined by giving a body to one of the member functions. The- canonical example is @Eq@, which defines @/=@ (not equal) in terms of @==@\ :--< class Eq a where-< (==) :: a -> a -> Bool-< (/=) :: a -> a -> Bool-< (/=) a b = not (a == b)-- Recursive definitions can be created. Continuing the @Eq@ example,- @==@ can be defined in terms of @/=@:--< (==) a b = not (a /= b)-- However, if instances do not provide enough concrete implementations- of member functions then any program using those instances will loop.--\shd{Data}\label{data}-- So-called \emph{algebraic data types} can be declared as follows:--> data MyType = MyValue1 | MyValue2--\begin{comment}--> deriving (Show, Eq)--\end{comment}-- @MyType@ is the type's \emph{name}. @MyValue1@ and @MyValue@ are \emph{values}- of the type and are called \emph{constructors}. Multiple constructors are- separated with the `@|@' character. Note that type and constructor names- \emph{must} start with a capital letter. It is a syntax error otherwise.-- \sshd{Constructors with Arguments}\label{constructors-with-arguments}-- The type above is not very interesting except as an enumeration. Constructors- that take arguments can be declared, allowing more information to be stored:--> data Point = TwoD Int Int-> | ThreeD Int Int Int-- Notice that the arguments for each constructor are \emph{type} names, not- constructors. That means this kind of declaration is illegal:--< data Poly = Triangle TwoD TwoD TwoD-- instead, the @Point@ type must be used:--> data Poly = Triangle Point Point Point-- \sshd{Type and Constructor Names}\label{type-punning}-- Type and constructor names can be the same, because they will never be used in- a place that would cause confusion. For example:--> data User = User String | Admin String-- which declares a type named @User@ with two constructors, @User@ and @Admin@.- Using this type in a function makes the difference clear:--> whatUser (User _) = "normal user."-> whatUser (Admin _) = "admin user."-- Some literature refers to this practice as \emph{type punning}.-- \sshd{Type Variables}\label{type-variables}-- Declaring so-called \emph{polymorphic} data types is as easy as adding type- variables in the declaration:--> data Slot1 a = Slot1 a | Empty1-- This declares a type @Slot1@ with two constructors, @Slot1@ and @Empty1@. The- @Slot1@ constructor can take an argument of \emph{any} type, which is- represented by the type variable @a@ above.-- We can also mix type variables and specific types in constructors:--> data Slot2 a = Slot2 a Int | Empty2-- Above, the @Slot2@ constructor can take a value of any type and an @Int@- value.-- \sshd{Record Syntax}\label{record-syntax}-- Constructor arguments can be declared either positionally, as above, or using- record syntax, which gives a name to each argument. For example, here we- declare a @Contact@ type with names for appropriate arguments:--> data Contact = Contact { ctName :: String-> , ctEmail :: String-> , ctPhone :: String }-- These names are referred to as \emph{selector} or \emph{accessor} functions- and are just that, functions. They must start with a lowercase letter or- underscore and cannot have the same name as another function in scope. Thus- the ``@ct@'' prefix on each above. Multiple constructors (of the same type)- can use the same accessor function for values of the same type, but that can- be dangerous if the accessor is not used by all constructors. Consider this- rather contrived example:--> data Con = Con { conValue :: String }-> | Uncon { conValue :: String }-> | Noncon->-> whichCon con = "convalue is " ++-> conValue con-- If @whichCon@ is called with a @Noncon@ value, a runtime error will occur.-- Finally, as explained elsewhere, these names can be used for pattern matching,- argument capture and ``updating.''-- \sshd{Deriving}\label{deriving}-- Many types have common operations which are tedious to define yet necessary,- such as the ability to convert to and from strings, compare for equality, or- order in a sequence. These capabilities are defined as typeclasses in Haskell.-- Because seven of these operations are so common, Haskell provides the- @deriving@ keyword which will automatically implement the typeclass on the- associated type. The seven supported typeclasses are: @Eq@, @Read@, @Show@,- @Ord@, @Enum@, @Ix@, and @Bounded@.-- Two forms of @deriving@ are possible. The first is used when a type only- derives one class:--> data Priority = Low | Medium | High-> deriving Show-- The second is used when multiple classes are derived:--> data Alarm = Soft | Loud | Deafening-> deriving (Read, Show)-- It is a syntax error to specify @deriving@ for any other classes besides the- seven given above.-- \sshd{Class Constraints}\label{class-constraints}-- Data types can be declared with class constraints on the type variables, but- this practice is discouraged. It is better to hide the- ``raw'' data constructors using the module system and instead export ``smart''- constructors which apply appropriate constraints. In any case, the syntax used- is:--> data (Num a) => SomeNumber a = Two a a-> | Three a a a-- This declares a type @SomeNumber@ which has one type variable argument. Valid- types are those in the @Num@ class.--\shd{Deriving}-- See the section on \hyperref[deriving]{@deriving@} under the @data@ keyword on- page~\pageref{deriving}.--\shd{Do}\label{do}-- The @do@ keyword indicates that the code to follow will be in a \emph{monadic}- context. Statements are separated by newlines, assignment is indicated by- @<-@, and a @let@ form is introduced which does not require the @in@ keyword.-- \sshd{If and IO}\label{if-io}-- @if@ can be tricky when used with IO. Conceptually it is no different from an- @if@ in any other context, but intuitively it is hard to develop. Consider the- function @doesFileExists@ from @System.Directory@:--< doesFileExist :: FilePath -> IO Bool-- The @if@ statement has this ``signature'':--< if-then-else :: Bool -> a -> a -> a-- That is, it takes a @Bool@ value and evaluates to some other value based on- the condition. From the type signatures it is clear that @doesFileExist@- cannot be used directly by @if@:--< wrong fileName =-< if doesFileExist fileName-< then ...-< else ...-- That is, @doesFileExist@ results in an @IO Bool@ value, while @if@ wants a- @Bool@ value. Instead, the correct value must be ``extracted'' by running the- IO action:--> right1 fileName = do-> exists <- doesFileExist fileName-> if exists-> then return 1-> else return 0-- Notice the use of @return@. Because @do@ puts us ``inside'' the @IO@ monad, we- can't ``get out'' except through @return@. Note that we don't have to use @if@- inline here---we can also use @let@ to evaluate the condition and get a value- first:--> right2 fileName = do-> exists <- doesFileExist fileName-> let result =-> if exists-> then 1-> else 0-> return result-- Again, notice where @return@ is. We don't put it in the @let@ statement.- Instead we use it once at the end of the function.-- \sshd{Multiple @do@'s}\label{multiple-dos}-- When using @do@ with @if@ or @case@, another @do@ is required if either branch- has multiple statements. An example with @if@:--> countBytes1 f =-> do-> putStrLn "Enter a filename."-> args <- getLine-> if length args == 0-> -- no 'do'.-> then putStrLn "No filename given."-> else-> -- multiple statements require-> -- a new 'do'.-> do-> f <- readFile args-> putStrLn ("The file is " ++-> show (length f)-> ++ " bytes long.")-- And one with @case@:--> countBytes2 =-> do-> putStrLn "Enter a filename."-> args <- getLine-> case args of-> [] -> putStrLn "No args given."-> file -> do-> f <- readFile file-> putStrLn ("The file is " ++-> show (length f)-> ++ " bytes long.")-- An alternative syntax uses semi-colons and braces. A @do@ is still required,- but indention is unnecessary. This code shows a @case@ example, but the- principle applies to @if@ as well:--> countBytes3 =-> do-> putStrLn "Enter a filename."-> args <- getLine-> case args of-> [] -> putStrLn "No args given."-> file -> do { f <- readFile file;-> putStrLn ("The file is " ++-> show (length f)-> ++ " bytes long."); }--\shd{Export}-- See the section on \hyperref[module]{@module@} on page~\pageref{module}.--\shd{If, Then, Else}\label{if}-- Remember, @if@ always ``returns'' a value. It is an expression, not just a- control flow statement. This function tests if the string given starts with a- lower case letter and, if so, converts it to upper case:--> -- Use pattern-matching to-> -- get first character-> sentenceCase (s:rest) =-> if isLower s-> then toUpper s : rest-> else s : rest-> -- Anything else is empty string-> sentenceCase _ = []--\shd{Import}-- See the section on \hyperref[module]{@module@} on page~\pageref{module}.--\shd{In}-- See \hyperref[let]{@let@} on page~\pageref{let}.--\shd{Infix, infixl and infixr}-- See the section on \hyperref[operators]{operators} on- page~\pageref{operators}.--\shd{Instance}-- See the section on \hyperref[class]{@class@} on page~\pageref{class}.--\shd{Let}\label{let}-- Local functions can be defined within a function using @let@. The @let@- keyword must always be followed by @in@. The @in@ must appear in the same- column as the @let@ keyword. Functions defined have access to all other- functions and variables within the same scope (including those defined by- @let@). In this example, @mult@ multiplies its argument @n@ by @x@, which was- passed to the original @multiples@. @mult@ is used by map to give the- multiples of x up to 10:--> multiples x =-> let mult n = n * x-> in map mult [1..10]-- @let@ ``functions'' with no arguments are actually constants and, once- evaluated, will not evaluate again. This is useful for capturing common- portions of your function and re-using them. Here is a silly example which- gives the sum of a list of numbers, their average, and their median:--> listStats m =-> let numbers = [1,3 .. m]-> total = sum numbers-> mid = head (drop (m `div` 2)-> numbers)-> in "total: " ++ show total ++-> ", mid: " ++ show mid-- \sshd{Deconstruction}\label{deconstruction}-- The left-hand side of a @let@ definition can also destructure its argument, in- case sub-components are to be accessed. This definition would extract the- first three characters from a string--> firstThree str =-> let (a:b:c:_) = str-> in "Initial three characters are: " ++-> show a ++ ", " ++-> show b ++ ", and " ++-> show c-- Note that this is different than the following, which only works if the string- has exactly three characters:--> onlyThree str =-> let (a:b:c:[]) = str-> in "The characters given are: " ++-> show a ++ ", " ++-> show b ++ ", and " ++-> show c--\shd{Of}-- See the section on \hyperref[case]{@case@} on page~\pageref{case}.--\shd{Module}\label{module}-- A module is a compilation unit which exports functions, types, classes,- instances, and other modules. A module can only be defined in one file, though- its exports may come from multiple sources. To make a Haskell file a module,- just add a module declaration at the top:--< module MyModule where-- Module names must start with a capital letter but otherwise can include- periods, numbers and underscores. Periods are used to give sense of structure,- and Haskell compilers will use them as indications of the directory a- particular source file is, but otherwise they have no meaning.-- The Haskell community has standardized a set of top-level module names such as- @Data@, @System@, @Network@, etc. Be sure to consult them for an appropriate- place for your own module if you plan on releasing it to the public.-- \sshd{Imports}\label{imports}-- The Haskell standard libraries are divided into a number of modules. The- functionality provided by those libraries is accessed by importing into your- source file. To import everything exported by a library, just use the- module name:--< import Text.Read-- Everything means \emph{everything}: functions, data types and constructors,- class declarations, and even other modules imported and then exported by the- that module. Importing selectively is accomplished by giving a list of names- to import. For example, here we import some functions from @Text.Read@:--< import Text.Read (readParen, lex)-- Data types can be imported in a number of ways. We can just import the type and- no constructors:--< import Text.Read (Lexeme)-- Of course, this prevents our module from pattern-matching on the values of- type @Lexeme@. We can import one or more constructors explicitly:--< import Text.Read (Lexeme(Ident, Symbol))-- All constructors for a given type can also be imported:--< import Text.Read (Lexeme(..))-- We can also import types and classes defined in the module:--< import Text.Read (Read, ReadS)-- In the case of classes, we can import the functions defined for a class using- syntax similar to importing constructors for data types:--< import Text.Read (Read(readsPrec-< , readList))-- Note that, unlike data types, all class functions are imported unless- explicitly excluded. To \emph{only} import the class, we use this syntax:--< import Text.Read (Read())-- \sshd{Exclusions}\label{exclusions}-- If most, but not all, names are to be imported from a module, it would be- tedious to list them all. For that reason, imports can also be specified via- the @hiding@ keyword:--< import Data.Char hiding (isControl-< , isMark)-- Except for instance declarations, any type, function, constructor or class can- be hidden.-- \sshd{Instance Declarations}\label{instance-declarations}-- It must be noted that @instance@ declarations \emph{cannot} be excluded from- import: all @instance@ declarations in a module will be imported when the- module is imported.-- \sshd{Qualified Imports}\label{qualified-imports}-- The names exported by a module (i.e., functions, types, operators, etc.) can- have a prefix attached through qualified imports. This is particularly useful- for modules which have a large number of functions having the same name as- @Prelude@ functions. @Data.Set@ is a good example:--< import qualified Data.Set as Set-- This form requires any function, type, constructor or other name exported by- @Data.Set@ to now be prefixed with the \emph{alias} (i.e., @Set@) given. Here- is one way to remove all duplicates from a list:--> removeDups a =-> Set.toList (Set.fromList a)-- A second form does not create an alias. Instead, the prefix becomes the module- name. We can write a simple function to check if a string is all upper case:--< import qualified Char--> allUpper str =-> all Char.isUpper str-- Except for the prefix specified, qualified imports support the same syntax as- normal imports. The name imported can be limited in the same ways as described- above.-- \sshd{Exports}\label{exports}-- If an export list is not provided, then all functions, types, constructors,- etc. will be available to anyone importing the module. Note that any imported- modules are \emph{not} exported in this case. Limiting the names exported is- accomplished by adding a parenthesized list of names before the @where@- keyword:--< module MyModule (MyType-< , MyClass-< , myFunc1-< ...)-< where-- The same syntax as used for importing can be used here to specify which- functions, types, constructors, and classes are exported, with a few- differences. If a module imports another module, it can also export that- module:--< module MyBigModule (module Data.Set-< , module Data.Char)-< where-<-< import Data.Set-< import Data.Char-- A module can even re-export itself, which can be useful when all local- definitions and a given imported module are to be exported. Below we export- ourselves and @Data.Set@, but not @Data.Char@:--< module AnotherBigModule (module Data.Set-< , module AnotherBigModule)-< where-<-< import Data.Set-< import Data.Char--\shd{Newtype}\label{newtype}-- While @data@ introduces new values and @type@ just creates synonyms, @newtype@- falls somewhere between. The syntax for @newtype@ is quite restricted---only- one constructor can be defined, and that constructor can only take one- argument. Continuing the above example, we can define a @Phone@ type as- follows:--> newtype Home = H String-> newtype Work = W String-> data Phone = Phone Home Work--\todo[use lowerName?]{lowerName function from above?}-- As opposed to @type@, the @H@ and @W@ ``values'' on @Phone@ are \emph{not}- just @String@ values. The typechecker treats them as entirely new types. That- means our @lowerName@ function from above would not compile. The following- produces a type error:--< lPhone (Phone hm wk) =-< Phone (lower hm) (lower wk)-- Instead, we must use pattern-matching to get to the ``values'' to which we- apply @lower@:--> lPhone (Phone (H hm) (W wk)) =-> Phone (H (lower hm)) (W (lower wk))-- The key observation is that this keyword does not introduce a new value;- instead it introduces a new type. This gives us two very useful properties:-- \begin{compactitem}- \item No runtime cost is associated with the new type, since it does not- actually produce new values. In other words, newtypes are absolutely free!-- \item The type-checker is able to enforce that common types such as @Int@ or- @String@ are used in restricted ways, specified by the programmer.- \end{compactitem}-- Finally, it should be noted that any @deriving@ clause which can be attached- to a @data@ declaration can also be used when declaring a @newtype@.--\shd{Return}-- See \hyperref[do]{@do@} on page~\pageref{do}.--\shd{Type}\label{type}-- This keyword defines a \emph{type synonym} (i.e., alias). This keyword does- not define a new type, like @data@ or @newtype@. It is useful for documenting- code but otherwise has no effect on the actual type of a given function or- value. For example, a @Person@ data type could be defined as:--< data Person = Person String String-- where the first constructor argument represents their first name and the- second their last. However, the order and meaning of the two arguments is not- very clear. A @type@ declaration can help:--> type FirstName = String-> type LastName = String-> data Person = Person FirstName LastName-- Because @type@ introduces a synonym, type checking is not affected in any way.- The function @lower@, defined as:--> lower s = map toLower s-- which has the type--< lower :: String -> String-- can be used on values with the type @FirstName@ or @LastName@ just as easily:--> lName (Person f l ) =-> Person (lower f) (lower l)-- Because @type@ is just a synonym, it cannot declare multiple constructors the- way @data@ can. Type variables can be used, but there cannot be more than the- type variables declared with the original type. That means a synonym like the- following is possible:--< type NotSure a = Maybe a-- but this not:--< type NotSure a b = Maybe a-- Note that \emph{fewer} type variables can be used, which is useful in certain- instances.--\shd{Where}\label{where}-- Similar to @let@, @where@ defines local functions and constants. The scope of- a @where@ definition is the current function. If a function is broken into- multiple definitions through pattern-matching, then the scope of a particular- @where@ clause only applies to that definition. For example, the function- @result@ below has a different meaning depending on the arguments given to the- function @strlen@:--> strlen [] = result-> where result = "No string given!"-> strlen f = result ++ " characters long!"-> where result = show (length f)-- \sshd{Where vs. Let}\label{where-vs-let}-- A @where@ clause can only be defined at the level of a function definition.- Usually, that is identical to the scope of @let@ definition. The only- difference is when guards are being used. The scope of the @where@ clause- extends over all guards. In contrast, the scope of a @let@ expression is only- the current function clause \emph{and} guard, if any.--\hd{Contributors}\label{contributors}-- My thanks to those who contributed patches and useful suggestions:- Dave Bayer, Paul Butler, Elisa Firth, Marc Fontaine, Brian- Gianforcaro, Cale Gibbard, Andrew Harris, Stephen Hicks, Kurt- Hutchinson, Johan Kiviniemi, Adrian Neumann, Barak Pearlmutter, Lanny- Ripple, Markus Roberts, Holger Siegel, Falko Spiller, Adam Vogt, Leif- Warner, and Jeff Zaroyko.--\hd{Version}\label{version}-- This is version 2.5. The source can be found at GitHub- (\url{http://github.com/m4dc4p/cheatsheet}). The latest released- version of the PDF can be downloaded from- \url{http://cheatsheet.codeslower.com}. Visit CodeSlower.com- (\url{http://blog.codeslower.com/}) for other projects and writings.--\todos-\end{multicols}-\end{document}--% vim:set tw=80:+\documentclass[11pt]{article} +%include lhs2TeX.fmt +\usepackage[T1]{fontenc} +\usepackage[sc]{mathpazo} +\linespread{1.05} +\usepackage{helvet} + +\usepackage{multicol} +\usepackage{float} +\usepackage[landscape, top=0.2in, bottom=1in, left=0.2in, right=0.2in, dvips]{geometry} +\usepackage{verbatim} +\usepackage{fancyhdr} +\usepackage{paralist} +\usepackage[hide]{todo} + +\usepackage{hyperref} +\usepackage[all]{hypcap} % Must be after hyperref +% \usepackage{setspace} +\hypersetup{colorlinks} + +\pagestyle{fancy} +\fancyhf{} +\lfoot{\copyright\ 2010 Justin Bailey.} +\cfoot{\thepage} +\rfoot{\href{mailto:jgbailey@@codeslower.com}{\tt jgbailey@@codeslower.com}} +\renewcommand\footrulewidth{0.4pt} + +\makeatletter +% Copied from article.cls; second-to-last parameter changed to -\parindent. +\renewcommand\subsubsection{\@@startsection{subsubsection}{3}{\z@@}% + {-3.25ex \@@plus -1ex \@@minus -.2ex}% + {-\parindent}% + {\normalfont\normalsize\bfseries}} +\makeatother + +\newcommand{\hd}[1]{\section*{\textsf{#1}}} +\newcommand{\shd}[1]{\subsection*{\textsf{#1}}} +\newcommand{\sshd}[1]{\subsubsection*{\textsf{#1}}} +\setlength{\columnsep}{18.0pt} +\setlength{\columnseprule}{0.4pt} +\begin{document} +% \doublespacing +\begin{multicols}{3} +\section*{\textsf{\LARGE Haskell Cheat Sheet\normalsize}}\label{preamble} + +This cheat sheet lays out the fundamental elements of the Haskell language: +syntax, keywords and other elements. It is presented as both an executable +Haskell file and a printable document. Load the source into your favorite +interpreter to play with code samples shown. + +\begin{comment} + +> {-# LANGUAGE MultiParamTypeClasses #-} +> +> module CheatSheet where +> +> import Data.Char (isUpper, isLower, toUpper, toLower, isSpace, GeneralCategory(..)) +> import System.IO (readFile) +> import System.Directory (doesFileExist) +> import qualified Data.Set as Set +> import qualified Data.Char as Char + +\end{comment} + +\hd{Basic Syntax}\label{syntax} + +\shd{Comments}\label{comments} + + A single line comment starts with `@--@' and extends to the end of the line. + Multi-line comments start with '@{-@' and extend to '@-}@'. Comments can be + nested. + + Comments above function definitions should start with `@{- |@' and those next + to parameter types with `@-- ^@' for compatibility with + Haddock, a system for documenting + Haskell code. + +\shd{Reserved Words}\label{reserved-words} + + The following words are reserved in Haskell. It is a syntax error to give a + variable or a function one of these names. + + \setlength{\columnsep}{10.0pt} + \setlength{\columnseprule}{0.0pt} + \begin{multicols}{3} + \begin{compactitem} + \item @case@ + \item @class@ + \item @data@ + \item @deriving@ + \item @do@ + \item @else@ + \item @if@ + \item @import@ + \item @in@ + \item @infix@ + \item @infixl@ + \item @infixr@ + \item @instance@ + \item @let@ + \item @of@ + \item @module@ + \item @newtype@ + \item @then@ + \item @type@ + \item @where@ + \end{compactitem} + \end{multicols} + \setlength{\columnsep}{18.0pt} + \setlength{\columnseprule}{0.4pt} + +\shd{Strings}\label{strings} + + \begin{compactitem} + \item @"abc"@ -- Unicode string, sugar for @['a','b','c']@. + \item @'a'@ -- Single character. + \end{compactitem} + + \sshd{Multi-line Strings}\label{multi-line-strings} + + Normally, it is a syntax error if a string has any newline characters. + That is, this is a syntax error: + +< string1 = "My long +< string." + + Backslashes (`@\@') can ``escape'' a newline: + +> string1 = "My long \ +> \string." + + The area between the backslashes is ignored. Newlines \emph{in} the + string must be represented explicitly: + +> string2 = "My long \n\ +> \string." + + That is, @string1@ evaluates to: + +< My long string. + + While @string2@ evaluates to: + +< My long +< string. + + \sshd{Escape Codes} The following escape codes can be used in characters or strings: + \begin{compactitem} + \item @\n@, @\r@, @\f@, etc. -- The standard codes for newline, + carriage return, form feed, etc. are supported. + \item @\72@, @\x48@, @\o110@ -- A character with the value 72 in + decimal, hex and octal, respectively. + \item @\&@ -- A ``null'' escape character which allows numeric + escape codes next to numeric literals. For example, @\x2C4@ is + $\wedge$ (in Unicode) while @\x2C\&4@ is @,4@. This sequence + cannot be used in character literals. \todo{Control characters, + ascii codes such as NUL} + \end{compactitem} + + +\shd{Numbers}\label{numbers} + + \begin{compactitem} + \item @1@ -- Integer or floating point value. + \item @1.0, 1e10@ -- Floating point value. + \item @0o1, 0O1@ -- Octal value. + \item @0x1, 0X1@ -- Hexadecimal value. + \item @-1@ -- Negative number; the minus sign (``@-@'') cannot be separated from the number. + \end{compactitem} + +\shd{Enumerations}\label{enumerations} + + \begin{compactitem} + \item @[1..10]@ -- List of numbers -- \texttt{1, 2, {\ensuremath\mathellipsis}, 10}. + \item @[100..]@ -- Infinite list of numbers -- \texttt{100, 101, 102, {\ensuremath\mathellipsis}\ }. + \item @[110..100]@ -- Empty list, but @[110, 109 .. 100]@ will give a list from 110 to 100. + \item @[0, -1 ..]@ -- Negative integers. + \item @[-110..-100]@ -- Syntax error; need @[-110.. -100]@ for negatives. + \item @[1,3..99], [-1,3..99]@ -- List from 1 to 99 by 2, -1 to 99 by 4. + \end{compactitem} + + \noindent In fact, any value which is in the @Enum@ class can be used: + + \begin{compactitem} + \item @['a' .. 'z']@ -- List of characters -- \texttt{a, b, {\ensuremath\mathellipsis}, z}. + \item @['z', 'y' .. 'a']@ -- \texttt{z, y, x, {\ensuremath\mathellipsis}, a}. + \item @[1.0, 1.5 .. 2]@ -- @[1.0,1.5,2.0]@. + \item @[UppercaseLetter ..]@ -- List of @GeneralCategory@ values (from @Data.Char@). + \end{compactitem} + +\shd{Lists \& Tuples}\label{lists-tuples} + + \begin{compactitem} + \item @[]@ -- Empty list. + \item @[1,2,3]@ -- List of three numbers. + \item @1 : 2 : 3 : []@ -- Alternate way to write lists using ``cons'' (@:@) and ``nil'' (@[]@). + \item @"abc"@ -- List of three characters (strings are lists). + \item @'a' : 'b' : 'c' : []@ -- List of characters (same as @"abc"@). + \item @(1,"a")@ -- 2-element tuple of a number and a string. + \item @(head, tail, 3, 'a')@ -- 4-element tuple of two functions, a number and a character. + \end{compactitem} + +\shd{``Layout'' rule, braces and semi-colons.}\label{layout} + + Haskell can be written using braces and semi-colons, just like C. However, no + one does. Instead, the ``layout'' rule is used, where spaces represent scope. + The general rule is: always indent. When the compiler complains, indent more. + + \sshd{Braces and semi-colons}\label{braces-semicolons} + + Semi-colons terminate an expression, and braces represent scope. They can be + used after several keywords: @where@, @let@, @do@ and @of@. They cannot be + used when defining a function body. For example, the below will not compile. + +< square2 x = { x * x; } + + However, this will work fine: + +> square2 x = result +> where { result = x * x; } + + \sshd{Function Definition}\label{layout-function-definition} + + Indent the body at least one space from the function name: + +< square x = +< x * x + + Unless a @where@ clause is present. In that case, indent the where clause at + least one space from the function name and any function bodies at least one + space from the @where@ keyword: + +< square x = +< x2 +< where x2 = +< x * x + + \sshd{Let}\label{layout-let} + + Indent the body of the let at least one space from the first definition in the + @let@. If @let@ appears on its own line, the body of any definition must + appear in the column after the let: + +< square x = +< let x2 = +< x * x +< in x2 + + As can be seen above, the @in@ keyword must also be in the same column as + @let@. Finally, when multiple definitions are given, all identifiers must + appear in the same column. + +\hd{Declarations, Etc.}\label{declarations} + + The following section details rules on function declarations, list + comprehensions, and other areas of the language. + +\shd{Function Definition}\label{function-definition} + + Functions are defined by declaring their name, any arguments, and an equals + sign: + +> square x = x * x + + \emph{All} functions names must start with a lowercase letter or ``@_@''. It + is a syntax error otherwise. + + \sshd{Pattern Matching}\label{pattern-matching} + + Multiple ``clauses'' of a function can be defined by ``pattern-matching'' on + the values of arguments. Here, the @agree@ function has four separate + cases: + +> -- Matches when the string "y" is given. +> agree1 "y" = "Great!" +> -- Matches when the string "n" is given. +> agree1 "n" = "Too bad." +> -- Matches when string beginning +> -- with 'y' given. +> agree1 ('y':_) = "YAHOO!" +> -- Matches for any other value given. +> agree1 _ = "SO SAD." + + Note that the `@_@' character is a wildcard and matches any value. + + Pattern matching can extend to nested values. Assuming this data declaration: + +< data Bar = Bil (Maybe Int) | Baz + + \noindent and recalling the \hyperref[maybe]{definition of @Maybe@} from + page~\pageref{maybe} we can match on nested @Maybe@ values when @Bil@ is + present: + +< f (Bil (Just _)) = ... +< f (Bil Nothing) = ... +< f Baz = ... + + Pattern-matching also allows values to be assigned to variables. For example, + this function determines if the string given is empty or not. If not, the + value bound to @str@ is converted to lower case: + +> toLowerStr [] = [] +> toLowerStr str = map toLower str + + Note that @str@ above is similer to @_@ in that it will match anything; the + only difference is that the value matched is also given a name. + + \sshd{{\ensuremath $n + k$} Patterns}\label{plus-patterns} + + This (sometimes controversial) pattern-matching facility makes it easy to match + certain kinds of numeric expressions. The idea is to define a base case (the + ``$n$'' portion) with a constant number for matching, and then to define other + matches (the ``$k$'' portion) as additives to the base case. Here is a rather + inefficient way of testing if a number is even or not: + +> isEven 0 = True +> isEven 1 = False +> isEven (n + 2) = isEven n + + \sshd{Argument Capture}\label{argument-capture} + + Argument capture is useful for pattern-matching a value \emph{and} using it, + without declaring an extra variable. Use an `|@|' symbol in between the + pattern to match and the variable to bind the value to. This facility is + used below to bind the head of the list in @l@ for display, while also + binding the entire list to @ls@ in order to compute its length: + +> len ls@(l:_) = "List starts with " ++ +> show l ++ " and is " ++ +> show (length ls) ++ " items long." +> len [] = "List is empty!" + + \sshd{Guards}\label{function-guards} + + Boolean functions can be used as ``guards'' in function definitions along with + pattern matching. An example without pattern matching: + +> which n +> | n == 0 = "zero!" +> | even n = "even!" +> | otherwise = "odd!" + + Notice @otherwise@ -- it always evaluates to @True@ and can be used to specify + a ``default'' branch. + + Guards can be used with patterns. Here is a function that determines if the + first character in a string is upper or lower case: + +> what [] = "empty string!" +> what (c:_) +> | isUpper c = "upper case!" +> | isLower c = "lower case" +> | otherwise = "not a letter!" + + \sshd{Matching \& Guard Order}\label{function-matching-order} + + Pattern-matching proceeds in top to bottom order. Similarly, guard expressions + are tested from top to bottom. For example, neither of these functions would + be very interesting: + +> allEmpty _ = False +> allEmpty [] = True +> +> alwaysEven n +> | otherwise = False +> | n `div` 2 == 0 = True + + \sshd{Record Syntax}\label{matching-record-syntax} + + Normally pattern matching occurs based on the position of arguments in the + value being matched. Types declared with record syntax, however, can match + based on those record names. Given this data type: + +> data Color = C { red +> , green +> , blue :: Int } + +\begin{comment} + +> deriving (Show, Eq) + +\end{comment} + + \noindent we can match on @green@ only: + +> isGreenZero (C { green = 0 }) = True +> isGreenZero _ = False + + Argument capture is possible with this syntax, although it gets clunky. + Continuing the above, we now define a @Pixel@ type and a function to replace + values with non-zero @green@ components with all black: + +> data Pixel = P Color + +\begin{comment} + +> deriving (Show, Eq) + +\end{comment} + +> -- Color value untouched if green is 0 +> setGreen (P col@(C { green = 0 })) = P col +> setGreen _ = P (C 0 0 0) + + \sshd{Lazy Patterns}\label{lazy-patterns} + + This syntax, also known as \emph{irrefutable} patterns, allows pattern matches + which always succeed. That means any clause using the pattern will succeed, + but if it tries to actually use the matched value an error may occur. This is + generally useful when an action should be taken on the \emph{type} of a + particular value, even if the value isn't present. + + For example, define a class for default values: + +> class Def a where +> defValue :: a -> a + + The idea is you give @defValue@ a value of the right type and it gives you + back a default value for that type. Defining instances for basic types is + easy: + +> instance Def Bool where +> defValue _ = False +> +> instance Def Char where +> defValue _ = ' ' + + @Maybe@ is a littler trickier, because we want to get a default value for the + type, but the constructor might be @Nothing@. The following definition would + work, but it's not optimal since we get @Nothing@ when @Nothing@ is passed in. + +< instance Def a => Def (Maybe a) where +< defValue (Just x) = Just (defValue x) +< defValue Nothing = Nothing + + We'd rather get a {\tt Just (\rm\emph{default value}\tt)\rm} back instead. + Here is where a lazy pattern saves us -- we can pretend that we've matched + @Just x@ and use that to get a default value, even if @Nothing@ is given: + +> instance Def a => Def (Maybe a) where +> defValue ~(Just x) = Just (defValue x) + + As long as the value @x@ is not actually evaluated, we're safe. None of the + base types need to look at @x@ (see the ``@_@'' matches they use), so things + will work just fine. + + One wrinkle with the above is that we must provide type annotations in the + interpreter or the code when using a @Nothing@ constructor. @Nothing@ has type + @Maybe a@ but, if not enough other information is available, Haskell must be + told what @a@ is. Some example default values: + +> -- Return "Just False" +> defMB = defValue (Nothing :: Maybe Bool) +> -- Return "Just ' '" +> defMC = defValue (Nothing :: Maybe Char) + +\shd{List Comprehensions}\label{list-comprehensions} + + A list comprehension consists of four types of elements: \emph{generators}, + \emph{guards}, \emph{local bindings}, and \emph{targets}. A list comprehension + creates a list of target values based on the generators and guards given. This + comprehension generates all squares: + +> squares = [x * x | x <- [1..]] + + @x <- [1..]@ generates a list of all @Integer@ values and puts them in @x@, + one by one. @x * x@ creates each element of the list by multiplying @x@ by + itself. + + Guards allow certain elements to be excluded. The following shows how divisors + for a given number (excluding itself) can be calculated. Notice how @d@ is + used in both the guard and target expression. + +> divisors n = +> [d | d <- [1..(n `div` 2)] +> , n `mod` d == 0] + + Local bindings provide new definitions for use in the generated expression or + subsequent generators and guards. Below, @z@ is used to represent the minimum + of @a@ and @b@: + +> strange = [(a,z) | a <-[1..3] +> , b <-[1..3] +> , c <- [1..3] +> , let z = min a b +> , z < c ] + + Comprehensions are not limited to numbers. Any list will do. All upper case + letters can be generated: + +> ups = +> [c | c <- [minBound .. maxBound] +> , isUpper c] + + Or, to find all occurrences of a particular break value @br@ in a list @word@ + (indexing from 0): + +> idxs word br = +> [i | (i, c) <- zip [0..] word +> , c == br] + + A unique feature of list comprehensions is that pattern matching failures do + not cause an error; they are just excluded from the resulting list. + +\shd{Operators}\label{operators} + + There are very few predefined ``operators'' in Haskell---most that appear + predefined are actually syntax (e.g., ``@=@''). Instead, operators are simply + functions that take two arguments and have special syntactic support. Any + so-called operator can be applied as a prefix function using parentheses: + +< 3 + 4 == (+) 3 4 + + To define a new operator, simply define it as a normal function, except the + operator appears between the two arguments. Here's one which inserts a + comma between two strings and ensures no extra spaces appear: + +> first ## last = +> let trim s = dropWhile isSpace +> (reverse (dropWhile isSpace +> (reverse s))) +> in trim last ++ ", " ++ trim first + +< > " Haskell " ## " Curry " +< Curry, Haskell + + Of course, full pattern matching, guards, etc. are available in this form. + Type signatures are a bit different, though. The operator ``name'' must appear + in parentheses: + +> (##) :: String -> String -> String + + Allowable symbols which can be used to define operators are: + +< # $ % & * + . / < = > ? @ \ ^ | - ~ + + However, there are several ``operators'' which cannot be redefined. They are: + @<-@, @->@ and @=@. The last, @=@, cannot be redefined by itself, but can be + used as part of multi-character operator. The ``bind'' function, @>>=@, is one + example. + + \sshd{Precedence \& Associativity}\label{fixity} + + The precedence and associativity, collectively called \emph{fixity}, of any + operator can be set through the @infix@, @infixr@ and @infixl@ keywords. These + can be applied both to top-level functions and to local definitions. The + syntax is: + +\bigskip + \textbraceleft\texttt{infix} || \texttt{infixr} || \texttt{infixl}\textbraceright\ \emph{precedence op} +\bigskip + + \noindent where \emph{precedence} varies from 0 to 9. \emph{Op} can actually + be any function which takes two arguments (i.e., any binary operation). + Whether the operator is left or right associative is specified by @infixl@ or + @infixr@, respectively. Such @infix@ declarations have no associativity. + + Precedence and associativity make many of the rules of arithmetic work ``as + expected.'' For example, consider these minor updates to the precedence of + addition and multiplication: + +> infixl 8 `plus1` +> plus1 a b = a + b +> infixl 7 `mult1` +> mult1 a b = a * b + + The results are surprising: + +< > 2 + 3 * 5 +< 17 +< > 2 `plus1` 3 `mult1` 5 +< 25 + + Reversing associativity also has interesting effects. Redefining division as + right associative: + +> infixr 7 `div1` +> div1 a b = a / b + + We get interesting results: + +< > 20 / 2 / 2 +< 5.0 +< > 20 `div1` 2 `div1` 2 +< 20.0 + +\shd{Currying}\label{currying} + + In Haskell, functions do not have to get all of their arguments at once. For + example, consider the @convertOnly@ function, which only converts certain + elements of string depending on a test: + +> convertOnly test change str = +> map (\c -> if test c +> then change c +> else c) str + + Using @convertOnly@, we can write the @l33t@ function which converts certain + letters to numbers: + +> l33t = convertOnly isL33t toL33t +> where +> isL33t 'o' = True +> isL33t 'a' = True +> -- etc. +> isL33t _ = False +> toL33t 'o' = '0' +> toL33t 'a' = '4' +> -- etc. +> toL33t c = c + + Notice that @l33t@ has no arguments specified. Also, the final argument to + @convertOnly@ is not given. However, the type signature of @l33t@ tells the + whole story: + +< l33t :: String -> String + + That is, @l33t@ takes a string and produces a string. It is a ``constant'', in + the sense that @l33t@ always returns a value that is a function which takes a + string and produces a string. @l33t@ returns a ``curried'' form of + @convertOnly@, where only two of its three arguments have been supplied. + + This can be taken further. Say we want to write a function which only changes + upper case letters. We know the test to apply, @isUpper@, but we don't want to + specify the conversion. That function can be written as: + +> convertUpper = convertOnly isUpper + + which has the type signature: + +< convertUpper :: (Char -> Char) +< -> String -> String + + That is, @convertUpper@ can take two arguments. The first is the conversion + function which converts individual characters and the second is the string to + be converted. + + A curried form of any function which takes multiple arguments can be created. + One way to think of this is that each ``arrow'' in the function's signature + represents a new function which can be created by supplying one more argument. + + \sshd{Sections}\label{sections} + + Operators are functions, and they can be curried like any other. For example, a + curried version of ``@+@'' can be written as: + +< add10 = (+) 10 + + However, this can be unwieldy and hard to read. ``Sections'' are curried + operators, using parentheses. Here is @add10@ using sections: + +> add10 = (10 +) + + The supplied argument can be on the right or left, which indicates what + position it should take. This is important for operations such as + concatenation: + +> onLeft str = (++ str) +> onRight str = (str ++) + + Which produces quite different results: + +< > onLeft "foo" "bar" +< "barfoo" +< > onRight "foo" "bar" +< "foobar" + +\shd{``Updating'' values and record syntax}\label{updating} + + Haskell is a pure language and, as such, has no mutable state. That is, once a + value is set it never changes. ``Updating'' is really a copy operation, with + new values in the fields that ``changed.'' For example, using the @Color@ type + defined earlier, we can write a function that sets the @green@ field to zero + easily: + +> noGreen1 (C r _ b) = C r 0 b + + The above is a bit verbose and can be rewritten using record syntax. This kind + of ``update'' only sets values for the field(s) specified and copies the rest: + +> noGreen2 c = c { green = 0 } + + Here we capture the @Color@ value in @c@ and return a new @Color@ value. That + value happens to have the same value for @red@ and @blue@ as @c@ and it's + @green@ component is 0. We can combine this with pattern matching to set the + @green@ and @blue@ fields to equal the @red@ field: + +> makeGrey c@(C { red = r }) = +> c { green = r, blue = r } + + Notice we must use argument capture (``|c@|'') to get the @Color@ value and + pattern matching with record syntax (``|C { red = r}|'') to get the inner + @red@ field. + +\shd{Anonymous Functions}\label{anonymous-functions} + + An anonymous function (i.e., a \emph{lambda expression} or \emph{lambda} for + short), is a function without a name. They can be defined at any time like so: + +< \c -> (c, c) + + which defines a function that takes an argument and returns a tuple + containing that argument in both positions. They are useful for simple + functions which don't need a name. The following determines if a string + consists only of mixed case letters and whitespace. + +> mixedCase str = +> all (\c -> isSpace c || +> isLower c || +> isUpper c) str + + Of course, lambdas can be the returned from functions too. This classic + returns a function which will then multiply its argument by the one originally + given: + +> multBy n = \m -> n * m + + For example: + +< > let mult10 = multBy 10 +< > mult10 10 +< 100 + +\shd{Type Signatures}\label{type-signatures} + + Haskell supports full type inference, meaning in most cases no types have to + be written down. Type signatures are still useful for at least two reasons. + + \begin{description} + \item{\emph{Documentation}}---Even if the compiler can figure out the types + of your functions, other programmers or even yourself might not be able to + later. Writing the type signatures on all top-level functions is considered + very good form. + + \item{\emph{Specialization}}---Typeclasses allow functions with overloading. + For example, a function to negate any list of numbers has the signature: + +< negateAll :: Num a => [a] -> [a] + + However, for efficiency or other reasons you may only want to allow @Int@ + types. You would accomplish that with a type signature: + +< negateAll :: [Int] -> [Int] + \end{description} + + Type signatures can appear on top-level functions and nested @let@ or @where@ + definitions. Generally this is useful for documentation, although in some + cases they are needed to prevent polymorphism. A type signature is first the + name of the item which will be typed, followed by a @::@, followed by the + types. An example of this has already been seen above. + + Type signatures do not need to appear directly above their implementation. + They can be specified anywhere in the containing module (yes, even below!). + Multiple items with the same signature can also be defined together: + +> pos, neg :: Int -> Int + +< ... + +> pos x | x < 0 = negate x +> | otherwise = x +> +> neg y | y > 0 = negate y +> | otherwise = y + + \sshd{Type Annotations}\label{type-annotations} + + Sometimes Haskell cannot determine what type is meant. The classic + demonstration of this is the so-called ``@show . read@'' problem: + +< canParseInt x = show (read x) + + Haskell cannot compile that function because it does not know the type of @read x@. + We must limit the type through an annotation: + +> canParseInt x = show (read x :: Int) + + Annotations have the same syntax as type signatures, but may adorn + any expression. Note that the annotation above is on the expression + @read x@, not on the variable @x@. Only function application (e.g., + @read x@) binds tighter than annotations. If that was not the case, + the above would need to be written @(read x) :: Int@. + +\shd{Unit}\label{unit} + + @()@ -- ``unit'' type and ``unit'' value. The value and type that represents + no useful information. + +\hd{Keywords}\label{keywords} + + Haskell keywords are listed below, in alphabetical order. + +\shd{Case}\label{case} + + @case@ is similar to a @switch@ statement in C\# or Java, but can match a + pattern: the shape of the value being inspected. Consider a simple data type: + +> data Choices = First String | Second | +> Third | Fourth + +\begin{comment} + +> deriving (Show, Eq) + +\end{comment} + + \noindent @case@ can be used to determine which choice was given: + +> whichChoice ch = +> case ch of +> First _ -> "1st!" +> Second -> "2nd!" +> _ -> "Something else." + + As with pattern-matching in function definitions, the `@_@' token is a + ``wildcard'' matching any value. + + \sshd{Nesting \& Capture}\label{nesting-capture} + + Nested matching and binding are also allowed. For example, here is the definition +of the @Maybe@ type: + +< data Maybe a = Just a | Nothing +\label{maybe} + + Using @Maybe@ we can determine if any choice was given using a nested match: + +> anyChoice1 ch = +> case ch of +> Nothing -> "No choice!" +> Just (First _) -> "First!" +> Just Second -> "Second!" +> _ -> "Something else." + + Binding can be used to manipulate the value matched: + +> anyChoice2 ch = +> case ch of +> Nothing -> "No choice!" +> Just score@(First "gold") -> +> "First with gold!" +> Just score@(First _) -> +> "First with something else: " +> ++ show score +> _ -> "Not first." + + \sshd{Matching Order}\label{case-matching-order} + + Matching proceeds from top to bottom. If @anyChoice1@ is reordered as follows, + the first pattern will always succeed: + +> anyChoice3 ch = +> case ch of +> _ -> "Something else." +> Nothing -> "No choice!" +> Just (First _) -> "First!" +> Just Second -> "Second!" + + \sshd{Guards}\label{case-guards} + + Guards, or conditional matches, can be used in cases just like function + definitions. The only difference is the use of the @->@ instead of @=@. Here + is a simple function which does a case-insensitive string match: + +> strcmp s1 s2 = case (s1, s2) of +> ([], []) -> True +> (s1:ss1, s2:ss2) +> | toUpper s1 == toUpper s2 -> +> strcmp ss1 ss2 +> | otherwise -> False +> _ -> False + +\shd{Class}\label{class} + + A Haskell function is defined to work on a certain type or set of types and + cannot be defined more than once. Most languages support the idea of + ``overloading'', where a function can have different behavior depending on the + type of its arguments. Haskell accomplishes overloading through @class@ and + @instance@ declarations. A @class@ defines one or more functions that can be + applied to any types which are members (i.e., instances) of that class. A + class is analogous to an interface in Java or C\#, and instances to a concrete + implementation of the interface. + + A class must be declared with one or more type variables. Technically, Haskell + 98 only allows one type variable, but most implementations of Haskell support + so-called \emph{multi-parameter type classes}, which allow more than one type + variable. + + We can define a class which supplies a flavor for a given type: + +> class Flavor a where +> flavor :: a -> String + + Notice that the declaration only gives the type signature of the function---no + implementation is given here (with some exceptions, see + \hyperref[defaults]{``Defaults''} on page~\pageref{defaults}). Continuing, we + can define several instances: + +> instance Flavor Bool where +> flavor _ = "sweet" +> +> instance Flavor Char where +> flavor _ = "sour" + + Evaluating @flavor True@ gives: + +< > flavor True +< "sweet" + + While @flavor 'x'@ gives: + +< > flavor 'x' +< "sour" + +\sshd{Defaults}\label{defaults} + + Default implementations can be given for functions in a class. These are + useful when certain functions can be defined in terms of others in the class. + A default is defined by giving a body to one of the member functions. The + canonical example is @Eq@, which defines @/=@ (not equal) in terms of @==@\ : + +< class Eq a where +< (==) :: a -> a -> Bool +< (/=) :: a -> a -> Bool +< (/=) a b = not (a == b) + + Recursive definitions can be created. Continuing the @Eq@ example, + @==@ can be defined in terms of @/=@: + +< (==) a b = not (a /= b) + + However, if instances do not provide enough concrete implementations + of member functions then any program using those instances will loop. + +\shd{Data}\label{data} + + So-called \emph{algebraic data types} can be declared as follows: + +> data MyType = MyValue1 | MyValue2 + +\begin{comment} + +> deriving (Show, Eq) + +\end{comment} + + @MyType@ is the type's \emph{name}. @MyValue1@ and @MyValue@ are \emph{values} + of the type and are called \emph{constructors}. Multiple constructors are + separated with the `@|@' character. Note that type and constructor names + \emph{must} start with a capital letter. It is a syntax error otherwise. + + \sshd{Constructors with Arguments}\label{constructors-with-arguments} + + The type above is not very interesting except as an enumeration. Constructors + that take arguments can be declared, allowing more information to be stored: + +> data Point = TwoD Int Int +> | ThreeD Int Int Int + + Notice that the arguments for each constructor are \emph{type} names, not + constructors. That means this kind of declaration is illegal: + +< data Poly = Triangle TwoD TwoD TwoD + + instead, the @Point@ type must be used: + +> data Poly = Triangle Point Point Point + + \sshd{Type and Constructor Names}\label{type-punning} + + Type and constructor names can be the same, because they will never be used in + a place that would cause confusion. For example: + +> data User = User String | Admin String + + which declares a type named @User@ with two constructors, @User@ and @Admin@. + Using this type in a function makes the difference clear: + +> whatUser (User _) = "normal user." +> whatUser (Admin _) = "admin user." + + Some literature refers to this practice as \emph{type punning}. + + \sshd{Type Variables}\label{type-variables} + + Declaring so-called \emph{polymorphic} data types is as easy as adding type + variables in the declaration: + +> data Slot1 a = Slot1 a | Empty1 + + This declares a type @Slot1@ with two constructors, @Slot1@ and @Empty1@. The + @Slot1@ constructor can take an argument of \emph{any} type, which is + represented by the type variable @a@ above. + + We can also mix type variables and specific types in constructors: + +> data Slot2 a = Slot2 a Int | Empty2 + + Above, the @Slot2@ constructor can take a value of any type and an @Int@ + value. + + \sshd{Record Syntax}\label{record-syntax} + + Constructor arguments can be declared either positionally, as above, or using + record syntax, which gives a name to each argument. For example, here we + declare a @Contact@ type with names for appropriate arguments: + +> data Contact = Contact { ctName :: String +> , ctEmail :: String +> , ctPhone :: String } + + These names are referred to as \emph{selector} or \emph{accessor} functions + and are just that, functions. They must start with a lowercase letter or + underscore and cannot have the same name as another function in scope. Thus + the ``@ct@'' prefix on each above. Multiple constructors (of the same type) + can use the same accessor function for values of the same type, but that can + be dangerous if the accessor is not used by all constructors. Consider this + rather contrived example: + +> data Con = Con { conValue :: String } +> | Uncon { conValue :: String } +> | Noncon +> +> whichCon con = "convalue is " ++ +> conValue con + + If @whichCon@ is called with a @Noncon@ value, a runtime error will occur. + + Finally, as explained elsewhere, these names can be used for pattern matching, + argument capture and ``updating.'' + + \sshd{Deriving}\label{deriving} + + Many types have common operations which are tedious to define yet necessary, + such as the ability to convert to and from strings, compare for equality, or + order in a sequence. These capabilities are defined as typeclasses in Haskell. + + Because seven of these operations are so common, Haskell provides the + @deriving@ keyword which will automatically implement the typeclass on the + associated type. The seven supported typeclasses are: @Eq@, @Read@, @Show@, + @Ord@, @Enum@, @Ix@, and @Bounded@. + + Two forms of @deriving@ are possible. The first is used when a type only + derives one class: + +> data Priority = Low | Medium | High +> deriving Show + + The second is used when multiple classes are derived: + +> data Alarm = Soft | Loud | Deafening +> deriving (Read, Show) + + It is a syntax error to specify @deriving@ for any other classes besides the + seven given above. + + \sshd{Class Constraints}\label{class-constraints} + + Data types can be declared with class constraints on the type variables, but + this practice is discouraged. It is better to hide the + ``raw'' data constructors using the module system and instead export ``smart'' + constructors which apply appropriate constraints. In any case, the syntax used + is: + +> data (Num a) => SomeNumber a = Two a a +> | Three a a a + + This declares a type @SomeNumber@ which has one type variable argument. Valid + types are those in the @Num@ class. + +\shd{Deriving} + + See the section on \hyperref[deriving]{@deriving@} under the @data@ keyword on + page~\pageref{deriving}. + +\shd{Do}\label{do} + + The @do@ keyword indicates that the code to follow will be in a \emph{monadic} + context. Statements are separated by newlines, assignment is indicated by + @<-@, and a @let@ form is introduced which does not require the @in@ keyword. + + \sshd{If and IO}\label{if-io} + + @if@ can be tricky when used with IO. Conceptually it is no different from an + @if@ in any other context, but intuitively it is hard to develop. Consider the + function @doesFileExists@ from @System.Directory@: + +< doesFileExist :: FilePath -> IO Bool + + The @if@ statement has this ``signature'': + +< if-then-else :: Bool -> a -> a -> a + + That is, it takes a @Bool@ value and evaluates to some other value based on + the condition. From the type signatures it is clear that @doesFileExist@ + cannot be used directly by @if@: + +< wrong fileName = +< if doesFileExist fileName +< then ... +< else ... + + That is, @doesFileExist@ results in an @IO Bool@ value, while @if@ wants a + @Bool@ value. Instead, the correct value must be ``extracted'' by running the + IO action: + +> right1 fileName = do +> exists <- doesFileExist fileName +> if exists +> then return 1 +> else return 0 + + Notice the use of @return@. Because @do@ puts us ``inside'' the @IO@ monad, we + can't ``get out'' except through @return@. Note that we don't have to use @if@ + inline here---we can also use @let@ to evaluate the condition and get a value + first: + +> right2 fileName = do +> exists <- doesFileExist fileName +> let result = +> if exists +> then 1 +> else 0 +> return result + + Again, notice where @return@ is. We don't put it in the @let@ statement. + Instead we use it once at the end of the function. + + \sshd{Multiple @do@'s}\label{multiple-dos} + + When using @do@ with @if@ or @case@, another @do@ is required if either branch + has multiple statements. An example with @if@: + +> countBytes1 f = +> do +> putStrLn "Enter a filename." +> args <- getLine +> if length args == 0 +> -- no 'do'. +> then putStrLn "No filename given." +> else +> -- multiple statements require +> -- a new 'do'. +> do +> f <- readFile args +> putStrLn ("The file is " ++ +> show (length f) +> ++ " bytes long.") + + And one with @case@: + +> countBytes2 = +> do +> putStrLn "Enter a filename." +> args <- getLine +> case args of +> [] -> putStrLn "No args given." +> file -> do +> f <- readFile file +> putStrLn ("The file is " ++ +> show (length f) +> ++ " bytes long.") + + An alternative syntax uses semi-colons and braces. A @do@ is still required, + but indention is unnecessary. This code shows a @case@ example, but the + principle applies to @if@ as well: + +> countBytes3 = +> do +> putStrLn "Enter a filename." +> args <- getLine +> case args of +> [] -> putStrLn "No args given." +> file -> do { f <- readFile file; +> putStrLn ("The file is " ++ +> show (length f) +> ++ " bytes long."); } + +\shd{Export} + + See the section on \hyperref[module]{@module@} on page~\pageref{module}. + +\shd{If, Then, Else}\label{if} + + Remember, @if@ always ``returns'' a value. It is an expression, not just a + control flow statement. This function tests if the string given starts with a + lower case letter and, if so, converts it to upper case: + +> -- Use pattern-matching to +> -- get first character +> sentenceCase (s:rest) = +> if isLower s +> then toUpper s : rest +> else s : rest +> -- Anything else is empty string +> sentenceCase _ = [] + +\shd{Import} + + See the section on \hyperref[module]{@module@} on page~\pageref{module}. + +\shd{In} + + See \hyperref[let]{@let@} on page~\pageref{let}. + +\shd{Infix, infixl and infixr} + + See the section on \hyperref[operators]{operators} on + page~\pageref{operators}. + +\shd{Instance} + + See the section on \hyperref[class]{@class@} on page~\pageref{class}. + +\shd{Let}\label{let} + + Local functions can be defined within a function using @let@. The @let@ + keyword must always be followed by @in@. The @in@ must appear in the same + column as the @let@ keyword. Functions defined have access to all other + functions and variables within the same scope (including those defined by + @let@). In this example, @mult@ multiplies its argument @n@ by @x@, which was + passed to the original @multiples@. @mult@ is used by map to give the + multiples of x up to 10: + +> multiples x = +> let mult n = n * x +> in map mult [1..10] + + @let@ ``functions'' with no arguments are actually constants and, once + evaluated, will not evaluate again. This is useful for capturing common + portions of your function and re-using them. Here is a silly example which + gives the sum of a list of numbers, their average, and their median: + +> listStats m = +> let numbers = [1,3 .. m] +> total = sum numbers +> mid = head (drop (m `div` 2) +> numbers) +> in "total: " ++ show total ++ +> ", mid: " ++ show mid + + \sshd{Deconstruction}\label{deconstruction} + + The left-hand side of a @let@ definition can also destructure its argument, in + case sub-components are to be accessed. This definition would extract the + first three characters from a string + +> firstThree str = +> let (a:b:c:_) = str +> in "Initial three characters are: " ++ +> show a ++ ", " ++ +> show b ++ ", and " ++ +> show c + + Note that this is different than the following, which only works if the string + has exactly three characters: + +> onlyThree str = +> let (a:b:c:[]) = str +> in "The characters given are: " ++ +> show a ++ ", " ++ +> show b ++ ", and " ++ +> show c + +\shd{Of} + + See the section on \hyperref[case]{@case@} on page~\pageref{case}. + +\shd{Module}\label{module} + + A module is a compilation unit which exports functions, types, classes, + instances, and other modules. A module can only be defined in one file, though + its exports may come from multiple sources. To make a Haskell file a module, + just add a module declaration at the top: + +< module MyModule where + + Module names must start with a capital letter but otherwise can include + periods, numbers and underscores. Periods are used to give sense of structure, + and Haskell compilers will use them as indications of the directory a + particular source file is, but otherwise they have no meaning. + + The Haskell community has standardized a set of top-level module names such as + @Data@, @System@, @Network@, etc. Be sure to consult them for an appropriate + place for your own module if you plan on releasing it to the public. + + \sshd{Imports}\label{imports} + + The Haskell standard libraries are divided into a number of modules. The + functionality provided by those libraries is accessed by importing into your + source file. To import everything exported by a library, just use the + module name: + +< import Text.Read + + Everything means \emph{everything}: functions, data types and constructors, + class declarations, and even other modules imported and then exported by the + that module. Importing selectively is accomplished by giving a list of names + to import. For example, here we import some functions from @Text.Read@: + +< import Text.Read (readParen, lex) + + Data types can be imported in a number of ways. We can just import the type and + no constructors: + +< import Text.Read (Lexeme) + + Of course, this prevents our module from pattern-matching on the values of + type @Lexeme@. We can import one or more constructors explicitly: + +< import Text.Read (Lexeme(Ident, Symbol)) + + All constructors for a given type can also be imported: + +< import Text.Read (Lexeme(..)) + + We can also import types and classes defined in the module: + +< import Text.Read (Read, ReadS) + + In the case of classes, we can import the functions defined for a class using + syntax similar to importing constructors for data types: + +< import Text.Read (Read(readsPrec +< , readList)) + + Note that, unlike data types, all class functions are imported unless + explicitly excluded. To \emph{only} import the class, we use this syntax: + +< import Text.Read (Read()) + + \sshd{Exclusions}\label{exclusions} + + If most, but not all, names are to be imported from a module, it would be + tedious to list them all. For that reason, imports can also be specified via + the @hiding@ keyword: + +< import Data.Char hiding (isControl +< , isMark) + + Except for instance declarations, any type, function, constructor or class can + be hidden. + + \sshd{Instance Declarations}\label{instance-declarations} + + It must be noted that @instance@ declarations \emph{cannot} be excluded from + import: all @instance@ declarations in a module will be imported when the + module is imported. + + \sshd{Qualified Imports}\label{qualified-imports} + + The names exported by a module (i.e., functions, types, operators, etc.) can + have a prefix attached through qualified imports. This is particularly useful + for modules which have a large number of functions having the same name as + @Prelude@ functions. @Data.Set@ is a good example: + +< import qualified Data.Set as Set + + This form requires any function, type, constructor or other name exported by + @Data.Set@ to now be prefixed with the \emph{alias} (i.e., @Set@) given. Here + is one way to remove all duplicates from a list: + +> removeDups a = +> Set.toList (Set.fromList a) + + A second form does not create an alias. Instead, the prefix becomes the module + name. We can write a simple function to check if a string is all upper case: + +< import qualified Char + +> allUpper str = +> all Char.isUpper str + + Except for the prefix specified, qualified imports support the same syntax as + normal imports. The name imported can be limited in the same ways as described + above. + + \sshd{Exports}\label{exports} + + If an export list is not provided, then all functions, types, constructors, + etc. will be available to anyone importing the module. Note that any imported + modules are \emph{not} exported in this case. Limiting the names exported is + accomplished by adding a parenthesized list of names before the @where@ + keyword: + +< module MyModule (MyType +< , MyClass +< , myFunc1 +< ...) +< where + + The same syntax as used for importing can be used here to specify which + functions, types, constructors, and classes are exported, with a few + differences. If a module imports another module, it can also export that + module: + +< module MyBigModule (module Data.Set +< , module Data.Char) +< where +< +< import Data.Set +< import Data.Char + + A module can even re-export itself, which can be useful when all local + definitions and a given imported module are to be exported. Below we export + ourselves and @Data.Set@, but not @Data.Char@: + +< module AnotherBigModule (module Data.Set +< , module AnotherBigModule) +< where +< +< import Data.Set +< import Data.Char + +\shd{Newtype}\label{newtype} + + While @data@ introduces new values and @type@ just creates synonyms, @newtype@ + falls somewhere between. The syntax for @newtype@ is quite restricted---only + one constructor can be defined, and that constructor can only take one + argument. Continuing the above example, we can define a @Phone@ type as + follows: + +> newtype Home = H String +> newtype Work = W String +> data Phone = Phone Home Work + +\todo[use lowerName?]{lowerName function from above?} + + As opposed to @type@, the @H@ and @W@ ``values'' on @Phone@ are \emph{not} + just @String@ values. The typechecker treats them as entirely new types. That + means our @lowerName@ function from above would not compile. The following + produces a type error: + +< lPhone (Phone hm wk) = +< Phone (lower hm) (lower wk) + + Instead, we must use pattern-matching to get to the ``values'' to which we + apply @lower@: + +> lPhone (Phone (H hm) (W wk)) = +> Phone (H (lower hm)) (W (lower wk)) + + The key observation is that this keyword does not introduce a new value; + instead it introduces a new type. This gives us two very useful properties: + + \begin{compactitem} + \item No runtime cost is associated with the new type, since it does not + actually produce new values. In other words, newtypes are absolutely free! + + \item The type-checker is able to enforce that common types such as @Int@ or + @String@ are used in restricted ways, specified by the programmer. + \end{compactitem} + + Finally, it should be noted that any @deriving@ clause which can be attached + to a @data@ declaration can also be used when declaring a @newtype@. + +\shd{Return} + + See \hyperref[do]{@do@} on page~\pageref{do}. + +\shd{Type}\label{type} + + This keyword defines a \emph{type synonym} (i.e., alias). This keyword does + not define a new type, like @data@ or @newtype@. It is useful for documenting + code but otherwise has no effect on the actual type of a given function or + value. For example, a @Person@ data type could be defined as: + +< data Person = Person String String + + where the first constructor argument represents their first name and the + second their last. However, the order and meaning of the two arguments is not + very clear. A @type@ declaration can help: + +> type FirstName = String +> type LastName = String +> data Person = Person FirstName LastName + + Because @type@ introduces a synonym, type checking is not affected in any way. + The function @lower@, defined as: + +> lower s = map toLower s + + which has the type + +< lower :: String -> String + + can be used on values with the type @FirstName@ or @LastName@ just as easily: + +> lName (Person f l ) = +> Person (lower f) (lower l) + + Because @type@ is just a synonym, it cannot declare multiple constructors the + way @data@ can. Type variables can be used, but there cannot be more than the + type variables declared with the original type. That means a synonym like the + following is possible: + +< type NotSure a = Maybe a + + but this not: + +< type NotSure a b = Maybe a + + Note that \emph{fewer} type variables can be used, which is useful in certain + instances. + +\shd{Where}\label{where} + + Similar to @let@, @where@ defines local functions and constants. The scope of + a @where@ definition is the current function. If a function is broken into + multiple definitions through pattern-matching, then the scope of a particular + @where@ clause only applies to that definition. For example, the function + @result@ below has a different meaning depending on the arguments given to the + function @strlen@: + +> strlen [] = result +> where result = "No string given!" +> strlen f = result ++ " characters long!" +> where result = show (length f) + + \sshd{Where vs. Let}\label{where-vs-let} + + A @where@ clause can only be defined at the level of a function definition. + Usually, that is identical to the scope of @let@ definition. The only + difference is when guards are being used. The scope of the @where@ clause + extends over all guards. In contrast, the scope of a @let@ expression is only + the current function clause \emph{and} guard, if any. + +\hd{Contributors}\label{contributors} + + My thanks to those who contributed patches and useful suggestions: + Dave Bayer, Paul Butler, Elisa Firth, Marc Fontaine, Brian + Gianforcaro, Cale Gibbard, Andrew Harris, Stephen Hicks, Kurt + Hutchinson, Johan Kiviniemi, Adrian Neumann, Barak Pearlmutter, Lanny + Ripple, Markus Roberts, Holger Siegel, Falko Spiller, Adam Vogt, Leif + Warner, and Jeff Zaroyko. + +\hd{Version}\label{version} + + This is version 2.6. The source can be found at GitHub + (\url{http://github.com/m4dc4p/cheatsheet}). The latest released + version of the PDF can be downloaded from + \url{http://cheatsheet.codeslower.com}. Visit CodeSlower.com + (\url{http://blog.codeslower.com/}) for other projects and writings. + +\todos +\end{multicols} +\end{document} + +% vim:set tw=80:
CheatSheet.pdf view
binary file changed (166195 → 166851 bytes)