Quantcast

Why doesn't this work? (palindrome :: IO)

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Why doesn't this work? (palindrome :: IO)

Alexej Segeda
Hi!

A couple of months ago, I wrote an exam in an introductory Haskell course and failed, all because of an assignment that I was convinced would work, but for some reason, it didn't. The assignment was to write a function that would take a line, then determine whether it's a palindrome or not. My code follows:

palindrome :: IO ()
palindrome = do putStr "Type in a word"
                s <- getLine
                case s of
                   (s == reverse s)    -> putStrLn (s ++ " is a palindrome")
                   otherwise           -> putStrLn (s ++ " is not a palindrome")

The interesting thing is, that if I change the "case ... of" statement to an "if ... then ... else" statement, this magically starts to work. Since I no longer am enrolled (I have to take the course next year), I can't ask a teacher, but my curiosity still bugs me. Why doesn't this work? And why does it work with a "if ... then ...else" statement?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Brandon Allbery
On Wed, Dec 7, 2011 at 23:24, Alexej Segeda <[hidden email]> wrote:
                case s of
                   (s == reverse s)    -> putStrLn (s ++ " is a palindrome")
                   otherwise           -> putStrLn (s ++ " is not a palindrome")

case does pattern matching, not Boolean expressions.  (s == reverse s) is not a useful pattern, and in fact is probably a syntax error because == is not a valid infix constructor.

If you want to do Boolean comparisons in a case, you need to use something like

> case () of
>   () | s == reverse s -> putStrLn "palindrome"
>   _                   -> putStrLn "nope"

(otherwise isn't doing what you think there, either; it's exactly equivalent to the _ (unnamed placeholder) I used, since you aren't then using otherwise as the local binding (shadowing the Prelude one) that it is.)

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

paul r-2
In reply to this post by Alexej Segeda
Alexej> The interesting thing is, that if I change the "case ... of"
Alexej> statement to an "if ... then ... else" statement, this magically
Alexej> starts to work. Since I no longer am enrolled (I have to take
Alexej> the course next year), I can't ask a teacher, but my curiosity
Alexej> still bugs me. Why doesn't this work? And why does it work with
Alexej> a "if ... then ...else" statement?

maybe you mixed up 'if' and 'case' usages. In fact, 'if' can alway be
translated to 'case' by matching on the boolean condition, like below :

case (s == reverse s) of
  True -> "s is a palindrome"
  False -> "s is not a palindrome



--
  Paul

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

amindfv
In reply to this post by Brandon Allbery


On Wed, Dec 7, 2011 at 11:46 PM, Brandon Allbery <[hidden email]> wrote:
On Wed, Dec 7, 2011 at 23:24, Alexej Segeda <[hidden email]> wrote:
                case s of
                   (s == reverse s)    -> putStrLn (s ++ " is a palindrome")
                   otherwise           -> putStrLn (s ++ " is not a palindrome")

case does pattern matching, not Boolean expressions.  (s == reverse s) is not a useful pattern, and in fact is probably a syntax error because == is not a valid infix constructor.

If you want to do Boolean comparisons in a case, you need to use something like

> case () of
>   () | s == reverse s -> putStrLn "palindrome"
>   _                   -> putStrLn "nope"




This is kind of a hack of case, though. I think what the OP was looking for is

palindrome :: IO ()
palindrome = do putStrLn "Type in a word"
                s <- getLine
                isPalindrome s

isPalindrome word
  | (word == reverse word) = putStrLn (word ++ " is a palindrome")
  | otherwise              = putStrLn (word ++ " is not a palindrome")


amindfv / Tom

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Brandon Allbery
On Thu, Dec 8, 2011 at 15:52, Tom Murphy <[hidden email]> wrote:
On Wed, Dec 7, 2011 at 11:46 PM, Brandon Allbery <[hidden email]> wrote:
> case () of
>   () | s == reverse s -> putStrLn "palindrome"
>   _                   -> putStrLn "nope"


This is kind of a hack of case, though. I think what the OP was looking for is
 isPalindrome word
  | (word == reverse word) = putStrLn (word ++ " is a palindrome")
  | otherwise              = putStrLn (word ++ " is not a palindrome")

Erm?  It's as much of a hack of case as yours is, since the above is actually using case.

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Yves Parès
Why do you people hate 'if' statements?

2011/12/9 Brandon Allbery <[hidden email]>
On Thu, Dec 8, 2011 at 15:52, Tom Murphy <[hidden email]> wrote:
On Wed, Dec 7, 2011 at 11:46 PM, Brandon Allbery <[hidden email]> wrote:
> case () of
>   () | s == reverse s -> putStrLn "palindrome"
>   _                   -> putStrLn "nope"


This is kind of a hack of case, though. I think what the OP was looking for is
 isPalindrome word
  | (word == reverse word) = putStrLn (word ++ " is a palindrome")
  | otherwise              = putStrLn (word ++ " is not a palindrome")

Erm?  It's as much of a hack of case as yours is, since the above is actually using case.


--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Brandon Allbery
On Fri, Dec 9, 2011 at 04:16, Yves Parès <[hidden email]> wrote:
Why do you people hate 'if' statements?

It's more that the language spec does; if statements, along with a number of other things, desugar to case which is the fundamental conditional construct.

(And more personally, I find the indentation behavior annoying, in that I need to indent then and else more inside something that uses layout; plus the lack of an else if that is aware of being part of a compound means that it "ladders" even more, so I end up switching to case just to keep from ending up on column 200 or something.)

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Yves Parès
I agree with all that, but in this special case, I think that

case something of
   True -> aaaa
   False -> bbbb

is less nice and obvious than

if something
   then aaaa
   else bbbb

2011/12/9 Brandon Allbery <[hidden email]>
On Fri, Dec 9, 2011 at 04:16, Yves Parès <[hidden email]> wrote:
Why do you people hate 'if' statements?

It's more that the language spec does; if statements, along with a number of other things, desugar to case which is the fundamental conditional construct.

(And more personally, I find the indentation behavior annoying, in that I need to indent then and else more inside something that uses layout; plus the lack of an else if that is aware of being part of a compound means that it "ladders" even more, so I end up switching to case just to keep from ending up on column 200 or something.)

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Brandon Allbery
On Fri, Dec 9, 2011 at 05:16, Yves Parès <[hidden email]> wrote:
I agree with all that, but in this special case, I think that

I should also note that the OP mentioned using if, but was surprised/confused by the behavior of case, which is why that's what we've been focusing on.

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

Yitzchak Gale
In reply to this post by Brandon Allbery
Brandon Allbery wrote:
>>> > case () of
>>> >   () | s == reverse s -> putStrLn "palindrome"
>>> >   _                   -> putStrLn "nope"

Tom Murphy wrote:
>> This is kind of a hack of case, though. I think what the OP was looking
>> for is
>>  isPalindrome word
>>   | (word == reverse word) = putStrLn (word ++ " is a palindrome")
>>   | otherwise              = putStrLn (word ++ " is not a palindrome")

> Erm?  It's as much of a hack of case as yours is, since the above is
> actually using case.

I agree with Tom here. While it's true that the compiler
internally desugars to case, that low-level compiler
transformation doesn't have much to do with the
best way to write clear code.

I find that case often creates code that is more
confusing and bug-prone. Except when what I
really want to express is pattern matching, *and*
there is some specific reason here why I don't
want to use a named function in a let or where
binding. Altogether, it doesn't come up very often
for me.

And even for styles that use case more than I
do, certainly there is room to call the use of
the "case ()" idiom a hack. (Even though I'll
admit that I do use it sometimes.)

Regards,
Yitz

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Why doesn't this work? (palindrome :: IO)

amindfv

To clarify, by hack I meant that it seemed like a workaround specifically to keep "case" in the OP's code, when it seemed like they were looking for the functionality of guards.

amindfv / Tom

On Dec 11, 2011 1:39 PM, "Yitzchak Gale" <[hidden email]> wrote:
Brandon Allbery wrote:
>>> > case () of
>>> >   () | s == reverse s -> putStrLn "palindrome"
>>> >   _                   -> putStrLn "nope"

Tom Murphy wrote:
>> This is kind of a hack of case, though. I think what the OP was looking
>> for is
>>  isPalindrome word
>>   | (word == reverse word) = putStrLn (word ++ " is a palindrome")
>>   | otherwise              = putStrLn (word ++ " is not a palindrome")

> Erm?  It's as much of a hack of case as yours is, since the above is
> actually using case.

I agree with Tom here. While it's true that the compiler
internally desugars to case, that low-level compiler
transformation doesn't have much to do with the
best way to write clear code.

I find that case often creates code that is more
confusing and bug-prone. Except when what I
really want to express is pattern matching, *and*
there is some specific reason here why I don't
want to use a named function in a let or where
binding. Altogether, it doesn't come up very often
for me.

And even for styles that use case more than I
do, certainly there is room to call the use of
the "case ()" idiom a hack. (Even though I'll
admit that I do use it sometimes.)

Regards,
Yitz

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Loading...