Haskell - Putting out result of function

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »

46 Replies - 4709 Views - Last Post: 24 July 2016 - 11:47 AM

#1 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Haskell - Putting out result of function

Posted 11 July 2016 - 10:13 AM

Hey

I'm trying to learn Haskell since yesterday-night. It's my first functional programming language and I'm still having problems with a few things.

For example, I'm was being busy this whole day figuring out how to make a 'while-loop' in Haskell to keep asking user-input until the input is empty. Then, I want to print out those lines.

My code:
import System.IO

summation x y = x + y

prompt txt = do
    putStr txt
    hFlush stdout
    getLine

--Error with this function
getLines = do
    word <- getLine
    if word == ""
        then return []
    else do
        let content = "\n" ++ content ++ word
        getLines

makeUpper = map
    (\c -> if c >= 'a' && c <= 'z'
        then toEnum (fromEnum c - 32) 
    else c)

main = do
    name <- prompt "Name: "
    putStrLn $ "Please " ++ name ++ " Give the..."

    a <- prompt "First number: "
    b <- prompt "Second number: "

    putStrLn $ show $ summation (read a) (read B)/>

    opt1 <- prompt "Make a list [Y/n]? "
    if (makeUpper opt1) == "Y"
        --Can I print/putStr it here?
        then getLines
     else return []




I commented the parts where the problem is.
In the function getLines I'm able to keep asking user-input until it's empty input.
However, in the if-statement, I want to print-out all the lines putted in by the user.

How'd I go about that?

Thanks

Is This A Good Question/Topic? 0
  • +

Replies To: Haskell - Putting out result of function

#2 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 11:24 AM

To print the result of `getLiines`, you can do getLines >>= print or, using do notation:

do
  lines <- getLines
  print lines



However getLines will only ever produce the empty list. Your base case returns the empty list and the recursive case simply returns the result of the recursive call without adding anything to it, so that will still be the empty list.

You also define a variable content that you never use and whose definition is infinitely recursive (so if you did use it, you'd get an infinite loop).
Was This Post Helpful? 0
  • +
  • -

#3 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 01:11 PM

What I rather meant, was putting all the inputted values in a list, and print out the list OUTSIDE the getLines function.
getLines create the list, how do I output it in main?

Code:
import System.IO
import Data.List

summation x y = x + y

prompt txt = do
    putStr txt
    hFlush stdout
    getLine

--Error with this function
getLines = do
    let allWords = []
    word <- getLine
    if word == ""
        then return allWords
    else do
        let allWords = words : allWords
        getLines

makeUpper = map
    (\c -> if c >= 'a' && c <= 'z'
        then toEnum (fromEnum c - 32) 
    else c)

main = do
    name <- prompt "Name: "
    putStrLn $ "Please " ++ name ++ " Give the..."

    a <- prompt "First number: "
    b <- prompt "Second number: "

    putStrLn $ show $ summation (read a) (read B)/>/>

    opt1 <- prompt "Make a list [Y/n]? "
    if (makeUpper opt1) == "Y"
        --Can I print/putStr it here?
        then putStr $ getLines
     else putStr ""




Output:

Quote

[1 of 1] Compiling Main ( C:\users\niel\desktop\test.hs, C:\users\name\desktop\test.o )

C:\users\name\desktop\test.hs:38:23: error:
* Couldn't match type `IO [t0]' with `[Char]'
Expected type: String
Actual type: IO [t0]
* In the second argument of `($)', namely `getLines'
In the expression: putStr $ getLines
In a stmt of a 'do' block:
if (makeUpper opt1) == "Y" then putStr $ getLines else putStr ""



Would someone also explain a bit more what 'let' is? I kind of understand it, that you use that variable in the following expression; but more explanation would be good.

Does someone also have tips for how to avoid conflicts in the else-part if if-then-else. I've read that the else must have the same 'type' than the if. How can you do this in each situation?

This post has been edited by O'Niel: 11 July 2016 - 01:13 PM

Was This Post Helpful? 0
  • +
  • -

#4 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 01:24 PM

View PostO, on 11 July 2016 - 10:11 PM, said:

getLines create the list, how do I output it in main?


Like this:

View Postsepp2k, on 11 July 2016 - 08:24 PM, said:

To print the result of `getLiines`, you can do getLines >>= print or, using do notation:

do
  lines <- getLines
  print lines




View PostO, on 11 July 2016 - 10:11 PM, said:

Code:
        --Can I print/putStr it here?
        then putStr $ getLines



As the error message is trying to tell you, putStr takes an argument of type String, but getLines is not a String, it's an IO [String]. That's why you need to use >>= or do notation to unpack it, giving you a list of strings. Then you can print that using either print (which will print it as a list in Haskell syntax) or mapM putStrLin (which will print one element of the list per line).


Quote

Would someone also explain a bit more what 'let' is? I kind of understand it, that you use that variable in the following expression; but more explanation would be good.


let var = value in body defines a variable named var, which will be in scope in body. If you're inside a do-block, you don't need the in, in which case the body will be the rest of the do-block.


Note that let always creates a new variable and you can't change the value of a given variable once defined. If you use let with a variable name that already exists, you'll create a new variable that shadows the old one. This does not affect the value of the original variable.
Was This Post Helpful? 1
  • +
  • -

#5 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 02:37 PM

Thanks for the explanation about 'Let', however, I'm implementing your code wrong somehow.

Code:
    if (makeUpper opt1) == "Y"
        --Can I print/putStr it here?
        then do
            lines <- getLines
            print lines
     else print ""



Output:

Quote

* Ambiguous type variable `t0' arising from a use of `print'
prevents the constraint `(Show t0)' from being solved.
Relevant bindings include
lines :: [t0] (bound at C:\users\niel\desktop\test.hs:39:13)
Probable fix: use a type annotation to specify what `t0' should be.
These potential instances exist:
instance Show HandlePosn -- Defined in `GHC.IO.Handle'
instance Show BufferMode -- Defined in `GHC.IO.Handle.Types'
instance Show Handle -- Defined in `GHC.IO.Handle.Types'
...plus 27 others
...plus 11 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In a stmt of a 'do' block: print lines
In the expression:
do { lines <- getLines;
print lines }
In a stmt of a 'do' block:
if (makeUpper opt1) == "Y" then
do { lines <- getLines;
print lines }
else
print ""

Was This Post Helpful? 0
  • +
  • -

#6 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 02:47 PM

No, you did it right. The problem is that the compiler doesn't know that getLines is supposed to return a list of strings because it doesn't have a type signature and, as I mentioned, it only ever returns an empty list, so Haskell can't infer what type is supposed to be inside the list. If you add a type signature to the definition of getLines (getLines :: IO [String]), it should compile.

Once you've fixed your getLines function, it should work even without the type signature, but giving top-level functions a type signature is good practice anyway.
Was This Post Helpful? 1
  • +
  • -

#7 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 03:20 PM

Thanks, it's compiling now!
However, the only output I get indeed is an empty list.
Is this because I defined let allWords = [], and
variables can't change in Haskell?

How do I fix this?
Was This Post Helpful? 0
  • +
  • -

#8 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 11 July 2016 - 03:33 PM

Since you never actually use allWords, its value does not matter (but yes, since variables can't change in Haskell, a definition like let allWords = [] is not very useful).

The reason that getLines always returns the empty list is that, as I said, you return the empty list in the base case and you never add anything to that result in the recursive case.

You need to unwrap the list returned by the recursive call and prepend the current line to it. If you only every pass around the same list, it's always going to be empty.
Was This Post Helpful? 0
  • +
  • -

#9 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 04:54 AM

Would you like explaining that more?
I searched "unwrap list haskell", and found this: https://mail.haskell...ust/010380.html

But I don't really get it.
Could you give an example of how to unwrap a list, and what that actually means, and why it's needed?

Also, are there so few resources about Haskell because it's still a young language?
When you search something about e.g C++ you get 50 Google pages explaining the same thing.
Was This Post Helpful? 0
  • +
  • -

#10 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6996
  • View blog
  • Posts: 14,635
  • Joined: 16-October 07

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 05:49 AM

Let's say your user wants to input:
Alice
Bob




Think about how your code will deal with that input. Your current code does this:
- x = IO "Alice"
- not "" call self
-- x = IO "Bob" 
-- not "" call self
--- x = IO "" 
--- is "" return IO []
-- return IO []
- return IO []



You want to see your code do this:
- x = IO "Alice"
- not "" call self
-- x = IO "Bob" 
-- not "" call self
--- x = IO "" 
--- is "" return IO []
-- return IO ["Bob"]
- return IO ["Alice", "Bob"]



Note, for learning Haskell, I would avoid IO for a while. It's messy and overly complicated because it ain't "pure." Try solving problems that don't require interaction. Get the hang of how the language works well before you get to experience when it doesn't.
Was This Post Helpful? 1
  • +
  • -

#11 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 07:32 AM

Yeah, I think I'll try to do things without user input first.
Was This Post Helpful? 0
  • +
  • -

#12 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 08:54 AM

View PostO, on 12 July 2016 - 01:54 PM, said:

Could you give an example of how to unwrap a list, and what that actually means, and why it's needed?


By "unwrap the list" I meant take the list out of the IO, i.e. what `<-` does.
Was This Post Helpful? 0
  • +
  • -

#13 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 09:07 AM

Yet another question.
This code is working:
func = do
    let x = "d"
    let lst = ["a", "b", "c", x]
    lst ++ ["e"]
     
main = do
    putStr $ show func





I can append to a list. :bananaman:

However, when I try to put the function 'func' in my main. I get this error:

Quote

* Couldn't match expected type `IO t0' with actual type `[()]'
* In the expression: main
When checking the type of the IO action `main'


This is because main if of the type IO which only expects input/output? So, no way to do this?
Also, in imperative languages you need to return, to return a function. In Haskell the last line is automatically returned?
Was This Post Helpful? 0
  • +
  • -

#14 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2517
  • View blog
  • Posts: 4,001
  • Joined: 21-June 11

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 09:29 AM

For which code do you get that error? The code you posted compiles and runs without a problem.

PS: func is a bit misleadingly named as it's not a function, just a value of type [String].
Was This Post Helpful? 0
  • +
  • -

#15 O'Niel  Icon User is offline

  • D.I.C Regular

Reputation: 14
  • View blog
  • Posts: 389
  • Joined: 13-September 15

Re: Haskell - Putting out result of function

Posted 12 July 2016 - 10:18 AM

This code:
 main = do
    let x = "d"
    let lst = ["a", "b", "c", x]
    lst ++ ["e"]
    putStr $ show lst



And why is func not a function? I use do? When you do something, you're functioning, not?
Or ain't it a function because it has no parameters?
Was This Post Helpful? 0
  • +
  • -

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »