Haskell IO type Problems

Moderator
Posts: 373
Joined: 2006.08
Post: #1
Hello again Smile
I've begun learning Haskell, and it's very entertaining language so far, but I'm running into some problems with IO types. Unfortunately, I don't have access to a Mac right now, so I'm compiling this in Windows using WinHugs, but I think the same code should compile fine on Mac once I have access to one again...
Anyway, here's the code I'm trying to compile:
Code:
module Main
    where
import Data.Set
import Char
import List
import IO

processExtensions :: String -> String
processExtensions processing = do {

   case processing of {

   {- '.':extension -> "nothing"; -}
   _ -> "nothing";

   }

}

main = do {

hSetBuffering stdin LineBuffering;
putStrLn "Enter a filename to be parsed";
fileName <- getLine;
returnedFileName <- processExtensions fileName;
putStrLn returnedFileName;
putStrLn "Finished";

}

and here's the error:

Code:
ERROR file:.\meshConversions.hs:20 - Type error in generator
*** Term           : processExtensions fileName
*** Type           : [Char]
*** Does not match : IO a

As far as I can tell, this is because getLine returns a type of IO String, instead of just a normal String, but all the tutorials I've looked at say that making a variable and calling getLine with a <- should turn the input into a String, so I'm a bit confused here Annoyed

A few other general questions about Haskell:
String is just a synonym for [Char], right? Are there any differences between the two, or reasons why I should use one or the other?
Is my layout alright? I'm shying away from the whole "indent instead of using braces" thing (although I like it alright in Python), at least until I learn the language better....is this a good strategy, or should I start out just using indentation instead of braces?

What's the difference between a .hs and .hls file?

Any other comments on things I'm doing wrong in my code, or pieces of code that don't really follow convention?

Thank you Smile
-wyrmmage

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
Code:
module Main where

import IO

processExtensions :: String -> String
-- processExtensions ('.':ext) = "nothing"
processExtensions _ = "nothing"

main = do
    hSetBuffering stdin LineBuffering
    putStrLn "Enter a filename to be parsed"
    fileName <- getLine
    let returnedFileName = processExtensions fileName
    putStrLn returnedFileName
    putStrLn "Finished"

The right-hand side of <- has type "IO t" and the left-hand side has type "t".
"processExtensions s" has type "String" so it can't be on the right-hand-side of <-; you meant "let ... =".

Use indentation. Your code was almost unreadable to me until I made the syntax more normal.

.hs is Haskell Source, .lhs is "Literate Haskell", that is, a human-readable document with interspersed, compilable Haskell code. I've never used it but I think you have the option of TeX or plain text.

I almost never use "case", I much prefer pattern-matching in the left-hand side of a rule.

String and [Char] are exactly equivalent, except that String is slightly easier to type and to read Wink
Quote this message in a reply
Moderator
Posts: 373
Joined: 2006.08
Post: #3
Thank you; it works now...and you're right, your version of the code looks much better Rasp
So, do I only use <- when I have a return type of IO *something*, or do I use it for functions that are 'function = do ...', instead of just using = for a normal function?

Thanks again Smile
-wyrmmage

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
a "do" "statement" will always result in a "return" which means that a function defined as f args = do ... will always have a return type in some monad or another...
Quote this message in a reply
Moderator
Posts: 373
Joined: 2006.08
Post: #5
ok; thank you Smile That makes things a bit clearer. My next thing I tried to do is not working, however, and I can't figure out why Sad

What I'm attempting to do is this:
Read in a string
Test to see if the string has ".wrl" in it; if so, return the string that was originally passed to the function
If it didn't have .wrl in the string, test to see if there was a . at all...if so, strip the letters before the dot into one string, and the letters after it into a different string
Finally, if neither of the above two options happened, just append ".wrl" onto the end of the string and return it.

Here's the code I tried:
Code:
module Main where

import IO

processExtensions (x:".wrl") = x:".wrl"
processExtensions (x:'.':xs) = error "only .wrl files are supported"
processExtensions (x) = x ++ ".wrl"

main = do
    hSetBuffering stdin LineBuffering
    putStrLn "Enter a filename to be parsed"
    fileName <- getLine
    let newFileName = processExtensions fileName
    putStrLn newFileName
    putStrLn "Finished"

However, whenever I execute the above code, it always jumps to the third possibility: processExtensions (x) = x ++ ".wrl"
If I remove the third statement and type in something like "test.wrl" when prompted, I get a message telling me that none of my patterns match: 'Program error: pattern match failure: processExtensions "test.wrl"', however if I keep the third statement, it just appends ".wrl" onto whatever I type in Sad

How would I go about doing this....or what mistakes am I making in my current code?
Thank you Smile

-wyrmmage

--Edit--

Actually, it seems like its only evaluating this: "processExtensions (x:".wrl")" if whats before the ".wrl" is only a single letter, not a String. How would I modify it to accept strings, as well as single characters?

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #6
Code:
(:) :: t -> [t] -> [t]

That is, it appends a single item to the head of a list. Learn to use :t in GHCi/hugs, or /msg lambdabot @type in IRC Wink

You can't do what you need with pattern matching alone. This works:

Code:
module Main where

import IO

processExtensions s =
    let ext = dropWhile (/= '.') s
    in case ext of
        ".wrl"    -> s
        ""        -> s ++ ".wrl"
        _         -> error "only .wrl files are supported"

main = do
    hSetBuffering stdin LineBuffering
    putStrLn "Enter a filename to be parsed"
    fileName <- getLine
    let newFileName = processExtensions fileName
    putStrLn newFileName
    putStrLn "Finished"

Note that ".wrl" can be written ('.': ('w': ('r': ('l': [])))) and that "" can be written [], the first pair are exactly equivalent, "" has a more specific type than [].
Quote this message in a reply
Moderator
Posts: 373
Joined: 2006.08
Post: #7
ah, ok Smile
That's a really cool little piece of code ^_^
As far as the "" vs [] goes: does "" match only empty Strings, while [] matches any empty List?

Thanks again, this has been a huge help Smile
-wyrmmage

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
Code:
CookieJar:~ keith$ ghci
   ___         ___ _
  / _ \ /\  /\/ __(_)
/ /_\// /_/ / /  | |      GHC Interactive, version 6.6.1, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Prelude> :t ""
"" :: [Char]
Prelude> :t []
[] :: [a]
Quote this message in a reply
Member
Posts: 567
Joined: 2004.07
Post: #9
Strings, like in C[++] are simply arrays of Chars, and you can treat them as such; strings in haskell are (correct me if I'm wrong) null terminated, so "" /= []::Char

On the bright side, your indenting leads to cheery code. Notice the '; -}' smiley face?

It's not magic, it's Ruby.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #10
You're wrong.

Strings are exactly [Char], it makes no sense for them to be NUL-terminated, and "" is exactly equivalent to []::[Char]

Try it out in GHCi.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Haskell IO String Problem michxs 2 5,092 Mar 11, 2008 06:24 PM
Last Post: wyrmmage
  Haskell Data Types and Functions wyrmmage 1 3,376 Mar 4, 2008 05:25 PM
Last Post: OneSadCookie