3 Expressions
In this chapter, we describe the syntax and informal semantics of Haskell expressions, including their translations into the Haskell kernel, where appropriate. Except in the case of let expressions, these translations preserve both the static and dynamic semantics. Free variables and constructors used in these translations always refer to entities defined by the Prelude. For example, “concatMap” used in the translation of list comprehensions (Section 3.11) means the concatMap defined by the Prelude, regardless of whether or not the identifier “concatMap” is in scope where the list comprehension is used, and (if it is in scope) what it is bound to.
| (expression type signature) | |||
| (prefix negation) | |||
| (lambda abstraction, | |||
| (let expression) | |||
| (conditional) | |||
| (case expression) | |||
| (do expression) | |||
| (function application) | |||
| (variable) | |||
| (general constructor) | |||
| (parenthesized expression) | |||
| (tuple, | |||
| (list, | |||
| (arithmetic sequence) | |||
| (list comprehension, | |||
| (left section) | |||
| (right section) | |||
| (labeled construction, | |||
| (labeled update, |
Expressions involving infix operators are disambiguated by the operator’s fixity (see Section 4.4.2). Consecutive unparenthesized operators with the same precedence must both be either left or right associative to avoid a syntax error. Given an unparenthesized expression “
An example algorithm for resolving expressions involving infix operators is given in Section 10.6.
Negation is the only prefix operator in Haskell; it has the same precedence as the infix - operator defined in the Prelude (see Section 4.4.2, Figure 1).
The grammar is ambiguous regarding the extent of lambda abstractions, let expressions, and conditionals. The ambiguity is resolved by the meta-rule that each of these constructs extends as far to the right as possible.
Sample parses are shown below.
| This | Parses as |
|---|---|
f x + g y | (f x) + (g y) |
- f x + y | (- (f x)) + y |
let {...} in x + y | let {...} in (x + y) |
z + let {...} in x + y | z + (let {...} in (x + y)) |
f x y :: Int | (f x y) :: Int |
\ x -> a+b :: Int | \x -> ((a+b) :: Int) |
For the sake of clarity, the rest of this section will assume that expressions involving infix operators have been resolved according to the fixities of the operators.
3.1 Errors
Errors during expression evaluation, denoted by
error :: String -> a
undefined :: aA call to error terminates execution of the program and returns an appropriate error indication to the operating system. It should also display the string in some system-dependent manner. When undefined is used, the error message is created by the compiler.
Translations of Haskell expressions use error and undefined to explicitly indicate where execution time errors may occur. The actual program behavior when an error occurs is up to the implementation. The messages passed to the error function in these translations are only suggestions; implementations may choose to display more or less information when an error occurs.
3.2 Variables, Constructors, Operators, and Literals
| (variable) | |||
| (general constructor) | |||
| (variable) | |||
| (qualified variable) | |||
| (constructor) | |||
| (qualified constructor) | |||
| (variable operator) | |||
| (qualified variable operator) | |||
| (constructor operator) | |||
| (qualified constructor operator) | |||
| (operator) | |||
| (qualified operator) | |||
Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).
An operator is either an operator symbol, such as + or $$, or is an ordinary identifier enclosed in grave accents (backquotes), such as `op`. For example, instead of writing the prefix application op x y, one can write the infix application x `op` y. If no fixity declaration is given for op then it defaults to highest precedence and left associativity (see Section 4.4.2).
Dually, an operator symbol can be converted to an ordinary identifier by enclosing it in parentheses. For example, (+) x y is equivalent to x + y, and foldr (*) 1 xs is equivalent to foldr (\x y -> x*y) xs.
Special syntax is used to name some constructors for some of the built-in types, as found in the production for
An integer literal represents the application of the function fromInteger to the appropriate value of type Integer. Similarly, a floating point literal stands for an application of fromRational to a value of type Rational (that is, Ratio Integer).
Translation: The integer literal fromInteger is a method in class Num (see Section 6.4.1).
The floating point literal fromRational is a method in class Fractional and Ratio.% constructs a rational from two integers, as defined in the module Data.Ratio from the standard library. The integers
3.3 Curried Applications and Lambda Abstractions
| (function application) | |||
| (lambda abstraction |
Function application is written (f x) y. Because
Lambda abstractions are written \x:xs->x is syntactically incorrect; it may legally be written as \(x:xs)->x.
The set of patterns must be linear—no variable may appear more than once in the set.
Translation: The following identity holds:
where the
Given this translation combined with the semantics of case expressions and pattern matching described in Section 3.17.3, if the pattern fails to match, then the result is
3.4 Operator Applications
| (prefix negation) | |||
| (qualified operator) |
The form
The special form - operator does not necessarily refer to the definition of - in the Prelude; it may be rebound by the module system. However, unary - will always refer to the negate function defined in the Prelude. There is no link between the local meaning of the - operator and unary negation.
Prefix negation has the same precedence as the infix operator - defined in the Prelude (see Table 1). Because e1-e2 parses as an infix application of the binary operator -, one must write e1(-e2) for the alternative parsing. Similarly, (-) is syntax for \x y -> x-y, as with any infix operator, and does not denote \x -> -x—one must use negate for that.
Translation: The following identities hold:
3.5 Sections
| (left section) | |||
| (right section) |
Sections are written as
Syntactic precedence rules apply to sections as follows. (*a+b) is syntactically invalid, but (+a*b) and (*(a+b)) are valid. Because (+) is left associative, (a+b+) is syntactically correct, but (+a+b) is not; the latter may legally be written as (+(a+b)). As another example, the expression
(let n = 10 in n +)is invalid because, by the let/lambda meta-rule (Section 3), the expression
(let n = 10 in n + x)parses as
(let n = 10 in (n + x))rather than
((let n = 10 in n) + x)Because - is treated specially in the grammar, subtract function defined in the Prelude such that
Translation: The following identities hold:
where
3.6 Conditionals
A conditional expression has the form True, False, and
Translation: The following identity holds:
where True and False are the two nullary constructors from the type Bool, as defined in the Prelude. The type of Bool;
3.7 Lists
Lists are written :, and the empty list is denoted []. Standard operations on lists are given in the Prelude (see Section 6.1.3, and Chapter 9 notably Section 9.1).
Translation: The following identity holds:
where : and [] are constructors for lists, as defined in the Prelude (see Section 6.1.3). The types of [t] (see Section 4.1.2).
The constructor “:” is reserved solely for list construction; like [], it is considered part of the language syntax, and cannot be hidden or redefined. It is a right-associative operator, with precedence level 5 (Section 4.4.2).
3.8 Tuples
Tuples are written (a,b,c) and (,,) a b c denote the same value. Standard operations on tuples are given in the Prelude (see Section 6.1.4 and Chapter 9).
3.9 Unit Expressions and Parenthesized Expressions
The form () has type () (see Section 4.1.2). It is the only member of that type apart from
3.10 Arithmetic Sequences
The arithmetic sequence Enum.
Translation: Arithmetic sequences satisfy these identities:
[ ..] | enumFrom | |
[ ..] | enumFromThen | |
[ .. ] | enumFromTo | |
[ .. ] | enumFromThenTo |
where enumFrom, enumFromThen, enumFromTo, and enumFromThenTo are class methods in the class Enum as defined in the Prelude (see Figure 3).
The semantics of arithmetic sequences therefore depends entirely on the instance declaration for the type t. See Section 6.3.4 for more details of which Prelude types are in Enum and their semantics.
3.11 List Comprehensions
| (list comprehension, | |||
| (generator) | |||
| (local declaration) | |||
| (boolean guard) |
A list comprehension has the form
- generators of the form
, where𝑝 <- 𝑒 is a pattern (see Section 3.17) of type𝑝 and𝑡 is an expression of type𝑒 [ 𝑡 ] - local bindings that provide new definitions for use in the generated expression
or subsequent boolean guards and generators𝑒 - boolean guards, which are arbitrary expressions of type
Bool.
Such a list comprehension returns the list of elements produced by evaluating
[ x | xs <- [ [(1,2),(3,4)], [(5,4),(3,2)] ],
(3,x) <- xs ]yields the list [4,2]. If a qualifier is a boolean guard, it must evaluate to True for the previous pattern match to succeed. As usual, bindings in list comprehensions can shadow those in outer scopes; for example:
Translation: List comprehensions satisfy these identities, which may be used as a translation into the kernel:
where ok is a fresh variable. The function concatMap, and boolean value True, are defined in the Prelude.
As indicated by the translation of list comprehensions, variables bound by let have fully polymorphic types while those defined by <- are lambda bound and are thus monomorphic (see Section 4.5.4).
3.12 Let Expressions
Let expressions have the general form let is often called letrec). The scope of the declarations is the expression ~ makes these patterns irrefutable. For example,
does not cause an execution-time error until x or y is evaluated.
Translation: The dynamic semantics of the expression
| where no variable in | ||
where fix is the least fixpoint operator. Note the use of the irrefutable patterns ~p. This translation does not preserve the static semantics because the use of case precludes a fully polymorphic typing of the bound variables. The static semantics of the bindings in a let expression are described in Section 4.4.3.
3.13 Case Expressions
| (empty alternative) | |||
| (pattern guard) | |||
| (local declaration) | |||
| (boolean guard) |
A case expression has the general form
where each
(Notice that in the syntax rule for |” is a terminal symbol, not the syntactic metasymbol for alternation.) Each alternative
A guard has one of the following forms:
- pattern guards are of the form
, where𝑝 <- 𝑒 is a pattern (see Section 3.17) of type𝑝 and𝑡 is an expression type𝑒 . They succeed if the expression𝑡 matches the pattern𝑒 , and introduce the bindings of the pattern to the environment.𝑝 - local bindings are of the form
. They always succeed, and they introduce the names defined in𝚕𝚎𝚝 𝑑𝑒𝑐𝑙𝑠 to the environment.𝑑𝑒𝑐𝑙𝑠 - boolean guards are arbitrary expressions of type
Bool. They succeed if the expression evaluates toTrue, and they do not introduce new names to the environment. A boolean guard, , is semantically equivalent to the pattern guard𝑔 .𝚃𝚛𝚞𝚎 <- 𝑔
An alternative of the form
is treated as shorthand for:
A case expression must have at least one alternative and each alternative must have at least one body. Each body must have the same type, and the type of the whole expression is that type.
A case expression is evaluated by pattern matching the expression where clause associated with that alternative.
For each guarded expression, the comma-separated guards are tried sequentially from left to right. If all of them succeed, then the corresponding expression is evaluated in the environment extended with the bindings introduced by the guards. That is, the bindings that are introduced by a guard (either by using a let clause or a pattern guard) are in scope in the following guards and the corresponding expression. If any of the guards fail, then this guarded expression fails and the next guarded expression is tried.
If none of the guarded expressions for a given alternative succeed, then matching continues with the next alternative. If no alternative succeeds, then the result is
A note about parsing. The expression
case x of { (a,_) | let b = not a in b :: Bool -> a }is tricky to parse correctly. It has a single unambiguous parse, namely
case x of { (a,_) | (let b = not a in b :: Bool) -> a }However, the phrase Bool -> a is syntactically valid as a type, and parsers with limited lookahead may incorrectly commit to this choice, and hence reject the program. Programmers are advised, therefore, to avoid guards that end with a type signature — indeed that is why a
3.14 Do Expressions
| (do expression) | |||
| (empty statement) |
A do expression provides a more conventional syntax for monadic programming. It allows an expression such as
putStr "x: " >>
getLine >>= \l ->
return (words l)to be written in a more traditional way as:
do putStr "x: "
l <- getLine
return (words l)Translation: Do expressions satisfy these identities, which may be used as a translation into the kernel, after eliminating empty
The ellipsis “...” stands for a compiler-generated error message, passed to fail, preferably giving some indication of the location of the pattern-match failure; the functions >>, >>=, and fail are operations in the class Monad, as defined in the Prelude; and ok is a fresh identifier.
As indicated by the translation of do, variables bound by let have fully polymorphic types while those defined by <- are lambda bound and are thus monomorphic.
3.15 Datatypes with Field Labels
A datatype declaration may optionally define field labels (see Section 4.2.1). These field labels can be used to construct, select from, and update fields in a manner that is independent of the overall structure of the datatype.
Different datatypes cannot share common field labels in the same scope. A field label can be used at most once in a constructor. Within a datatype, however, a field label can be used in more than one constructor provided the field has the same typing in all constructors. To illustrate the last point, consider:
data S = S1 { x :: Int } | S2 { x :: Int } -- OK
data T = T1 { y :: Int } | T2 { y :: Bool } -- BADHere S is legal but T is not, because y is given inconsistent typings in the latter.
3.15.1 Field Selection
Field labels are used as selector functions. When used as a variable, a field label serves as a function that extracts the field from an object. Selectors are top level bindings and so they may be shadowed by local variables but cannot conflict with other top level bindings of the same name. This shadowing only affects selector functions; in record construction (Section 3.15.2) and update (Section 3.15.3), field labels cannot be confused with ordinary variables.
Translation: A field label
where undefined otherwise.
3.15.2 Construction Using Field Labels
| (labeled construction, | |||
A constructor with labeled fields may be used to construct a value in which the components are specified by name rather than by position. Unlike the braces used in declaration lists, these are not subject to layout; the { and } characters must be explicit. (This is also true of field updates and field patterns.) Construction using field labels is subject to the following constraints:
- Only field labels declared with the specified constructor may be mentioned.
- A field label may not be mentioned more than once.
- Fields not mentioned are initialized to
.⊥ - A compile-time error occurs when any strict fields (fields whose declared types are prefixed by
!) are omitted during construction. Strict fields are discused in Section 4.2.1.
The expression F {}, where F is a data constructor, is legal whether or not F was declared with record syntax (provided F has no strict fields — see the fourth bullet above); it denotes F.
Translation: In the binding
where
The auxiliary function
If theth component of a constructor 𝑖 has the field label 𝐶 , and if 𝑓 appears in the binding list 𝑓 = 𝑣 , then 𝑏𝑠 is 𝑝𝑖𝑐𝑘 𝑖 𝐶 𝑏𝑠 𝑑 . Otherwise, 𝑣 is the default value 𝑝𝑖𝑐𝑘 𝑖 𝐶 𝑏𝑠 𝑑 . 𝑑
3.15.3 Updates Using Field Labels
| (labeled update, |
Values belonging to a datatype with field labels may be non-destructively updated. This creates a new value in which the specified field values replace those in the existing value. Updates are restricted in the following ways:
- All labels must be taken from the same datatype.
- At least one constructor must define all of the labels mentioned in the update.
- No label may be mentioned more than once.
- An execution error occurs when the value being updated does not contain all of the specified labels.
Translation: Using the prior definition of
where
Here are some examples using labeled fields:
data T = C1 {f1,f2 :: Int}
| C2 {f1 :: Int,
f3,f4 :: Char}| Expression | Translation |
|---|---|
C1 {f1 = 3} | C1 3 undefined |
C2 {f1 = 1, f4 = 'A', f3 = 'B'} | C2 1 'B' 'A' |
x {f1 = 1} | case x of C1 _ f2 -> C1 1 f2 |
C2 _ f3 f4 -> C2 1 f3 f4 |
The field f1 is common to both constructors in T. This example translates expressions using constructors in field-label notation into equivalent expressions using the same constructors without field labels. A compile-time error will result if no single constructor defines the set of field labels used in an update, such as x {f2 = 1, f3 = 'x'}.
3.16 Expression Type-Signatures
Expression type-signatures have the form
Translation:
3.17 Pattern Matching
Patterns appear in lambda abstractions, function definitions, pattern bindings, list comprehensions, do expressions, and case expressions. However, the first five of these ultimately translate into case expressions, so defining the semantics of pattern matching for case expressions is sufficient.
3.17.1 Patterns
Patterns have this syntax:
| (infix constructor) | |||
| (negative literal) | |||
| (arity | |||
| (as pattern) | |||
| (arity | |||
| (labeled pattern, | |||
| (wildcard) | |||
| (parenthesized pattern) | |||
| (tuple pattern, | |||
| (list pattern, | |||
| (irrefutable pattern) | |||
All patterns must be linear—no variable may appear more than once. For example, this definition is illegal:
f (x,x) = x -- ILLEGAL; x used twice in patternPatterns of the form
case e of { xs@(x:rest) -> if x==0 then rest else xs }is equivalent to:
let { xs = e } in
case xs of { (x:rest) -> if x==0 then rest else xs }Patterns of the form _ are wildcards and are useful when some part of a pattern is not referenced on the right-hand-side. It is as if an identifier not used elsewhere were put in its place. For example,
case e of { [x,_,_] -> if x==0 then True else False }is equivalent to:
case e of { [x,y,z] -> if x==0 then True else False }3.17.2 Informal Semantics of Pattern Matching
Patterns are matched against values. Attempting to match a pattern can have one of three results: it may fail; it may succeed, returning a binding for each variable in the pattern; or it may diverge (i.e. return
- Matching the pattern
against a value𝑣𝑎𝑟 always succeeds and binds𝑣 to𝑣𝑎𝑟 .𝑣 Matching the pattern
against a value∼ 𝑎𝑝𝑎𝑡 always succeeds. The free variables in𝑣 are bound to the appropriate values if matching𝑎𝑝𝑎𝑡 against𝑎𝑝𝑎𝑡 would otherwise succeed, and to𝑣 if matching⊥ against𝑎𝑝𝑎𝑡 fails or diverges. (Binding does not imply evaluation.)𝑣 Operationally, this means that no matching is done on a
pattern until one of the variables in∼ 𝑎𝑝𝑎𝑡 is used. At that point the entire pattern is matched against the value, and if the match fails or diverges, so does the overall computation.𝑎𝑝𝑎𝑡 - Matching the wildcard pattern
_against any value always succeeds, and no binding is done. Matching the pattern
against a value, where𝑐𝑜𝑛 𝑝𝑎𝑡 is a constructor defined by𝑐𝑜𝑛 newtype, depends on the value:- If the value is of the form
, then𝑐𝑜𝑛 𝑣 is matched against𝑝𝑎𝑡 .𝑣 - If the value is
, then⊥ is matched against𝑝𝑎𝑡 .⊥
That is, constructors associated with
newtypeserve only to change the type of a value.- If the value is of the form
Matching the pattern
against a value, where𝑐𝑜𝑛 𝑝𝑎𝑡 1 … 𝑝𝑎𝑡 𝑛 is a constructor defined by𝑐𝑜𝑛 data, depends on the value:- If the value is of the form
, sub-patterns are matched left-to-right against the components of the data value; if all matches succeed, the overall match succeeds; the first to fail or diverge causes the overall match to fail or diverge, respectively.𝑐𝑜𝑛 𝑣 1 … 𝑣 𝑛 - If the value is of the form
, where𝑐𝑜𝑛 ′ 𝑣 1 … 𝑣 𝑚 is a different constructor to𝑐𝑜𝑛 , the match fails.𝑐𝑜𝑛 ′ - If the value is
, the match diverges.⊥
- If the value is of the form
- Matching against a constructor using labeled fields is the same as matching ordinary constructor patterns except that the fields are matched in the order they are named in the field list. All fields listed must be declared by the constructor; fields may not be named more than once. Fields not named by the pattern are ignored (matched against
_). Matching a numeric, character, or string literal pattern
against a value𝑘 succeeds if𝑣 , where𝑣 == 𝑘 ==is overloaded based on the type of the pattern. The match diverges if this test diverges.The interpretation of numeric literals is exactly as described in Section 3.2; that is, the overloaded function
fromIntegerorfromRationalis applied to anIntegerorRationalliteral (resp) to convert it to the appropriate type.- Matching an as-pattern
against a value𝑣𝑎𝑟 @ 𝑎𝑝𝑎𝑡 is the result of matching𝑣 against𝑎𝑝𝑎𝑡 , augmented with the binding of𝑣 to𝑣𝑎𝑟 . If the match of𝑣 against𝑎𝑝𝑎𝑡 fails or diverges, then so does the overall match.𝑣
Aside from the obvious static type constraints (for example, it is a static error to match a character against a boolean), the following static class constraints hold:
- An integer literal pattern can only be matched against a value in the class
Num. - A floating literal pattern can only be matched against a value in the class
Fractional.
It is sometimes helpful to distinguish two kinds of patterns. Matching an irrefutable pattern is non-strict: the pattern matches even if the value to be matched is newtype and
Here are some examples:
If the pattern
['a','b']is matched against , then[ ′ 𝑥 ′ , ⊥ ] 'a'fails to match against'x', and the result is a failed match. But if['a','b']is matched against , then attempting to match[ ⊥ , ′ 𝑥 ′ ] 'a'against causes the match to diverge.⊥ These examples demonstrate refutable vs. irrefutable matching:
(\ ~(x,y) -> 0)⊥ ⇒ 0 (\ (x,y) -> 0)⊥ ⇒ ⊥ (\ ~[x] -> 0) []⇒ 0 (\ ~[x] -> x) []⇒ ⊥ (\ ~[x, ~(a,b)] -> x[ ( 0 , 1 ) , ⊥ ] ⇒ ( 0 , 1 ) (\ ~[x, (a,b)] -> x[ ( 0 , 1 ) , ⊥ ] ⇒ ⊥ (\ (x:xs) -> x:x:xs)⊥ ⇒ ⊥ (\ ~(x:xs) -> x:x:xs)⊥ ⇒ ⊥ : ⊥ : ⊥ Consider the following declarations:
newtype N = N Bool data D = D !BoolThese examples illustrate the difference in pattern matching between types defined by
dataandnewtype:(\ (N True) -> True)⊥ ⇒ ⊥ (\ (D True) -> True)⊥ ⇒ ⊥ (\ ~(D True) -> True)⊥ ⇒ TrueAdditional examples may be found in Section 4.2.3.
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards. See Section 3.13 for the syntax and semantics of guards.
The guard semantics have an influence on the strictness characteristics of a function or case expression. In particular, an otherwise irrefutable pattern may be evaluated because of a guard. For example, in
f :: (Int,Int,Int) -> [Int] -> Int
f ~(x,y,z) [a] | (a == y) = 1both a and y will be evaluated by == in the guard.
3.17.3 Formal Semantics of Pattern Matching
The semantics of all pattern matching constructs other than case expressions are defined by giving identities that relate those constructs to case expressions. The semantics of case expressions themselves are in turn given as a series of identities, in Figure 1 – Figure 2. Any implementation should behave so that these identities hold; it is not expected that it will use them directly, since that would generate rather inefficient code.
In Figure 1 – Figure 2: data) constructors (including tuple constructors); and newtype constructor.
Rule (b) matches a general source-language case expression, regardless of whether it actually includes guards—if no guards are written, then True is substituted for the guards case expression into simpler and simpler forms.
Rule (h) in Listing 3 involves the overloaded operator ==; it is this rule that defines the meaning of pattern matching against overloaded constants.
These identities all preserve the static semantics. Rules (d), (e), (j), and (q) use a lambda rather than a let; this indicates that variables bound by case are monomorphically typed (Section 4.1.4).
- (a)
𝚌𝚊𝚜𝚎 𝑒 𝚘𝚏 { 𝑎𝑙𝑡𝑠 } = ( \ 𝑣 -> 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑎𝑙𝑡𝑠 } ) 𝑒
where is a new variable𝑣 - (b)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 1 𝑚𝑎𝑡𝑐ℎ 1 ; … ; 𝑝 𝑛 𝑚𝑎𝑡𝑐ℎ 𝑛 } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 1 𝑚𝑎𝑡𝑐ℎ 1 ; _ -> … 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 𝑛 𝑚𝑎𝑡𝑐ℎ 𝑛 ; _ -> 𝚎𝚛𝚛𝚘𝚛 "𝙽𝚘 𝚖𝚊𝚝𝚌𝚑" } … }
where each has the form𝑚𝑎𝑡𝑐ℎ 𝑖 | 𝑔𝑠 𝑖 , 1 -> 𝑒 𝑖 , 1 ; … ; 𝑔𝑠 𝑖 , 𝑚 𝑖 -> 𝑒 𝑖 , 𝑚 𝑖 𝚠𝚑𝚎𝚛𝚎 { 𝑑𝑒𝑐𝑙𝑠 } - (c)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 | 𝑔𝑠 1 -> 𝑒 1 ; … | 𝑔𝑠 𝑛 -> 𝑒 𝑛 𝚠𝚑𝚎𝚛𝚎 { 𝑑𝑒𝑐𝑙𝑠 } _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑒 ′ 𝚘𝚏 { 𝑦 -> 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 -> 𝚕𝚎𝚝 { 𝑑𝑒𝑐𝑙𝑠 } 𝚒𝚗 𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑔𝑠 1 -> 𝑒 1 ; _ -> … 𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑔𝑠 𝑛 -> 𝑒 𝑛 ; _ -> 𝑦 } … } _ -> 𝑦 } }
where is a new variable𝑦 - (d)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { ~ 𝑝 -> 𝑒 ; _ -> 𝑒 ′ } = ( \ 𝑥 1 … 𝑥 𝑛 -> 𝑒 ) ( 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 -> 𝑥 1 } ) … ( 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 -> 𝑥 𝑛 } )
where are all the variables in𝑥 1 , … , 𝑥 𝑛 𝑝 - (e)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑥 @ 𝑝 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 -> ( \ 𝑥 -> 𝑒 ) 𝑣 ; _ -> 𝑒 ′ } - (f)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { _ -> 𝑒 ; _ -> 𝑒 ′ } = 𝑒
- (g)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 𝑝 1 … 𝑝 𝑛 -> 𝑒 _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 𝑥 1 … 𝑥 𝑛 -> 𝚌𝚊𝚜𝚎 𝑥 1 𝚘𝚏 { 𝑝 1 -> … 𝚌𝚊𝚜𝚎 𝑥 𝑛 𝚘𝚏 { 𝑝 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } … _ -> 𝑒 ′ } _ -> 𝑒 ′ }
at least one of is not a variable;𝑝 1 , … , 𝑝 𝑛 are new variables𝑥 1 , … , 𝑥 𝑛 - (h)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑘 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚒𝚏 ( 𝑣 == 𝑘 ) 𝚝𝚑𝚎𝚗 𝑒 𝚎𝚕𝚜𝚎 𝑒 ′
where is a numeric, character, or string literal𝑘 - (i)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑥 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑥 -> 𝑒 } - (j)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑥 -> 𝑒 } = ( \ 𝑥 -> 𝑒 ) 𝑣 - (k)
𝚌𝚊𝚜𝚎 𝑁 𝑣 𝚘𝚏 { 𝑁 𝑝 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝑝 -> 𝑒 ; _ -> 𝑒 ′ }
where is a𝑁 newtypeconstructor- (l)
𝚌𝚊𝚜𝚎 ⊥ 𝚘𝚏 { 𝑁 𝑝 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 ⊥ 𝚘𝚏 { 𝑝 -> 𝑒 }
where is a newtype constructor𝑁 - (m)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 { 𝑓 1 = 𝑝 1 , 𝑓 2 = 𝑝 2 , … } -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑒 ′ 𝚘𝚏 { 𝑦 -> 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 { 𝑓 1 = 𝑝 1 } -> 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 { 𝑓 2 = 𝑝 2 , … } -> 𝑒 ; _ -> 𝑦 } ; _ -> 𝑦 } }
where are fields of constructor𝑓 1 , 𝑓 2 , … ;𝐾 is a new variable𝑦 - (n)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 { 𝑓 = 𝑝 } -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 𝑝 1 … 𝑝 𝑛 -> 𝑒 ; _ -> 𝑒 ′ }
where is𝑝 𝑖 if𝑝 labels the𝑓 th component of𝑖 ,𝐾 _otherwise- (o)
𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 { } -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑣 𝚘𝚏 { 𝐾 _ … _ -> 𝑒 ; _ -> 𝑒 ′ } - (p)
𝚌𝚊𝚜𝚎 ( 𝐾 ′ 𝑒 1 … 𝑒 𝑚 ) 𝚘𝚏 { 𝐾 𝑥 1 … 𝑥 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } = 𝑒 ′
where and𝐾 are distinct𝐾 ′ dataconstructors of arity and𝑛 , respectively𝑚 - (q)
𝚌𝚊𝚜𝚎 ( 𝐾 𝑒 1 … 𝑒 𝑛 ) 𝚘𝚏 { 𝐾 𝑥 1 … 𝑥 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } = ( \ 𝑥 1 … 𝑥 𝑛 -> 𝑒 ) 𝑒 1 … 𝑒 𝑛
where is a𝐾 dataconstructor of arity𝑛 - (r)
𝚌𝚊𝚜𝚎 ⊥ 𝚘𝚏 { 𝐾 𝑥 1 … 𝑥 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } = ⊥
where is a𝐾 dataconstructor of arity𝑛
- (s)
𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑔 1 , … , 𝑔 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑔 1 -> … 𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑔 𝑛 -> 𝑒 ; _ -> 𝑒 ′ } … _ -> 𝑒 ′ }
where is a new variable𝑦 - (t)
𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑝 <- 𝑒 0 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚌𝚊𝚜𝚎 𝑒 0 𝚘𝚏 { 𝑝 -> 𝑒 ; _ -> 𝑒 ′ } - (u)
𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝚕𝚎𝚝 𝑑𝑒𝑐𝑙𝑠 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚕𝚎𝚝 𝑑𝑒𝑐𝑙𝑠 𝚒𝚗 𝑒 - (v)
𝚌𝚊𝚜𝚎 ( ) 𝚘𝚏 { ( ) | 𝑒 0 -> 𝑒 ; _ -> 𝑒 ′ } = 𝚒𝚏 𝑒 0 𝚝𝚑𝚎𝚗 𝑒 𝚎𝚕𝚜𝚎 𝑒 ′