Why does Haskell have the if-then-else syntax?

I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story? thanks, -m

As opposed to what? Mike Mike Gunter wrote:
I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story?
thanks, -m _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 7/27/06, mvanier
As opposed to what?
For example case-of, guards (in combination with let or where), or just a function: if :: Bool -> a -> a -> a if True t _ = t if False _ e = e -- example usage myAbs x = if (x < 0) (negate x) x /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Jul 26, 2006, at 6:44 PM, Sebastian Sylvan wrote:
For example ...
if :: Bool -> a -> a -> a if True t _ = t if False _ e = e
-- example usage myAbs x = if (x < 0) (negate x) x
I suppose there might also be a case for flipping the arguments about like this: if :: a -> a -> Bool -> a if t _ True = t if _ e False = e This way it would follow foldr more closely, in recognition that the conditional is essentially the fold/cata/eliminator/... for booleans. But argument order is a pretty trivial thing, and I think the committee made the right choice with if-then-else as a language construct. -- Fritz

On Wed, 26 Jul 2006, Fritz Ruehr wrote:
On Jul 26, 2006, at 6:44 PM, Sebastian Sylvan wrote:
For example ...
if :: Bool -> a -> a -> a if True t _ = t if False _ e = e
-- example usage myAbs x = if (x < 0) (negate x) x
I suppose there might also be a case for flipping the arguments about like this:
if :: a -> a -> Bool -> a if t _ True = t if _ e False = e
This way it would follow foldr more closely, in recognition that the conditional is essentially the fold/cata/eliminator/... for booleans.
I found the argument order of the first if (Bool -> a -> a -> a) already useful for a 'case' with computed conditions: select = foldr (uncurry if_) http://www.haskell.org/hawiki/Case

Mike Gunter wrote:
I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story?
thanks, -m
Thanks for asking about this -- it probably should be in the paper. Dan Doel's answer is closest to the truth: I imagine the answer is that having the syntax for it looks nicer/is clearer. "if a b c" could be more cryptic than "if a then b else c" for some values of a, b and c. except that there was also the simple desire to conform to convention here (I don't recall fewer parentheses being a reason for the choice). In considering the alternative, I remember the function "cond" being proposed instead of "if", in deference to Scheme and to avoid confusion with people's expectations regarding "if". A related issue is why Haskell does not have a "single arm" conditional -- i.e. an "if-then" form, which would evaluate to bottom (i.e. error) if the predicate were false. This was actually discussed, but rejected as a bad idea for a purely functional language. -Paul

I often find myself at odds with this choice. The reason is that I use
Haskell as a host for embedded languages, and these often come with
their own control flows. So I find myself wanting to write my own
definition of the if-then-else construct that works on terms of some
other type, e.g. tests on values of type Exp Bool instead of Bool, and
at the same time make sure that the user doesn't use the built-in
if-then-else. Sure, I can (and do) call my own version if_, ifElse or
something else along those lines, but it's sure to be a constant
source of programmer errors, writing if-then-else instead of if_ by
habit.
A thought that has crossed my mind on several occasions is, why not
make the syntactic if-then-else construct rebindable, like the do
notation? I think I know the answer already -- the do notation is
syntactic sugar for >>= and company so it's easy to translate it into
non-prelude-qualified versions of functions with those names. This is
not the case for if-then-else. But it could be, the prelude could
define a function if_ (or whatever) that the if-then-else construct is
made to be sugar for, and thus also amenable to rebinding by not
prelude-qualifying.
/Niklas
On 7/27/06, Paul Hudak
Mike Gunter wrote:
I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story?
thanks, -m
Thanks for asking about this -- it probably should be in the paper. Dan Doel's answer is closest to the truth:
I imagine the answer is that having the syntax for it looks nicer/is clearer. "if a b c" could be more cryptic than "if a then b else c" for some values of a, b and c.
except that there was also the simple desire to conform to convention here (I don't recall fewer parentheses being a reason for the choice). In considering the alternative, I remember the function "cond" being proposed instead of "if", in deference to Scheme and to avoid confusion with people's expectations regarding "if".
A related issue is why Haskell does not have a "single arm" conditional -- i.e. an "if-then" form, which would evaluate to bottom (i.e. error) if the predicate were false. This was actually discussed, but rejected as a bad idea for a purely functional language.
-Paul
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I often find myself at odds with this choice. The reason is that I use Haskell as a host for embedded languages, and these often come with their own control flows. So I find myself wanting to write my own definition of the if-then-else construct that works on terms of some other type, e.g. tests on values of type Exp Bool instead of Bool, and at the same time make sure that the user doesn't use the built-in if-then-else. Sure, I can (and do) call my own version if_, ifElse or something else along those lines, but it's sure to be a constant source of programmer errors, writing if-then-else instead of if_ by habit.
A thought that has crossed my mind on several occasions is, why not make the syntactic if-then-else construct rebindable, like the do notation? I think I know the answer already -- the do notation is syntactic sugar for >>= and company so it's easy to translate it into non-prelude-qualified versions of functions with those names. This is not the case for if-then-else. But it could be, the prelude could define a function if_ (or whatever) that the if-then-else construct is made to be sugar for, and thus also amenable to rebinding by not prelude-qualifying.
Wouldn't this cause a conflict with specialized knowledge the compiler has about if-then-else, e.g. for optimizations? Tom -- Tom Schrijvers Department of Computer Science K.U. Leuven Celestijnenlaan 200A B-3001 Heverlee Belgium tel: +32 16 327544 e-mail: tom.schrijvers@cs.kuleuven.be

Niklas Broberg wrote:
I often find myself at odds with this choice. The reason is that I use Haskell as a host for embedded languages, and these often come with their own control flows. So I find myself wanting to write my own definition of the if-then-else construct that works on terms of some other type, e.g. tests on values of type Exp Bool instead of Bool, and at the same time make sure that the user doesn't use the built-in if-then-else. Sure, I can (and do) call my own version if_, ifElse or something else along those lines, but it's sure to be a constant source of programmer errors, writing if-then-else instead of if_ by habit.
A thought that has crossed my mind on several occasions is, why not make the syntactic if-then-else construct rebindable, like the do notation? I think I know the answer already -- the do notation is syntactic sugar for >>= and company so it's easy to translate it into non-prelude-qualified versions of functions with those names. This is not the case for if-then-else. But it could be, the prelude could define a function if_ (or whatever) that the if-then-else construct is made to be sugar for, and thus also amenable to rebinding by not prelude-qualifying.
/Niklas
You may not realize that if-then-else is just syntactic sugar like "do". Read the Haskell 98 Report http://www.haskell.org/onlinereport/exps.html#conditionals
Translation: The following identity holds: if e1 then e2 else e3 = case e1 of { True -> e2 ; False -> e3 } where True and False are the two nullary constructors from the type Bool, as defined in the Prelude. The type of e1 must be Bool; e2 and e3 must have the same type, which is also the type of the entire conditional expression.
So you could easily create a patched compiler that allows for rebindable syntax. The fundamental syntax of "do" and "if/then/else" and patterns or guards in function definitions is always a case statement. -- Chris

GHC does indeed include the notion of "rebindable syntax". It would be
straightforward to extend it to include if-then-else. In effect, that
would mean that
if e1 then e2 else e3
would behave exactly like
cond e1 e2 e3
including from the point of view of typing. (You could choose a
different name than 'cond'.) Then by importing a 'cond' with (say) type
cond :: MyBool -> b -> b
you could use a different kind of Boolean. You could even overload the
bool:
cond :: Boolean a => a -> b -> b
This could be done with a few hours work. But not a few minutes. Want
to put a feature request in Trac?
Simon
| -----Original Message-----
| From: haskell-cafe-bounces@haskell.org
[mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Niklas
| Broberg
| Sent: 27 July 2006 09:01
| To: Haskell-cafe
| Subject: Re: [Haskell-cafe] Why does Haskell have the if-then-else
syntax?
|
| I often find myself at odds with this choice. The reason is that I use
| Haskell as a host for embedded languages, and these often come with
| their own control flows. So I find myself wanting to write my own
| definition of the if-then-else construct that works on terms of some
| other type, e.g. tests on values of type Exp Bool instead of Bool, and
| at the same time make sure that the user doesn't use the built-in
| if-then-else. Sure, I can (and do) call my own version if_, ifElse or
| something else along those lines, but it's sure to be a constant
| source of programmer errors, writing if-then-else instead of if_ by
| habit.
|
| A thought that has crossed my mind on several occasions is, why not
| make the syntactic if-then-else construct rebindable, like the do
| notation? I think I know the answer already -- the do notation is
| syntactic sugar for >>= and company so it's easy to translate it into
| non-prelude-qualified versions of functions with those names. This is
| not the case for if-then-else. But it could be, the prelude could
| define a function if_ (or whatever) that the if-then-else construct is
| made to be sugar for, and thus also amenable to rebinding by not
| prelude-qualifying.
|
| /Niklas
|
| On 7/27/06, Paul Hudak

On 2006-07-27 at 01:33EDT Paul Hudak wrote:
Thanks for asking about this -- it probably should be in the paper. Dan Doel's answer is closest to the truth:
I imagine the answer is that having the syntax for it looks nicer/is clearer. "if a b c" could be more cryptic than "if a then b else c" for some values of a, b and c.
except that there was also the simple desire to conform to convention here (I don't recall fewer parentheses being a reason for the choice).
In a sense, it explicitly wasn't: I suggested "if _ then _ else _ fi" -- something I was long used to from Algol68 -- but it was rejected on the ground that there wasn't a dangling else problem in Haskell. I probably muttered something about wanting things to be self-bracketing (I've certainly grumbled inwardly since about having to write "(if _ then _ else _)¹" in some Haskell contexts), but since I'm quite slow witted, I expect that the discussion had moved on by then.
In considering the alternative, I remember the function "cond" being proposed instead of "if", in deference to Scheme and to avoid confusion with people's expectations regarding "if".
Did we talk about Dijkstra's "fat bar", or was that a discussion I had elsewhere? Jón [1] which I find ugly, and besides, making all like constructs self-bracketing would have allowed a saner (to my mind) layout rule. -- Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk

On Thu, Jul 27, 2006 at 10:22:31AM +0100, Jon Fairbairn wrote:
On 2006-07-27 at 01:33EDT Paul Hudak wrote:
Thanks for asking about this -- it probably should be in the paper. Dan Doel's answer is closest to the truth:
I imagine the answer is that having the syntax for it looks nicer/is clearer. "if a b c" could be more cryptic than "if a then b else c" for some values of a, b and c.
except that there was also the simple desire to conform to convention here (I don't recall fewer parentheses being a reason for the choice).
In a sense, it explicitly wasn't: I suggested "if _ then _ else _ fi" -- something I was long used to from Algol68 -- but it was rejected on the ground that there wasn't a dangling else problem in Haskell.
But because if-then-else is an expression, there is another problem. Consider: (if True then 0 else 1) + 2 --> 2 if True then 0 else 1 + 2 --> 0 let cond a b c = if a then b else c cond True 0 1 + 2 --> 2 -- different from if-then-else withouth parentheses It's quite easy to fall in this trap. I think it happened to me at least twice. It goes like this: first I have an expression that doesn't involve if-then-else, eg. a + b Then I realize that "a" has to be changed in some situations, so I replace it with a conditional expression: if c then a else a' + b or if c then f a else g a + b But now " + b" gets under the "else" branch. If I used a "cond" function, or if if-then-else had a different priority, it would be easier to avoid such a mistake. There is no problem with the first version: cond c a a' + b For an experienced Haskell programmer it's obvious that function application has a higher precendence than addition. In the second version, it would be clear that parentheses have to be added: cond c (f a) (g a) + b Could the "cond" function encourage other kinds of bugs? I think it's less likely, because it's a normal function. Also, after a few years of Haskell programming, I am still not sure how to indent if-then-else. Perhaps in Haskell' we could have some lightweight case-of version with no pattern matching, guards only ("cond" could be a good name). I think it was even discussed before. The usual case-of looks like this: case x of Left err | isEOFError e -> ... Left err -> ... Right result -> ... "cond" would involve no pattern matching, or only as pattern guards. cond x == 0 -> ... x == 1 -> ... otherwise -> ... currently it can be written as case () of _ | x == 0 -> ... _ | x == 1 -> ... _ | otherwise -> ... which is a bit ugly. Best regards Tomasz

On 2006-07-27 at 13:01+0200 Tomasz Zielonka wrote:
But because if-then-else is an expression, there is another problem.
That was exactly my point when I made the muttering about self-bracketing (if ... fi, like everything else, is an expression in Algol68) all those years ago. I really regret not having been more forceful!
Also, after a few years of Haskell programming, I am still not sure how to indent if-then-else.
what I was alluding to in my footnote... Jón -- Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk

Jon Fairbairn wrote:
On 2006-07-27 at 13:01+0200 Tomasz Zielonka wrote:
Also, after a few years of Haskell programming, I am still not sure how to indent if-then-else.
what I was alluding to in my footnote...
I think there's really only one way when it needs to occupy more than one line: if c then t else f Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

David House wrote:
On 27/07/06, Brian Hulley
wrote: I think there's really only one way when it needs to occupy more than one line:
if c then t else f
Confusingly,
if c then t else f
Also works, although no-one really knows why.
Only if the "if" does not start a new layout line. Anyway, how about changing the syntax to: "if" exp "{" "then" exp ";" "else" exp "}" Then the layout rule + the offside rule would still allow (iiuc) if x < 0 then 5 else 6 but would force the "then" to be further indented than the "if" (and the "else" to be indented at least as much as the "then" (indenting it more is where the offside rule is needed to make things work)) In addition, if we followed Jon's suggestion to make constructs self-bracketing, we could allow an optional keyword such as "/if" to terminate the construct early thus: a = if x < 0 then 5 else 6 /if + 78 I'd also change the lambda syntax to: \{x 2 -> x+5; x y -> x*y} which again would, by the layout rule, still allow current lambda syntax as a special case. The optional terminator could be "/\" and if all constructs were now aexp's (as suggested by the desire to make them self-bracketing) instead of exp10's we could then write: f \x y -> y x /\ 6 instead of having to write f (\x y -> y x) 6 I'd be in favour of /if /case /let /\ etc instead of fi esac tel because it looks more systematic and follows the usual XML conventions for end tags. I'd suggest that floating point division should just be written `divide` - it's just a very specialised arithmetic op so why waste a nice symbol on it? (ditto ^ ^^ **) (I'd have thought integer division is used more often and no-one seems to mind writing `div`.) Anyway having said all this, I can't help feeling that explicit brackets, as required at the moment, help to clarify the structure of the code, and that removing the need for them may negatively impact on readability. Regards, Brian. -- Logic empowers us and Love gives us purpose. Yet still phantoms restless for eras long past, congealed in the present in unthought forms, strive mightily unseen to destroy us. http://www.metamilk.com

On 27/07/06, Brian Hulley
I'd be in favour of /if /case /let /\ etc instead of fi esac tel because it looks more systematic and follows the usual XML conventions for end tags. I'd suggest that floating point division should just be written `divide` - it's just a very specialised arithmetic op so why waste a nice symbol on it? (ditto ^ ^^ **) (I'd have thought integer division is used more often and no-one seems to mind writing `div`.)
Why I'd oppose this: 1. Decreases readability/clarity (brackets group things so much clearer) 2. No obvious benefits over brackets (just as many keystrokes, if not more) 3. Not at all backwards-compatible. I'd support your ideas to change the if syntax, if they weren't backwards-incompatible. I think something as basic as if statements can't really be changed now. It will always be a blot on the otherwise lovely Haskell syntax. -- -David House, dmhouse@gmail.com

Thanks for the answer. (And doubly thanks for giving the answer I
hoped for!)
I propose that ifThenElse and thenElseIf be added to the Prelude for
Haskell'. While these names are a bit long, I think we want both
functions and these names make the behaviors clear (to me, at least).
Comments?
-m
Paul Hudak
Mike Gunter wrote:
I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story?
thanks, -m
Thanks for asking about this -- it probably should be in the paper. Dan Doel's answer is closest to the truth:
I imagine the answer is that having the syntax for it looks nicer/is clearer. "if a b c" could be more cryptic than "if a then b else c" for some values of a, b and c.
except that there was also the simple desire to conform to convention here (I don't recall fewer parentheses being a reason for the choice). In considering the alternative, I remember the function "cond" being proposed instead of "if", in deference to Scheme and to avoid confusion with people's expectations regarding "if".
A related issue is why Haskell does not have a "single arm" conditional -- i.e. an "if-then" form, which would evaluate to bottom (i.e. error) if the predicate were false. This was actually discussed, but rejected as a bad idea for a purely functional language.
-Paul

Mike Gunter wrote:
I had hoped the "History of Haskell" paper would answer a question I've pondered for some time: why does Haskell have the if-then-else syntax? The paper doesn't address this. What's the story?
For what it's worth, I have been asking myself the same question several times. If/then/else syntax could be replaced by a regular (lazy) function without any noticeable loss. Almost every time I use if/then/else I end up changing it to a case expression on teh underlying data (which is almost never Bool); the only exception being simple one liners, and for those a function would be even more concise. IMHO, the next standardized version of Haskell, however named, should abandon the special if/then/else syntax so we'll have at least /one/ item where the language becomes smaller and simpler. Remember: Perfection is reached not when there is nothing more to add, but rather when there is nothing more to take away. On another note, I remember reading a paper proposing to generalize if/then/else to arbitrary (so-called) dist-fix operators, using something like partial backquoting, as in `if condition `then` true_branch `else` false_branch fi` Can't remember the exact title of the paper, nor the details, but it was something to do with adding macros to Haskell. Cheers, Ben

G'day all.
Quoting Benjamin Franksen
For what it's worth, I have been asking myself the same question several times. If/then/else syntax could be replaced by a regular (lazy) function without any noticeable loss.
I believe that if-then-else cannot be replaced by a regular function for the same reason that regular function application and ($) are not identical. The loss may not be noticeable, but it's still a loss. It could be replaced by a case-switch-on-Bool, though.
IMHO, the next standardized version of Haskell, however named, should abandon the special if/then/else syntax so we'll have at least /one/ item where the language becomes smaller and simpler.
The de facto Haskell philosophy, if you read the history paper, is to have a small core language with a lot of syntactic sugar. The syntactic sugar is specified by translation to the core language. The small core ensures that Haskell remains simple. If you discount changes in the type system, the Haskell core language is as simple now as it was in 1989.
Remember: Perfection is reached not when there is nothing more to add, but rather when there is nothing more to take away.
Perfection is asymptotically approached when arbitrary restrictions are removed and special cases are dumped in favour of general, theoretically sound, principles. Perfection will never be reached in a practical programming language, but it may be asymptotically approached. Cheers, Andrew Bromage
participants (18)
-
ajb@spamcop.net
-
Andreas Rossberg
-
Benjamin Franksen
-
Brian Hulley
-
Chris Kuklewicz
-
David House
-
Fritz Ruehr
-
Henning Thielemann
-
Jon Fairbairn
-
Mike Gunter
-
mvanier
-
Niklas Broberg
-
Paul Hudak
-
Sebastian Sylvan
-
Simon Peyton-Jones
-
Stefan Monnier
-
Tom Schrijvers
-
Tomasz Zielonka