Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Haskell Cheatsheet

Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

Haskell Cheat Sheet

Strings

Enumerations
[1..10] List of numbers 1, 2, . . ., 10. [100..] Innite list of numbers 100, 101, 102, . . . . [110..100] Empty list; ranges only go forwards. [0, -1 ..] Negative integers. [-100..-110] Syntax error; need [-100.. -110] for negatives. [1,3..100], [-1,3..100] List from 1 to 100 by 2, -1 to 100 by 4. In fact, any value which is in the Enum class can be used: ['a' .. 'z'] List of characters a, b, . . ., z. [1.0, 1.5 .. 2] [1.0,1.5,2.0]. [UppercaseLetter ..] List of GeneralCategory values (from Data.Char).

"abc" Unicode string, sugar for This cheat sheet lays out the fundamental elements ['a','b','c']. of the Haskell language: syntax, keywords and 'a' Single character. other elements. It is presented as both an executable Haskell le and a printable document. Normally, it is a syntax error Load the source into your favorite interpreter to Multi-line Strings if a string has any actual newline characters. That play with code samples shown. is, this is a syntax error:

Basic Syntax
Comments

string1 = "My long string."


Backslashes (\) can escape a newline:

string1 = "My long \ A single line comment starts with -- and extends \string." to the end of the line. Multi-line comments start with {- and extend to -}. Comments can be The area between the backslashes is ignored. Newnested. lines in the string must be represented explicitly: Comments above function denitions should string2 = "My long \n\ start with {- | and those next to parameter types 1 \string." with -- ^ for compatibility with Haddock , a system for documenting Haskell code. That is, string1 evaluates to:

Lists & Tuples


[] Empty list. [1,2,3] List of three numbers. 1 : 2 : 3 : [] Alternate way to write lists using cons (:) and nil ([]). "abc" List of three characters (strings are lists). 'a' : 'b' : 'c' : [] List of characters (same as "abc"). (1,"a") 2-element tuple of a number and a string. (head, tail, 3, 'a') 4-element tuple of two functions, a number and a character.

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.

My long string.
While string2 evaluates to:

My long string.

case class data deriving do else if

import in infix infixl infixr instance let

of module newtype then type where

Numbers

1 Integer or Floating point 1.0, 1e10 Floating point 1. syntax error -1 sugar for (negate 1) 2-1 sugar for ((-) 2 1)

1 http://haskell.org/haddock/

c 2009 Justin Bailey.

jgbailey@codeslower.com

Nested matching and bindLet Indent the body of the let at least one space Nesting & Capture from the rst denition in the let. If let appears ing are also allowed. Haskell can be written using braces and semi- on its own line, the body of any denition must colons, just like C. However, no one does. Instead, appear in the column after the let: data Maybe a = Just a | Nothing the layout rule is used, where spaces represent square x = scope. The general rule is: always indent. When Figure 1: The denition of Maybe let x2 = the compiler complains, indent more. x * x Using Maybe we can determine if any choice was in x2 Braces and semi-colons Semi-colons termigiven using a nested match: nate an expression, and braces represent scope. As can be seen above, the in keyword must also be anyChoice1 ch = They can be used after several keywords: where, in the same column as let. Finally, when multiple case ch of let, do and of. They cannot be used when den- denitions are given, all identiers must appear in Nothing -> "No choice!" ing a function body. For example, the below will the same column. Just (First _) -> "First!" not compile. Just Second -> "Second!" Keywords square2 x = { x * x; } _ -> "Something else." However, this will work ne: Haskell keywords are listed below, in alphabetical Binding can be used to manipulate the value order. matched:

Layout rule, braces and semi-colons.

square2 x = result where { result = x * x; }

Case

case is similar to a switch statement in C# or Java, Function Denition Indent the body at least but can match a pattern: the shape of the value being inspected. Consider a simple data type: one space from the function name: square x = x * x data Choices = First String | Second | Third | Fourth

case can be used to determine which choice was Unless a where clause is present. In that case, in- given: dent the where clause at least one space from the Matching Order Matching proceeds from top to whichChoice ch = function name and any function bodies at least one bottom. If anyChoice1 is reordered as follows, the case ch of space from the where keyword: rst pattern will always succeed: First _ -> "1st!" Second -> "2nd!" square x = anyChoice3 ch = _ -> "Something else." x2 case ch of where x2 = _ -> "Something else." As with pattern-matching in function denitions, x * x the _ token is a wildcard matching any value. Nothing -> "No choice!"
c 2009 Justin Bailey. 2

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."

jgbailey@codeslower.com

Just (First _) -> "First!" Just Second -> "Second!"


Guards Guards, or conditional matches, can be used in cases just like function denitions. 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

Class
A Haskell function is dened to work on a certain type or set of types and cannot be dened 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 denes 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 multi-parameter type classes, which allow more than one type variable. We can dene a class which supplies a avor for a given type: c 2009 Justin Bailey.

So-called algebraic data types can be declared as folNotice that the declaration only gives the type lows: signature of the functionno implementation is data MyType = MyValue1 | MyValue2 given here (with some exceptions, see Defaults on page 3). Continuing, we can dene several inMyType is the types name. MyValue1 and stances: MyValue are values of the type and are called constructors. Multiple constructors are separated with instance Flavor Bool where the | character. Note that type and constructor flavor _ = "sweet" names must start with a capital letter. It is a syntax error otherwise. instance Flavor Char where flavor _ = "sour" Constructors with Arguments The type above Evaluating flavor True gives: is not very interesting except as an enumeration. Constructors that take arguments can be declared, > flavor True allowing more information to be stored: "sweet" While flavor 'x' gives:

class Flavor a where flavor :: a -> String

Data

> flavor 'x' "sour"

data Point = TwoD Int Int | ThreeD Int Int Int


Notice that the arguments for each constructor are type names, not constructors. That means this kind of declaration is illegal:

Defaults Default implementations can be given data Poly = Triangle TwoD TwoD TwoD for functions in a class. These are useful when certain functions can be dened in terms of others in instead, the Point type must be used: the class. A default is dened by giving a body to data Poly = Triangle Point Point Point one of the member functions. The canonical example is Eq, which denes /= (not equal) in terms of ==. : Type and Constructor Names Type and constructor names can be the same, because they will class Eq a where never be used in a place that would cause confu(==) :: a -> a -> Bool sion. For example: (/=) :: a -> a -> Bool (/=) a b = not (a == b) data User = User String | Admin String Recursive denitions can be created, but an which declares a type named User with two coninstance declaration must always implement at structors, User and Admin. Using this type in a least one class member. function makes the difference clear: 3

jgbailey@codeslower.com

Because seven of these operations are so comsame accessor function for values of the same type, but that can be dangerous if the accessor is not used mon, Haskell provides the deriving keyword by all constructors. Consider this rather contrived which will automatically implement the typeclass Some literature refers to this practice as type punon the associated type. The seven supported typeexample: ning. classes are: Eq, Read, Show, Ord, Enum, Ix, and data Con = Con { conValue :: String } Bounded. | Uncon { conValue :: String } Type Variables Declaring so-called polymorphic Two forms of deriving are possible. The rst is | Noncon data types is as easy as adding type variables in used when a type only derives one class: the declaration: whichCon con = "convalue is " ++ data Slot1 a = Slot1 a | Empty1 data Priority = Low | Medium | High conValue con deriving Show This declares a type Slot1 with two constructors, If whichCon is called with a Noncon value, a runtime Slot1 and Empty1. The Slot1 constructor can take error will occur. an argument of any type, which is represented by Finally, as explained elsewhere, these names The second is used when multiple classes are dethe type variable a above. can be used for pattern matching, argument cap- rived: We can also mix type variables and specic ture and updating. types in constructors: data Alarm = Soft | Loud | Deafening data Slot2 a = Slot2 a Int | Empty2 deriving (Read, Show) Class Constraints Data types can be declared Above, the Slot2 constructor can take a value of with class constraints on the type variables, but this practice is generally discouraged. It is gener- It is a syntax error to specify deriving for any other any type and an Int value. ally better to hide the raw data constructors us- classes besides the six given above. ing the module system and instead export smart Record Syntax Constructor arguments can be constructors which apply appropriate constraints. declared either positionally, as above, or using In any case, the syntax used is: record syntax, which gives a name to each arguDeriving ment. For example, here we declare a Contact type data (Num a) => SomeNumber a = Two a a See the section on deriving under the data keywith names for appropriate arguments: | Three a a a word on page 4. data Contact = Contact { ctName :: String This declares a type SomeNumber which has one , ctEmail :: String type variable argument. Valid types are those in , ctPhone :: String } the Num class. Do These names are referred to as selector or 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 prex on each above. Multiple constructors (of the same type) can use the c 2009 Justin Bailey. Deriving Many types have common operations which are tedious to dene yet necessary, such as the ability to convert to and from strings, compare for equality, or order in a sequence. These capabilities are dened as typeclasses in Haskell. 4 The do keyword indicates that the code to follow will be in a monadic context. Statements are separated by newlines, assignment is indicated by <-, and a let form is introduce which does not require the in keyword.

whatUser (User _) = "normal user." whatUser (Admin _) = "admin user."

jgbailey@codeslower.com

If and 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:

let result = if exists then 1 else 0 return result

file -> do f <- readFile file putStrLn ("The file is " ++ show (length f) ++ " bytes long.")

doesFileExist :: FilePath -> IO Bool


The if statement has this signature:

if-then-else :: Bool -> a -> a -> a

Again, notice where return is. We dont put it in An alternative syntax uses semi-colons and braces. the let statement. Instead we use it once at the end A do is still required, but indention is unnecessary. This code shows a case example, but the principle of the function. applies to if as well:

When using do with if or case, That is, it takes a Bool value and evaluates to some Multiple dos other value based on the condition. From the type another do is required if either branch has multiple signatures it is clear that doesFileExist cannot be statements. An example with if: used directly by if: countBytes1 f = do wrong fileName = putStrLn "Enter a filename." if doesFileExist fileName args <- getLine then ... if length args == 0 else ... -- no 'do'. That is, doesFileExist results in an IO Bool value, then putStrLn "No filename given." while if wants a Bool value. Instead, the correct else value must be extracted by running the IO ac-- multiple statements require tion: -- a new 'do'. do right1 fileName = do f <- readFile args exists <- doesFileExist fileName putStrLn ("The file is " ++ if exists show (length f) then return 1 ++ " bytes long.") else return 0 Notice the use of return. Because do puts us in- And one with case: side the IO monad, we cant get out except countBytes2 = through return. Note that we dont have to use do if inline herewe can also use let to evaluate the putStrLn "Enter a filename." condition and get a value rst: args <- getLine case args of right2 fileName = do [] -> putStrLn "No args given." exists <- doesFileExist fileName c 2009 Justin Bailey. 5

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."); }

Export
See the section on module on page 6.

If, Then, Else


Remember, if always returns a value. It is an expression, not just a control ow 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 jgbailey@codeslower.com

silly example which gives the sum of a list of num- A module can only be dened in one le, though its exports may come from multiple sources. To bers, their average, and their median: make a Haskell le a module, just add a module listStats m = declaration at the top: Import let numbers = [1,3 .. m] total = sum numbers module MyModule where See the section on module on page 6. mid = head (take (m `div` 2) Module names must start with a capital letter but numbers) In otherwise can include periods, numbers and unin "total: " ++ show total ++ derscores. Periods are used to give sense of struc", mid: " ++ show mid See let on page 6. ture, and Haskell compilers will use them as indications of the directory a particular source le is, Deconstruction The left-hand side of a let defInx, inxl and inxr but otherwise they have no meaning. inition can also destructure its argument, in case The Haskell community has standardized a set See the section on operators on page 11. sub-components are to be accessed. This denition of top-level module names such as Data, System, would extract the rst three characters from a string Network, etc. Be sure to consult them for an approInstance firstThree str = priate place for your own module if you plan on let (a:b:c:_) = str See the section on class on page 3. releasing it to the public. in "Initial three characters are: " ++ show a ++ ", " ++ Imports The Haskell standard libraries are diLet show b ++ ", and " ++ vided into a number of modules. The functionality Local functions can be dened within a function usshow c provided by those libraries is accessed by importing let. The let keyword must always be followed Note that this is different than the following, which ing into your source le. To import all everything by in. The in must appear in the same column as exported by a library, just use the module name: only works if the string has three characters: the let keyword. Functions dened have access to onlyThree str = all other functions and variables within the same import Text.Read let (a:b:c:[]) = str scope (including those dened by let). In this exEverything means everything: functions, data types in "The characters given are: " ++ ample, mult multiplies its argument n by x, which and constructors, class declarations, and even other show a ++ ", " ++ show b ++ was passed to the original multiples. mult is used modules imported and then exported by the that ", and " ++ show c by map to give the multiples of x up to 10: module. Importing selectively is accomplished by giving a list of names to import. For example, here multiples x = Of we import some functions from Text.Read: let mult n = n * x See the section on case on page 2. in map mult [1..10] import Text.Read (readParen, lex) let functions with no arguments are actually Data types can imported in a number of ways. We Module constants and, once evaluated, will not evaluate can just import the type and no constructors: again. This is useful for capturing common por- A module is a compilation unit which exports funcimport Text.Read (Lexeme) tions of your function and re-using them. Here is a tions, types, classes, instances, and other modules. c 2009 Justin Bailey. 6

-- Anything else is empty string sentenceCase _ = []

jgbailey@codeslower.com

It must be noted that Of course, this prevents our module from pattern- Instance Declarations matching on the values of type Lexeme. We can instance declarations cannot be excluded from import: all instance declarations in a module will be import one or more constructors explicitly: imported when the module is imported. 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 dened in the module:

import Text.Read (Read, ReadS)


In the case of classes, we can import the functions dened for a class using syntax similar to importing constructors for data types:

import Text.Read (Read(readsPrec , readList))

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 not exported in this case. Limiting the names exported is accomplished by adding a parenthesized list of names before the where keyQualied Imports The names exported by a word: module (i.e., functions, types, operators, etc.) can have a prex attached through qualied imports. module MyModule (MyType This is particularly useful for modules which have , MyClass a large number of functions having the same name , myFunc1 as Prelude functions. Data.Set is a good example: ...) where import qualified Data.Set as Set The same syntax as used for importing can be used This form requires any function, type, constructor here to specify which functions, types, construcor other name exported by Data.Set to now be pre- tors, and classes are exported, with a few differxed with the alias (i.e., Set) given. Here is one way ences. If a module imports another module, it can also export that module: to remove all duplicates from a list:

Note that, unlike data types, all class functions are imported unless explicitly excluded. To only import A second form does not create an alias. Instead, the class, we use this syntax: the prex becomes the module name. We can write a simple function to check if a string is all upper import Text.Read (Read()) case: 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 specied via the hiding keyword:

removeDups a = Set.toList (Set.fromList a)

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 denitions and a given imported module are to be exported. Below we export ourselves and Data.Set, but not Data.Char:

import qualified Char allUpper str = all Char.isUpper str

Except for the prex specied, qualied imports support the same syntax as normal imports. The Except for instance declarations, any type, function, name imported can be limited in the same ways as described above. constructor or class can be hidden. c 2009 Justin Bailey. 7

import Data.Char hiding (isControl , isMark)

module AnotherBigModule (module Data.Set , module AnotherBigModule) where import Data.Set import Data.Char jgbailey@codeslower.com

Finally, it should be noted that any deriving clause which can be attached to a data declaration While data introduces new values and type just can also be used when declaring a newtype. creates synonyms, newtype falls somewhere between. The syntax for newtype is quite restricted only one constructor can be dened, and that con- Return structor can only take one argument. Continuing See do on page 4. the above example, we can dene a Phone type as follows:

Newtype

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

type NotSure a = Maybe a This keyword denes a type synonym (i.e., alias). This keyword does not dene a new type, like data but this not: or newtype. It is useful for documenting code but otherwise has no effect on the actual type of a given type NotSure a b = Maybe a As opposed to type, the H and W values on function or value. For example, a Person data type Phone are not just String values. The typechecker Note that fewer type variables can be used, which could be dened as: treats them as entirely new types. That means our useful in certain instances. lowerName function from above would not compile. data Person = Person String String The following produces a type error: where the rst constructor argument represents Where lPhone (Phone hm wk) = their rst name and the second their last. How- Similar to let, where denes local functions and Phone (lower hm) (lower wk) ever, the order and meaning of the two arguments constants. The scope of a where denition is the is not very clear. A type declaration can help: current function. If a function is broken into multiInstead, we must use pattern-matching to get to the ple denitions through pattern-matching, then the values to which we apply lower: type FirstName = String scope of a particular where clause only applies to type LastName = String that denition. For example, the function result lPhone (Phone (H hm) (W wk)) = data Person = Person FirstName LastName below has a different meaning depending on the Phone (H (lower hm)) (W (lower wk)) Because type introduces a synonym, type checking arguments given to the function strlen: The key observation is that this keyword does not is not affected in any way. The function lower, destrlen [] = result introduce a new value; instead it introduces a new ned as: where result = "No string given!" type. This gives us two very useful properties: strlen f = result ++ " characters long!" lower s = map toLower s No runtime cost is associated with the new where result = show (length f) type, since it does not actually produce new which has the type values. In other words, newtypes are absoWhere vs. Let A where clause can only be delutely free! lower :: String -> String ned at the level of a function denition. Usually, The type-checker is able to enforce that common types such as Int or String are used in can be used on values with the type FirstName or that is identical to the scope of let denition. The only difference is when guards are being used. The restricted ways, specied by the programmer. LastName just as easily: newtype Home = H String newtype Work = W String data Phone = Phone Home Work
c 2009 Justin Bailey. 8

jgbailey@codeslower.com

data Bar = Bil (Maybe Int) | Baz scope of the where clause extends over all guards. In contrast, the scope of a let expression is only and recalling the denition of Maybe from page 2 the current function clause and guard, if any. we can match on nested Maybe values when Bil is present:

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:

Declarations, Etc.

Pattern-matching also allows values to be assigned Boolean functions can be used as to variables. For example, this function determines Guards Function Denition if the string given is empty or not. If not, the value guards in function denitions along with pattern matching. An example without pattern matching: Functions are dened by declaring their name, any bound to str is converted to lower case: arguments, and an equals sign: which n toLowerStr [] = [] | n == 0 = "zero!" toLowerStr str = map toLower str square x = x * x | even n = "even!" All functions names must start with a lowercase let- Note that str above is similer to _ in that it will | otherwise = "odd!" ter or _. It is a syntax error otherwise. match anything; the only difference is that the Notice otherwise it always evaluates to true and value matched is also given a name. can be used to specify a default branch. Pattern Matching Multiple clauses of a funcGuards can be used with patterns. Here is a tion can be dened by pattern-matching on the n + k Patterns This (sometimes controversial) function that determines if the rst character in a values of arguments. Here, the the agree function pattern-matching facility makes it easy to match string is upper or lower case: has four separate cases: certain kinds of numeric expressions. The idea

The following section details rules on function declarations, list comprehensions, and other areas of the language.

f (Bil (Just _)) = ... f (Bil Nothing) = ... f Baz = ...

len ls@(l:_) = "List starts with " ++ show l ++ " and is " ++ show (length ls) ++ " items long." len [] = "List is empty!"

Matching & Guard 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 inArgument capture is useful Note that the _ character is a wildcard and Argument Capture teresting: for pattern-matching a value and using it, without matches any value. allEmpty _ = False Pattern matching can extend to nested values. declaring an extra variable. Use an @ symbol in allEmpty [] = True Assuming this data declaration: between the pattern to match and the variable to c 2009 Justin Bailey. 9

-- 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."

is to dene a base case (the n portion) with a constant number for matching, and then to dene other matches (the k portion) as additives to the base case. Here is a rather inefcient way of testing if a number is even or not:

what [] = "empty string!" what (c:_) | isUpper c = "upper case!" | isLower c = "lower case" | otherwise = "not a letter!"

isEven 0 = True isEven 1 = False isEven (n + 2) = isEven n

jgbailey@codeslower.com

alwaysEven n | otherwise = False | n `div` 2 == 0 = True


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:

the type of a particular value, even if the value isnt code when using a Nothing constructor. Nothing has type Maybe a but, if not enough other informapresent. tion is available, Haskell must be told what a is. For example, dene a class for default values: Some example default values: class Def a where defValue :: a -> a -- Return "Just False" defMB = defValue (Nothing :: Maybe Bool) The idea is you give defValue a value of the right -- Return "Just ' '" type and it gives you back a default value for that defMC = defValue (Nothing :: Maybe Char) type. Dening instances for basic types is easy:

A list comprehension consists of four types of elements: generators, guards, local bindings, and targets. instance Def Char where A list comprehension creates a list of target values defValue _ = ' ' based on the generators and guards given. This we can match on green only: Maybe is a littler trickier, because we want to get comprehension generates all squares: a default value for the type, but the constructor isGreenZero (C { green = 0 }) = True squares = [x * x | x <- [1..]] might be Nothing. The following denition would isGreenZero _ = False work, but its not optimal since we get Nothing x <- [1..] generates a list of all Integer values Argument capture is possible with this syntax, al- when Nothing is passed in. and puts them in x, one by one. x * x creates each though it gets clunky. Continuing the above, we element of the list by multiplying x by itself. instance Def a => Def (Maybe a) where now dene a Pixel type and a function to replace Guards allow certain elements to be excluded. defValue (Just x) = Just (defValue x) values with non-zero green components with all The following shows how divisors for a given numdefValue Nothing = Nothing black: ber (excluding itself) can be calculated. Notice how Wed rather get a Just (default value) back instead. d is used in both the guard and target expression. data Pixel = P Color Here is where a lazy pattern saves us we can predivisors n = tend that weve matched Just x and use that to get -- Color value untouched if green is 0 [d | d <- [1..(n `div` 2)] a default value, even if Nothing is given: setGreen (P col@(C { green = 0 })) = P col , n `mod` d == 0] instance Def a => Def (Maybe a) where setGreen _ = P (C 0 0 0) defValue ~(Just x) = Just (defValue x) Local bindings provide new denitions for use in the generated expression or subsequent generators Lazy Patterns This syntax, also known as ir- As long as the value x is not actually evaluated, and guards. Below, z is used to represent the minirefutable patterns, allows pattern matches which al- were safe. None of the base types need to look at x mum of a and b: ways succeed. That means any clause using the (see the _ matches they use), so things will work strange = [(a,z) | a <-[1..3] pattern will succeed, but if it tries to actually use just ne. , b <-[1..3] One wrinkle with the above is that we must the matched value an error may occur. This is gen, c <- [1..3] erally useful when an action should be taken on provide type annotations in the interpreter or the c 2009 Justin Bailey. 10

data Color = C { red , green , blue :: Int }

instance Def Bool where defValue _ = False

List Comprehensions

jgbailey@codeslower.com

, let z = min a b , z < c ]


Comprehensions are not limited to numbers. Any list will do. All upper case letters can be generated:

(reverse (dropWhile isSpace (reverse s))) in trim last ++ ", " ++ trim first > " Haskell " ## " Curry " Curry, Haskell

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:

Of course, full pattern matching, guards, etc. are available in this form. Type signatures are a bit different, though. The operator name must appear Or, to nd all occurrences of a particular break The results are surprising: in parentheses: value br in a list word (indexing from 0): > 2 + 3 * 5 (##) :: String -> String -> String 17 idxs word br = Allowable symbols which can be used to dene op> 2 `plus1` 3 `mult1` 5 [i | (i, c) <- zip [0..] word erators are: 25 , c == br]

ups = [c | c <- [minBound .. maxBound] , isUpper c]

infixl 8 `plus1` plus1 a b = a + b infixl 7 `mult1` mult1 a b = a * b

# $ % & * + . / < = > ? @ \ ^ | - ~ A unique feature of list comprehensions is that pattern matching failures do not cause an error; they However, there are several operators which canare just excluded from the resulting list. not be redened. They are: <-, -> and =. The last, =, cannot be redened by itself, but can be used as part of multi-character operator. The bind funcOperators tion, >>=, is one example. There are very few predened operators in Haskellmost that appear predened are actually Precedence & Associativity The precedence syntax (e.g., =). Instead, operators are simply and associativity, collectively called xity, of any functions that take two arguments and have speoperator can be set through the infix, infixr and cial syntactic support. Any so-called operator can infixl keywords. These can be applied both to be applied as a prex function using parentheses: top-level functions and to local denitions. The syntax is: 3 + 4 == (+) 3 4

Reversing associativity also has interesting effects. Redening 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

Currying

In Haskell, functions do not have to get all of infix | infixr | infixl precedence op To dene a new operator, simply dene it as a northeir arguments at once. For example, consider the mal function, except the operator appears between convertOnly function, which only converts certain the two arguments. Heres one which takes inserts where precedence varies from 0 to 9. Op can actu- elements of string depending on a test: a comma between two strings and ensures no extra ally be any function which takes two arguments (i.e., any binary operation). Whether the operator convertOnly test change str = spaces appear: is left or right associative is specied by infixl or map (\c -> if test c infixr, respectively. Such infix declarations have then change c first ## last = no associativity. else c) str let trim s = dropWhile isSpace c 2009 Justin Bailey. 11

jgbailey@codeslower.com

Using convertOnly, we can write the l33t function That is, convertUpper can take two arguments. The rst is the conversion function which converts indiwhich converts certain letters to numbers: vidual characters and the second is the string to be l33t = convertOnly isL33t toL33t converted. where A curried form of any function which takes isL33t 'o' = True multiple arguments can be created. One way to isL33t 'a' = True think of this is that each arrow in the functions -- etc. signature represents a new function which can be isL33t _ = False created by supplying one more argument. toL33t 'o' = '0' toL33t 'a' = '4' Sections Operators are functions, and they can -- etc. be curried like any other. For example, a curried toL33t c = c version of + can be written as:

changes. Updating is really a copy operation, with new values in the elds that changed. For example, using the Color type dened earlier, we can write a function that sets the green eld to zero easily:

noGreen1 (C r _ b) = C r 0 b
The above is a bit verbose and can be rewriten using record syntax. This kind of update only sets values for the eld(s) specied 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 Notice that l33t has no arguments specied. Also, same value for red and blue as c and its green add10 = (+) 10 the nal argument to convertOnly is not given. component is 0. We can combine this with pattern However, the type signature of l33t tells the whole However, this can be unwieldy and hard to read. matching to set the green and blue elds to equal Sections are curried operators, using parenthe- the red eld: story: ses. Here is add10 using sections: makeGrey c@(C { red = r }) = l33t :: String -> String add10 = (10 +) c { green = r, blue = r } That is, l33t takes a string and produces a string. It is a constant, in the sense that l33t always re- The supplied argument can be on the right or left, Notice we must use argument capture (c@) to get turns a value that is a function which takes a string which indicates what position it should take. This the Color value and pattern matching with record and produces a string. l33t returns a curried is important for operations such as concatenation: syntax (C { red = r}) to get the inner red eld. form of convertOnly, where only two of its three onLeft str = (++ str) Anonymous Functions arguments have been supplied. onRight str = (str ++) This can be taken further. Say we want to write An anonymous function (i.e., a lambda expression a function which only changes upper case letters. Which produces quite different results: or lambda for short), is a function without a name. We know the test to apply, isUpper, but we dont They can be dened at any time like so: > onLeft "foo" "bar" want to specify the conversion. That function can "barfoo" \c -> (c, c) be written as: > onRight "foo" "bar" which denes a function which takes an argument "foobar" convertUpper = convertOnly isUpper and returns a tuple containing that argument in both positions. They are useful for simple funcwhich has the type signature: Updating values and record syntax tions which dont need a name. The following deHaskell is a pure language and, as such, has no termines if a string has mixed case (or is all whitesconvertUpper :: (Char -> Char) mutable state. That is, once a value is set it never pace): -> String -> String c 2009 Justin Bailey. 12

jgbailey@codeslower.com

mixedCase str = all (\c -> isSpace c || isLower c || isUpper c) str

However, for efciency or other reasons you Haskell cannot compile that function because it may only want to allow Int types. You would does not know the type of x. We must limit the type through an annotation: accomplish that with a type signature:

negateAll :: [Int] -> [Int]

canParseInt x = show ((read x) :: Int)


Annotations have the same syntax as type signatures, but may adorn any expression.

Of course, lambdas can be the returned from funcType signatures can appear on top-level functions too. This classic returns a function which will tions and nested let or where denitions. Generthen multiply its argument by the one originally ally this is useful for documentation, although in given: some cases they are needed to prevent polymormultBy n = \m -> n * m phism. A type signature is rst the name of the item which will be typed, followed by a ::, folFor example: lowed by the types. An example of this has already been seen above. > let mult10 = multBy 10 Type signatures do not need to appear directly > mult10 10 above their implementation. They can be specied 100 anywhere in the containing module (yes, even below!). Multiple items with the same signature can Type Signatures also be dened together: Haskell supports full type inference, meaning in pos, neg :: Int -> Int most cases no types have to be written down. Type signatures are still useful for at least two reasons. ... DocumentationEven if the compiler can gure 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.

Unit
() unit type and unit value. The value and type that represents no useful information.

Contributors
My thanks to those who contributed patches and useful suggestions: Dave Bayer, Cale Gibbard, Stephen Hicks, Kurt Hutchinson, Johan Kiviniemi, Adrian Neumann, Barak Pearlmutter, Lanny Ripple, Markus Roberts, Holger Siegel, Leif Warner, and Jeff Zaroyko.

pos x | x < 0 = negate x | otherwise = x neg y | y > 0 = negate y | otherwise = y

Version
This is version 1.8. The source can be found at GitHub2 . The latest released version of the PDF can be downloaded from Hackage3 . Visit CodeSlower.com4 for other projects and writings.

Type Annotations Sometimes Haskell cannot SpecializationTypeclasses allow functions with determine what type is meant. The classic demonoverloading. For example, a function to stration of this is the so-called show . read probnegate any list of numbers has the signature: lem:

negateAll :: Num a => [a] -> [a]


2 http://github.com/m4dc4p/cheatsheet 4 http://blog.codeslower.com/

canParseInt x = show (read x)

3 http://hackage.haskell.org/cgi-bin/hackage-scripts/package/CheatSheet

c 2009 Justin Bailey.

13

jgbailey@codeslower.com

You might also like