-- 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.
:type nullnull :: [a] -> Bool
: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
ifexpression 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
elsebranch from an
if, because we're working with statements, not expressions. However, when we're working with expressions, an
ifthat was missing an
elsewouldn'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 evaluationIn 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
Post a Comment