问题描述:

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!

网友答案:

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 ).

网友答案:

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"
网友答案:

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.

相关阅读:
Top