Ferry
Ferry

Reputation: 583

Haskell - Print numbers

I've written following code:

module Test where

import Char
import IO

main = do
    str <- readFile "no.txt"
    putStrLn (show(english str))

string2list :: String -> [String]
string2list "" = []
string2list s = words s


english :: String -> Int
english s
    | head (string2list s) == "one"     = 1
    | head (string2list s) == "two"     = 2
    | head (string2list s) == "three"   = 3
    | head (string2list s) == "four"    = 4
    | head (string2list s) == "five"    = 5
    | head (string2list s) == "six"     = 6
    | head (string2list s) == "seven"   = 7
    | head (string2list s) == "eight"   = 8
    | head (string2list s) == "nine"    = 9
    | otherwise                         = error "not match"

And in no.txt:

one
two
three
four
....

After compiled and run the code, I got the result:

1

But I expect to get:

1
2
3
4
...

What's wrong with the code? Any help? thx!

Upvotes: 2

Views: 1944

Answers (3)

HaskellElephant
HaskellElephant

Reputation: 9891

Your problem is that english only looks at the first word. Your file comes in as

"one\ntwo\nthree\nfour"

Then words turns that into:

["one","two","three","four"]

Using head on that gives you:

"one"

And therefor 1 is printed.

Instaid we would like to use english on all the words. That is when map comes in handy, but in this case we are mapping an IO action onto the list, so we want to use mapM. Furthermore we are not interested in the outcome of the IO action (we just want the action to happen) so we use mapM_:

import Control.Monad

main = do
  str <- readFile "no.txt"
  mapM_ (print . english) (words str)

english "one"   = 1
english "two"   = 2
english "three" = 3
english "four"  = 4
english "five"  = 5
english "six"   = 6 
english "seven" = 7
english "eight" = 8 
english "nine"  = 9 

Note that it is possible to write this using map instaid of mapM by first making ["one","two","three",...] into ["1","2","3"], concating those strings, and then using putStrLn, but the above way is both shorter and more idiomatic.

Upvotes: 2

jeha
jeha

Reputation: 10700

str is not list of String (it's just a String like one\ntwo) when read from readFile. Do

main = do
    str <- readFile "no.txt"
    mapM_ (\x -> putStrLn (show(english x))) $ lines str

in your main instead and convert str to a list using lines (see doc of lines ).

Upvotes: 6

fuz
fuz

Reputation: 92966

This is not an answer to your question but rather a stylistic advice. You can get rid of those wordy head (string2list s) things by using pattern matching and by replacing string2list with words; both do exactly the same thing:

english s = case words s of
  "one"   :_ -> 1
  "two"   :_ -> 2
  "three" :_ -> 3
  "four"  :_ -> 4
  "five"  :_ -> 5
  "six"   :_ -> 6 
  "seven" :_ -> 7
  "eight" :_ -> 8 
  "nine"  :_ -> 9
  _          -> error "no match"

Upvotes: 5

Related Questions