Professional Documents
Culture Documents
Haskell CheatSheet
Haskell CheatSheet
strcmp s1 s2 = case (s1, s2) of instance Flavor Bool where data MyType = MyValue1 | MyValue2
([], []) -> True flavor _ = "sweet"
(s1:ss1, s2:ss2)
instance Flavor Char where MyType is the type’s name. MyValue1 and
| toUpper s1 == toUpper s2 ->
flavor _ = "sour" MyValue are values of the type and are called con-
strcmp ss1 ss2
structors. Multiple constructors are separated with
| otherwise -> False Evaluating flavor True gives:
the ‘|’ character. Note that type and constructor
_ -> False > flavor True names must start with a capital letter. It is a syn-
"sweet" tax error otherwise.
Class
While flavor 'x' gives:
A Haskell function is defined to work on a certain > flavor 'x'
type or set of types and cannot be defined more "sour" Constructors with Arguments The type above
than once. Most languages support the idea of is not very interesting except as an enumeration.
“overloading”, where a function can have differ- Defaults Default implementations can be given Constructors that take arguments can be declared,
ent behavior depending on the type of its argu- for functions in a class. These are useful when cer- allowing more information to be stored:
ments. Haskell accomplishes overloading through tain functions can be defined in terms of others in
class and instance declarations. A class defines the class. A default is defined by giving a body
one or more functions that can be applied to any to one of the member functions. The canonical ex- data Point = TwoD Int Int
types which are members (i.e., instances) of that ample is Eq, which defines /= (not equal) in terms | ThreeD Int Int Int
class. A class is analogous to an interface in Java of == :
or C#, and instances to a concrete implementation
class Eq a where Notice that the arguments for each constructor are
of the interface.
(==) :: a -> a -> Bool type names, not constructors. That means this
A class must be declared with one or more
(/=) :: a -> a -> Bool kind of declaration is illegal:
type variables. Technically, Haskell 98 only al-
lows one type variable, but most implementations (/=) a b = not (a == b)
of Haskell support so-called multi-parameter type Recursive definitions can be created. Continuing data Poly = Triangle TwoD TwoD TwoD
classes, which allow more than one type variable. the Eq example, == can be defined in terms of /=:
We can define a class which supplies a flavor (==) a b = not (a /= b)
for a given type: instead, the Point type must be used:
However, if instances do not provide enough con-
class Flavor a where crete implementations of member functions then
flavor :: a -> String any program using those instances will loop. data Poly = Triangle Point Point Point
That is, it takes a Bool value and evaluates to some Multiple do’s When using do with if or case, countBytes3 =
other value based on the condition. From the type another do is required if either branch has multi- do
signatures it is clear that doesFileExist cannot be ple statements. An example with if: putStrLn "Enter a filename."
used directly by if: args <- getLine
countBytes1 f =
case args of
wrong fileName = do
[] -> putStrLn "No args given."
if doesFileExist fileName putStrLn "Enter a filename."
file -> do { f <- readFile file;
then ... args <- getLine
putStrLn ("The file is " ++
else ... if length args == 0
show (length f)
-- no 'do'.
That is, doesFileExist results in an IO Bool ++ " bytes long."); }
then putStrLn "No filename given."
value, while if wants a Bool value. Instead, the else
correct value must be “extracted” by running the -- multiple statements require
Export
IO action: -- a new 'do'. See the section on module on page 11.
right1 fileName = do do
exists <- doesFileExist fileName f <- readFile args If, Then, Else
if exists putStrLn ("The file is " ++
show (length f) Remember, if always “returns” a value. It is an
then return 1
else return 0 ++ " bytes long.") expression, not just a control flow statement. This
function tests if the string given starts with a lower
Notice the use of return. Because do puts us “in- And one with case: case letter and, if so, converts it to upper case:
side” the IO monad, we can’t “get out” except
countBytes2 = -- Use pattern-matching to
through return. Note that we don’t have to use
do -- get first character
if inline here—we can also use let to evaluate
putStrLn "Enter a filename." sentenceCase (s:rest) =
the condition and get a value first:
args <- getLine if isLower s
right2 fileName = do case args of then toUpper s : rest
exists <- doesFileExist fileName [] -> putStrLn "No args given." else s : rest