Question on Pattern Matching: Why can I not use the same arguments for a conjuction? - haskell

Context from Programming with haskell Textbook Page 32
This version also has the benefit that, under lazy evaluation as
discussed in chapter 12, if the first argument is False, then the
result False is returned without the need to evaluate the second
argument. In practice, the prelude defines ∧ using equations that have
this same property, but make the choice about which equation applies
using the value of the first argument only:
True ∧ b = b
False ∧ _ = False
That is, if the first argument is True, then the result is the value
of the second argument, and, if the first argument is False, then the
result is False. Note that for technical reasons the same name may not
be used for more than one argument in a single equation. For example,
the following definition for the operator ∧ is based upon the
observation that, if the two arguments are equal, then the result is
the same value, otherwise the result is False, but is invalid because
of the above naming requirement:
Question
I do not understand the explanation for not being able to use the expression
b ∧ b = b
__∧_ _= False

To accept a definition such as
myFunction x x = ...
myFunction _ _ = ...
we need to be able to test two values for equality. That is, given two arbitrary values x and y, we need to be able to compute whether x == y holds.
This can be done in many cases, but (perhaps surprisingly) not all. We surely can do that when x and y are Bools or Ints, but not when they are Integer -> Bool or IO (), for instance, since we can not really test functions on infinitely many points, or IO actions on infinitely many worlds.
Consequently, pattern matching is allowed only when variables are used linearly, i.e. when the appear at most once in patterns. So, myFunction x x = ... is disallowed.
If needed, when == is defined (like on Bools) we can use guards to express the same idea:
myFunction x1 x2 | x1 == x2 = ....
| otherwise = ....
In principle, Haskell could automatically translate non-linear patterns into patterns with guards using ==, possible causing an error if == is not available for the type at hand. However, it was not defined in this way, and requires the guard to be explicitly written, if required.
This automatic translation could be convenient but could also be a source of subtle bugs, if one inadvertently reuses a variable in a pattern without realizing it.

Related

In what sense is one function "less defined" than another?

What I mean is that, from definition:
fix f is the least fixed point of the function f
In other words:
the least defined x such that f x = x.
The least defined value of any nullary type is undefined. There is some ambiguity here still as undefined may mean either "will throw an error" (the better) or "will never terminate" (the worse). As both reasoning and trial show, fix (+1) and fix pred :: Word both never seem to approach termination (even though pred 0 is an error), so the worse one of "never terminate" likely always gets chosen between these two alternatives. (What can escape fix is the boring const 1, but on that later.)
This is not the useful way of applying fix.
The useful way of applying fix is something along the lines of:
fix (\f x -> if x > 7 then f (x - 1) else x)
-- That is, using fix to magically produce a recursive function. (This never ceases to amaze me.) This may be regarded as choosing between 2 functions: \f x -> f (x - 1) and \_ x -> x, one of which does never evaluate its first bound variable. This is a dangerous toy, as we may still obtain a function that is non-terminating for half its domain as easily as by accidentally flipping > to < or - to +.
So, somehow, of these two functions:
f1 = \f x -> f (x - 1)
f2 = \_ x -> x
-- The latter is "least defined ". If we squint hard, we can actually recognise our boring fellow const in it, just flip'd.
Now, this is counter-intuitive. f2 is actually more fault tolerant, so, in a sense, it's defined for more input values than f1. (In particular, this is what lets it escape the otherwise infinite loop of fix). Specifically, f2 is defined for all the same pairs (f, x) of input as f1 plus the (undefined, x). Along the same line, const 1 is the most fault tolerant of all unary functions.
So, how do I understand definedness now?
some justification for the question
There is this answer nearby that kind of offers a different intuition for fix than the one proposed in this question. It also emphasizes that for a full understanding one must pass to an external tutorial on denotational semantics.
I would like to have an answer that either supports, or explains the wrongs of, the intuition proposed here, and also, if domain theory really is behind that cursive ordering put forward in the comments, includes at least some rules of thumb that allow, however limited, but practical application of domain theory. One particular part of the question that I'd like to see light shed upon is whether a fixable function can always be decomposed on a constant function and a reduction function, and what would the definition of these classes of functions be.
My wish is for an actual, practical answer on building useful and safe fix-encoded recursion, backed by solid mathematical reasoning.
In Haskell, functions are pure. They take input and yield output. So the natural question arises: what about functions that don't terminate?
f x = 1 + f x
This function will lock your interpreter in an infinite loop. But mathematically, we have to say it "returns" something, or else it's not a function. We call this special "something went wrong" value the "bottom" value and we denote it with the symbol ⊥.
So, mathematically speaking, the Haskell Int type contains every integer, plus an additional special element: ⊥. We call a type which contains ⊥ a "lifted" type, and pretty much all types you'll use in Haskell are lifted.[1] As it turns out, an infinite loop is not the only way to invoke ⊥. We can also do so by "crashing" the interpreter in other ways. The most common way you'll see is with undefined, a built-in function which halts the program with a generic error.
But there's another problem. Specifically, the halting problem. If ⊥ is supposed to represent infinite loops and other unpredictable issues, there are certain functions we can't write in Haskell. For example, the following pseudocode is nonsensical.
doesItHalt :: a -> Bool
doesItHalt ⊥ = False
doesItHalt _ = True
This would check if the resulting value is ⊥ or not, which would solve the halting problem. Clearly, we can't do this in Haskell. So what functions can we define in Haskell? We can define those which are monotonic with respect to the definedness ordering. We define ⊑ to be this ordering. We say ⊥ is the least-defined value, so ⊥ ⊑ x for all x. ⊑ is a partial ordering, so some elements cannot be compared. While 1 ⊑ 1, it is not true that either 1 ⊑ 2 or 2 ⊑ 1. In pure English, we're saying that 1 is certainly less-than-or-equally-defined-as 1 (clearly; they're the same value), but it doesn't make sense to say 1 is more or less defined than 2. They're just... different values.
In Haskell, we can only define functions which are monotonic with respect to this ordering. So we can only define functions for which, for all values a and b, if a ⊑ b then f a ⊑ f b. Our above doesItHalt fails, since, for instance, ⊥ ⊑ "foo" but f ⊥ = False and f "foo" = True. Like we said before, two fully defined but non-equal values are not comparable. So this function fails to work.
In simple terms, the reason we define the ordering to be this way is because, when we "inspect" a value using pattern matching, that acts as an assertion that it must be at least defined enough for us to see the parts we matched on. If it's not, then we'll always get ⊥, since the program will crash.
It's worth noting, before we discuss fix, that there are "partially defined" values. For example, 1 : ⊥ (in Haskell, we could write this as 1 : undefined) is a list whose first element is defined but for which the tail of the list is undefined. In some sense, this value is "more defined" than a simple ⊥, since we can at least pattern match and extract the first value. So we would say ⊥ ⊑ (1 : ⊥) ⊑ (1 : []). Thus, we end up with a hierarchy of "definedness".
Now, fix says it returns the least-defined fixed point. A fixed point of a function f is a value x such that x = f x. Let's try it out with a few examples and see if we can figure out why it says it that way. Let's define a function
f 0 = 1
f x = x
This function has a lot of fixed points. For any x other than zero, f x = x. By our "least-defined" principle, which one will be returned? ⊥ will, actually, since f ⊥ will return ⊥. If we pass undefined to f, the first pattern match will cause the program to crash, since we're comparing an undefined value against 0. So ⊥ is a fixed-point, and since it's the least possible defined value, it will be returned by fix f. Internally, fix works by applying the function to itself infinitely, so this makes some amount of sense. Applying f (f (f ...)) will keep trying to compare the inner argument against 0 and will never terminate. Now let's try a different function.
g x = 0
Applying this function to itself infinitely gives 0. As it turns out, fix g = 0. Why was 0 returned in this case and not ⊥? As it turns out, ⊥ fails to be a fixed-point of this function. g ⊥ = 0. Since the argument is never inspected and Haskell is a non-strict language, g will return 0, even if you pass undefined or error "Oops!" or some absurd infinitely recursing value as an argument. Thus, the only fixed point of g, even over a lifted type, is 0, since g 0 = 0. Thus, 0 is truly the least-defined fixed point of g.
So, in summary, we define a mathematical framework in order to rigorously describe the notion that certain functions don't terminate. "least-defined" is just a very mathematically precise way of saying that fix won't work on functions which are always completely strict in their argument. If f ⊥ is going to return ⊥ then fix f is also going to return ⊥.
* Most of this answer was paraphrased and summarized from the wiki page on Denotational Semantics. I encourage reading that page for more information; it's written to be very understandable to non-mathematicians and is very informative.
[1] A few primitive types are unlifted. For example, GHC-specific Int# is an integer type that does not contain ⊥ and is used internally in some places.

Could `if-then-else` (always) be replaced by a function call?

This question is out of curiousity about how PLs work, more than anything else. (It actually came to me while looking at SML which differs from Haskell in that the former uses call-by-value - but my question is about Haskell.)
Haskell (as I understand) has "call-by-need" semantics.
Does this imply that if I define a function as follows:
cond True thenExp elseExp = thenExp
cond _ thenExp elseExp = elseExp
that this will always behave exactly like an if-then-else expression?
Or, in another sense, can if-then-else be regarded as syntactic sugar for something that could've been defined as a function?
Edit:
Just to contrast the behaviour of Haskell with Standard ML, define (in SML)
cond p t f = if p then t else f;
and then the factorial function
fun factc n = cond (n=0) 1 (n * factc (n-1));
evaluating factc 1 (say) never finishes, because the recursion in the last argument of cond never terminates.
However, defining
fun fact n = if n=0 then 1 else fact (n-1);
works as we expect because the then branch is only evaluated as needed.
Maybe there are clever ways to defer argument evaluation in SML (don't know as I'm not that familiar with it yet) but the point is that in a call-by-value type language, if-then-else often behaves differently.
My question was whether this (call-by-need vs call-by-value) was the principle reason behind this difference (and the consensus seems to be "yes").
Like the Haskell Wikipedia on if-then-else says:
For processing conditions, the `if-then-else` **syntax was defined in Haskell98**. However it could be simply replaced by the function `if'`
with
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y
So if we use the above if' function, and we need to evaluate it (since Haskell is lazy, we do not necessary need to evaluate an if-then-else expression at all), Haskell will first evaluate the first operand to decide if it is True or False. In case it is True, it will return the first expression, if it is False it will return the second expression. Note that this does not per se means that we (fully) evaluate these expressions. Only when we need the result, we will evaluate the expressions.
But in case the condition is True, there is no reason at all to ever evaluate the second expression, since we ignore it.
In case we share an expression over multiple parts of the expression tree, it is of course possible that another call will (partially) evaluate the other expression.
ghci even has an option to override the if <expr> then <expr> else <expr> syntax: the -XRebindable flag. It will, besides other things also:
Conditionals (e.g. if e1 then e2 else e3) means ifThenElse e1 e2 e3. However case expressions are unaffected.
Yes, a lazy language will evaluate an expression only when it needs to. Therefore it is no problem to convert the then/else parts of the expression into function arguments.
This is unlike strict languages like Idris or OCaml, where arguments for a function call are evaluated before the called function is executed.
Yes, you can regard if/then/else as syntactic sugar. In fact, a programming language doesn't even need Boolean primitives, so you can also consider True and False as syntactic sugar.
The lambda calculus defines Boolean values as a set of functions that take two arguments:
true = λt.λf.t
false = λt.λf.f
Both functions are functions that takes two values, t for true, and f for false. The function true always returns the t value, whereas the function false always returns the f value.
In Haskell, you can define similar functions like this:
true = \t f -> t
false = \t f -> f
You could then write your cond function like:
cond = \b t f -> b t f
Examples:
Prelude> cond true "foo" "bar"
"foo"
Prelude> cond false "foo" "bar"
"bar"
Read more in Travis Whitaker's article Scrap Your Constructors: Church Encoding Algebraic Types.

Can any recursive definition be rewritten using foldr?

Say I have a general recursive definition in haskell like this:
foo a0 a1 ... = base_case
foo b0 b1 ...
| cond1 = recursive_case_1
| cond2 = recursive_case_2
...
Can it always rewritten using foldr? Can it be proved?
If we interpret your question literally, we can write const value foldr to achieve any value, as #DanielWagner pointed out in a comment.
A more interesting question is whether we can instead forbid general recursion from Haskell, and "recurse" only through the eliminators/catamorphisms associated to each user-defined data type, which are the natural generalization of foldr to inductively defined data types. This is, essentially, (higher-order) primitive recursion.
When this restriction is performed, we can only compose terminating functions (the eliminators) together. This means that we can no longer define non terminating functions.
As a first example, we lose the trivial recursion
f x = f x
-- or even
a = a
since, as said, the language becomes total.
More interestingly, the general fixed point operator is lost.
fix :: (a -> a) -> a
fix f = f (fix f)
A more intriguing question is: what about the total functions we can express in Haskell? We do lose all the non-total functions, but do we lose any of the total ones?
Computability theory states that, since the language becomes total (no more non termination), we lose expressiveness even on the total fragment.
The proof is a standard diagonalization argument. Fix any enumeration of programs in the total fragment so that we can speak of "the i-th program".
Then, let eval i x be the result of running the i-th program on the natural x as input (for simplicity, assume this is well typed, and that the result is a natural). Note that, since the language is total, then a result must exist. Moreover, eval can be implemented in the unrestricted Haskell language, since we can write an interpreter of Haskell in Haskell (left as an exercise :-P), and that would work as fine for the fragment. Then, we simply take
f n = succ $ eval n n
The above is a total function (a composition of total functions) which can be expressed in Haskell, but not in the fragment. Indeed, otherwise there would be a program to compute it, say the i-th program. In such case we would have
eval i x = f x
for all x. But then,
eval i i = f i = succ $ eval i i
which is impossible -- contradiction. QED.
In type theory, it is indeed the case that you can elaborate all definitions by dependent pattern-matching into ones only using eliminators (a more strongly-typed version of folds, the generalisation of lists' foldr).
See e.g. Eliminating Dependent Pattern Matching (pdf)

Why should I use case expressions if I can use "equations"?

I'm learning Haskell, from the book "Real World Haskell". In pages 66 and 67, they show the case expressions with this example:
fromMaybe defval wrapped =
case wrapped of
Nothing -> defval
Just value -> value
I remember a similar thing in F#, but (as shown earlier in the book) Haskell can define functions as series of equations; while AFAIK, F Sharp cannot. So I tried to define this in such a way:
fromMaybe2 defval Nothing = defval
fromMaybe2 defval (Just value) = value
I loaded it in GHCi and after a couple of results, I convinced myself it was the same However; this makes me wonder, why should there be case expressions when equations:
are more comprehensible (it's Mathematics; why use case something of, who says that?);
are less verbose (2 vs 4 lines);
require much less structuring and syntatic sugar (-> could be an operator, look what they've done!);
only use variables when needed (in basic cases, such as this wrapped just takes up space).
What's good about case expressions? Do they exist only because similar FP-based languages (such as F#) have them? Am I missing something?
Edit:
I see from #freyrs's answer that the compiler makes these exactly the same. So, equations can always be turned into case expressions (as expected). My next question is the converse; can one go the opposite route of the compiler and use equations with let/where expressions to express any case expression?
This comes from a culture of having small "kernel" expression-oriented languages. Haskell grows from Lisp's roots (i.e. lambda calculus and combinatory logic); it's basically Lisp plus syntax plus explicit data type definitions plus pattern matching minus mutation plus lazy evaluation (lazy evaluation was itself first described in Lisp AFAIK; i.e. in the 70-s).
Lisp-like languages are expression-oriented, i.e. everything is an expression, and a language's semantics is given as a set of reduction rules, turning more complex expressions into simpler ones, and ultimately into "values".
Equations are not expressions. Several equations could be somehow mashed into one expression; you'd have to introduce some syntax for that; case is that syntax.
Rich syntax of Haskell gets translated into smaller "core" language, that has case as one of its basic building blocks. case has to be a basic construct, because pattern-matching in Haskell is made to be such a basic, core feature of the language.
To your new question, yes you can, by introducing auxiliary functions as Luis Casillas shows in his answer, or with the use of pattern guards, so his example becomes:
foo x y | (Meh o p) <- z = baz y p o
| (Gah t q) <- z = quux x t q
where
z = bar x
The two functions compile into exactly the same internal code in Haskell ( called Core ) which you can dump out by passing the flags -ddump-simpl -dsuppress-all to ghc.
It may look a bit intimidating with the variable names, but it's effectively just a explicitly typed version of the code you wrote above. The only difference is the variables names.
fromMaybe2
fromMaybe2 =
\ # t_aBC defval_aB6 ds_dCK ->
case ds_dCK of _ {
Nothing -> (defval_aB6) defval_aB6;
Just value_aB8 -> (value_aB8) value_aB8
}
fromMaybe
fromMaybe =
\ # t_aBJ defval_aB3 wrapped_aB4 ->
case wrapped_aB4 of _ {
Nothing -> (defval_aB3) defval_aB3;
Just value_aB5 -> (value_aB5) value_aB5
}
The paper "A History of Haskell: Being Lazy with Class" (PDF) provides some useful perspective on this question. Section 4.4 ("Declaration style vs. expression style," p.13) is about this topic. The money quote:
[W]e engaged in furious debate about which style was “better.” An underlying assumption was that if possible there should be “just one way to do something,” so that, for example, having both let and where would be redundant and confusing. [...] In the end, we abandoned the underlying assumption, and provided full syntactic support for both styles.
Basically they couldn't agree on one so they threw both in. (Note that quote is explicitly about let and where, but they treat both that choice and the case vs. equations choice as two manifestations of the same basic choice—what they call "declaration style" vs. "expression style.")
In modern practice, the declaration style (your "series of equations") has become the more common one. case is often seen in this situation, where you need to match on a value that is computed from one of the arguments:
foo x y = case bar x of
Meh o p -> baz y p o
Gah t q -> quux x t q
You can always rewrite this to use an auxiliary function:
foo x y = go (bar x)
where go (Meh o p) = baz y p o
go (Gah t q) = quux x t q
This has the very minor disadvantage that you need to name your auxiliary function—but go is normally a perfectly fine name in this situation.
Case expression can be used anywhere an expression is expected, while equations can't. Example:
1 + (case even 9 of True -> 2; _ -> 3)
You can even nest case expression, and I've seen code that does that. However I tend to stay away from case expressions, and try to solve the problem with equations, even if I have to introduce a local function using where/let.
Every definition using equations is equivalent to one using case. For instance
negate True = False
negate False = True
stands for
negate x = case x of
True -> False
False -> True
That is to say, these are two ways of expressing the same thing, and the former is translated to the latter by GHC.
From the Haskell code that I've read, it seems canonical to use the first style wherever possible.
See section 4.4.3.1 of the Haskell '98 report.
The answer to your added question is yes, but it's pretty ugly.
case exp of
pat1 -> e1
pat2 -> e2
etc.
can, I believe, be emulated by
let
f pat1 = e1
f pat2 = e2
etc.
in f exp
as long as f is not free in exp, e1, e2, etc. But you shouldn't do that because it's horrible.

What would pattern matching look like in a strict Haskell?

As a research experiment, I've recently worked on implementing strict-by-default Haskell modules. Instead of being lazy-by-default and having ! as an escape hatch, we're strict-by-default and have ~ as an escape hatch. This behavior is enabled using a {-# LANGUAGE Strict #-} pragma.
While working on making patterns strict I came up on an interesting question: should patterns be strict in the "top-level" only or in all bind variables. For example, if we have
f x = case x of
y -> ...
we will force y even though Haskell would not do so. The more tricky case is
f x = case x of
Just y -> ...
Should we interpret that as
f x = case x of
Just y -> ... -- already strict in 'x' but not in `y`
or
f x = case x of
Just !y -> ... -- now also strict in 'y'
(Note that we're using the normal, lazy Haskell Just here.)
One design constraint that might of value is this: I want the pragma to be modular. For example, even with Strict turned on we don't evaluate arguments to functions defined in other modules. That would make it non-modular.
Is there any prior art here?
As far as I understand things, refutable patterns are always strict at least on the outer level. Which is another way to say that the scrutinized expression must have been evaluated to WHNF, otherwise you couldn't see if it is a 'Just' or a 'Nothing'.
Hence your
!(Just y) -> ...
notation appears useless.
OTOH, since in a strict language, the argument to Just must already have been evaluated, the notation
Just !y ->
doesn't make sense either.

Resources