-1

I am attempting to run a simple palindrome program in Haskell but I want to request input from the user to be used in the program.

code:

palindrome :: String -> Bool
palindrome x = x == reverse x
main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter word to test for Palindrome"
  palindrome <- getLine
  putStrLn "Thanks"

The code works but it just displays "thanks". If I exclude the last line of the block I get the "last line of do block must be expression" and if I include the actual palindrome code above the do block I get errors saying I need a "let" statement but incorporating one causes more errors. I am brand new to Haskell (and functional programming in general. I do java, c++, and web langs) I think the explanation here will be simple but after reading input output documentation on haskell I still can't figure out the proper way to accomplish this.

I'm doing it this way because my assignment stipulates that I must show the class info when the program is run. The palindrome part works fine without the do block. I'm just attempting to automatically output my text before testing a palindrome. Also how can I set up a haskell script to just run when loaded? I don't want the user to have to type "main" I want it to just run.

edit:

palindrome :: String -> Bool
palindrome x = x == reverse x
main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter Word"
  x <- getLine
  palindrome x
  putStrLn "thanks"

This also doesn't work. How do I get the users input to use in the palindrome???

If the code:

palindrome :: String -> Bool
palindrome x = x == reverse x

works when "palindrome "etc"" is entered in GHCi then why doesn't my second code version do the same thing???

edit 2: Don't forget to enclose print statements in parentheses or Haskell will think it separate input is a separate argument. Dumb mistake but easy to make.

Bren Bailey
  • 11
  • 1
  • 1
  • 8
  • 1
    Hint: `palindrome <- getLine` binds the result of `getline` to a local variable named `palindrome`, unrelated to the top level unction named `palindrome`. – n. m. could be an AI Dec 08 '17 at 21:36
  • Ok then why doesn't this work (sorry if this isn't formatted right I can never format my damn code right in responses since it doesn't have the {} formatting tool and indenting never works. code: inline `palindrome :: String -> Bool palindrome x = x == reverse x main = do putStrLn "Brendon Bailey CSCI 4200-DB" putStrLn "Enter Word" x <- getLine palindrome x putStrLn "thanks"` – Bren Bailey Dec 08 '17 at 21:51
  • "Doesn't work" is not a problem description. What do you want `palindrome x` to do? Right now you're getting an error because `palindrome x` is just a boolean, and it doesn't make sense to put `False` or `True` in the middle of your program. – melpomene Dec 08 '17 at 21:58
  • I just want to output the boolean result. – Bren Bailey Dec 08 '17 at 22:01
  • 2
    So ... `print (palindrome x)`? – melpomene Dec 08 '17 at 22:03
  • Oh. wow. I have been trying many different versions of that line but I kept getting the "too many arguements etc" errors. I wasn't putting parentheses so it thought I wanted to use multiple separate arguments. Thanks for pointing that out. – Bren Bailey Dec 08 '17 at 22:06
  • "Also how can I set up a haskell script to just run when loaded? (...)" Have you heard of compilation? Do you know about GHC? – AJF Dec 08 '17 at 22:11
  • Yes I have. I want the do block to activate without requiring the user to enter "main". – Bren Bailey Dec 08 '17 at 22:17
  • @BrenBailey... that's exactly what compilation does. – AJF Dec 08 '17 at 22:19
  • And to justify my previous confusion with the print output. If you just have the palindrome code outside of the do block and the user enters "palindrome "etc"" in GHCi the program returns the boolean as output so I think it was pretty reasonable to assume the boolean would return as output when executed in a do block but thanks for the tinges of pompousness y'all. StackExchange wouldn't be the same without belittling responses. – Bren Bailey Dec 08 '17 at 22:23
  • So are you saying there is a difference between compilation and using :load to run a program from GHCi? I'm afraid I'm confused about haskell code execution then. – Bren Bailey Dec 08 '17 at 22:24
  • @BrenBailey Ok, this question has become hugely broad. Have you read [learn you a haskell](http://learnyouahaskell.com/chapters)? Also, calling people pompous isn't going to help you get an answer, please refrain from insulting people. – AJF Dec 08 '17 at 22:29
  • actually yes I've been using this site. I guess I'll dig back into it. I'm in a class where our professor gave us literally 2 days to write 5 programs in a functional language (which I've never used since all of my classes including this one have been java, c++) ! So thanks and wish me luck! – Bren Bailey Dec 08 '17 at 22:34
  • 1
    ghci is a developer tool. It's not how you normally run a program. For that you'd either compile it (`ghc foo.hs`) and run the resulting executable, or you'd use the interpreter (`runghc foo.hs`). – melpomene Dec 08 '17 at 23:09

2 Answers2

4

This question is multiple questions in one, so I'll try to address each problem. I will address these in a different order to which they were stated in.

Before we begin, it must be said that you have critical misconceptions about the way Haskell works. I strongly recommend reading Learn You a Haskell for Great Good, which may seem juvenile, but is in fact a stellar introduction to functional programming, and in fact is the way many of us began learning Haskell.

Question 1: Compilation, GHC, and Haskell executables

(...) how can I set up a haskell script to just run when loaded? I don't want the user to have to type "main" I want it to just run.

You are confusing interpreted scripting languages like Python, Javascript, or Ruby, with compiled languages like C, Java, or Haskell.

Programs in interpreted languages are run by a program on the computer that contains information on how to interpret the text written, hence the name 'interpreted'. However, compiled languages are written, then converted from text into machine code, which is almost unreadable by humans, but which computers can run quickly.

When we write a complete, executable program in Haskell, we expect to compile it with The Glasgow Haskell Compiler, GHC (not GHCi). This looks something like this:

$ cat MyProgram.hs
main :: IO ()
main = putStrLn "This is my program!"
$ ghc MyProgram.hs
[1 of 1] Compiling Main             ( MyProgram.hs, MyProgram.o )
Linking MyProgram ...
$ ./MyProgram
This is my program!

Now, MyProgram.hs was converted by GHC from a Haskell source code file into an executable, MyProgram. We defined an IO action, called main, to tell the compiler where we wanted it to begin. This is called an entry point, and is necessary to create a standalone executable. This is how Haskell programs are created and run.

Crucially, GHCi is not how Haskell programs are run. GHCi is an interactive environment for experimenting with Haskell functions and definitions. GHCi allows you to evaluate expressions (such as palindrome "Hello", or main) but is not intended as the way to run Haskell programs, in the same way that python's IDLE is for Python programs.

Question 2: Functions vs IO actions

(...) If you just have the palindrome code outside of the do block and the user enters "palindrome "etc"" in GHCi the program returns the boolean as output (...)

Haskell does not behave like languages you may be used to. Functions in Haskell are not programs. When you defined your function palindrome, you made a way for the computer to convert a String into a Bool. You did not tell it how to output that Bool in any way. Hence, there is an extra step: the IO monad.

Haskell programs are, in a way, represented as data, hence the somewhat strange type signature main :: IO (). I will not be explaining monads in detail here, but put simply, in a do-block, you can only state things of type IO a where a is any type. So, when you wrote:

main = do
    -- (...)
    palindrome x
    -- (...)

It didn't make sense. Think of it this way: how can you 'run' or 'execute' a Bool? It's a boolean, not a program!

However, there is a function, called print, which allows you to do exactly that. Your line should be:

main = do
    -- (...)
    print (palindrome x)
    -- (...)

I won't go into prints type signature, but rest assured that it does indeed return an IO (), which allows us to put it into a do-block. By the way, if you write:

palindrome :: String -> Bool
palindrome x = x == reverse x

main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter Word"
  x <- getLine
  print (palindrome x)
  putStrLn "thanks"

...and compile the file with GHC, you will get the desired effect, assuming you did in fact want the program to output True or False. In fact, I compiled this as Palindromes.hs, and here's the result:

$ ghc Palindromes.hs 
[1 of 1] Compiling Main             ( Palindromes.hs, Palindromes.o )
Linking Palindromes ...
$ ./Palindromes
Brendon Bailey CSCI 4200-DB
Enter Word
amanaplanacanalpanama
True
thanks

Question 3: GHCi as a testing environment

[My code] works when "palindrome "etc"" is entered in GHCi then why doesn't my second code version do the same thing???

GHCi, as stated before, is different from GHC, in that it is an environment to test and 'play' with Haskell code before writing standalone programs.

In GHCi, you write expressions, and they are evaluated (using GHC's machinery), the result is printed, and it loops, Hence, this kind of system is often called a Read-Evaluate-Print-Loop, or a REPL.

Let's examine a bit of code in GHCi:

λ let plusOne n = n + 1
λ plusOne 5
6

The first line defines a value (here a function) that we can use later. The second line, however, is not a definition, but an expression. Hence, GHCi evaluates it, and prints the result.

GHCi can also execute IO actions:

λ let myProgram = putStrLn "Hello!"
λ myProgram
Hello!

This works because evaluating an IO action in Haskell is equivalent to executing them: this is how Haskell is designed to work - it's a truly brilliant idea provided that you grasp it.

Even though we see these similarities, GHCi is not equivalent to a Haskell program, as one might expect after using Python. GHCi unfortunately bears little resemblance to 'real' Haskell code, because Haskell works in a fundamentally different way to most other languages.

GHCi is nothing more than a useful way to quickly see results of our code, as well as other useful information that I won't explain here.

Other points

Monads are a key part of the problem here. There have been many, many questions on Monads here on StackOverflow as they tend to be a sticking point, so any questions you may have are likely here. This makes things difficult, since Haskell IO cannot be fully appreciated without an understanding of Monads. There is an LYAH chapter on Monads.

AJF
  • 11,767
  • 2
  • 37
  • 64
2

because they are not the same thing Haskell is a pure functional programming . with no side effects ,for example if a sum function changes a global variable, or prints the sum before returning it, those are side effects. Functions in most other languages frequently have side effects, typically making them hard to analyze. Functional programming languages seek to avoid side effects when possible.

in this case reading and writing to IO is side effects. operations that have side effects are handled by Monad (do) == (>>=)

this is valid code

palindrome :: String -> Bool
palindrome x = x == reverse x
main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter Word"
  x <- getLine
  let y = palindrome x
  putStrLn "thanks"
  print y

here is a good explanations about Monads

Naqib Hakimi
  • 874
  • 4
  • 15