Conditional evaluation
-- file: ch02/myDrop.hs myDrop n xs = if n <= 0 || null xs then xs else myDrop (n - 1) (tail xs)The if keyword introduces an expression that has three components.
- An expression of type Bool, immediately following the if. We refer to this as a predicate.
- A then keyword, followed by another expression. This expression will be used as the value of the if expression if the predicate evaluates to True.
- An else keyword, followed by another expression. This expression will be used as the value of the if expression if the predicate evaluates to False.
- The null function indicates whether a list is empty, while the (||) operator performs a logical “or” of its Bool-typed arguments.
ghci>
:type null
null :: [a] -> Boolghci>
:type (||)
(||) :: Bool -> Bool -> Bool
Operators are not special.Notice that we were able to find the type of
(||)
by wrapping it in parentheses. The
(||)
operator isn't “built
into” the language: it's an ordinary
function.The following are equivalent
True || False
(||) True False
if
expression will also have this type. An
expression such as if True then 1 else "foo"
has
different types for its branches, so it is ill typed and will
be rejected by a compiler or interpreter.In an imperative language, it can make sense to omit the
else
branch from an if
,
because we're working with statements,
not expressions. However, when we're working with
expressions, an if
that was missing an
else
wouldn't have a result or type if the
predicate evaluated to False
, so it would
be nonsensical. It is an if *expression* rather than an if *statement*. This is an important distinction and worth stressing. An if expression must evaluate to a value, whereas an if statement can leave off the else clause as a shorthand for the 'do nothing' action. It still would not make sense to leave off the 'else' clause from an if-expression in a dynamically typed language.
Our procedure will involve rewriting expressions over and over, substituting expressions for variables until we reach a final result.
Lazy evaluation
In a language that uses strict evaluation, the arguments to a function are evaluated before the function is applied. Haskell chooses another path: non-strict evaluation.In Haskell, the subexpression 1 + 2 is not reduced to the value 3. Instead, we create a “promise” that when the value of the expression isOdd (1 + 2) is needed, we'll be able to compute it. The record that we use to track an unevaluated expression is referred to as a thunk -- A thunk is a function which takes no arguments. -- a delayed computation -- This is all that happens: we create a thunk, and defer the actual evaluation until it's really needed. If the result of this expression is never subsequently used, we will not compute its value at all.
Non-strict evaluation is often referred to as lazy evaluation
No comments:
Post a Comment