#haskell #printing
#haskell #печать
Вопрос:
Я написал следующий код:
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"
И в no.txt:
one
two
three
four
....
После компиляции и запуска кода я получил результат:
1
Но я ожидаю получить:
1
2
3
4
...
Что не так с кодом? Любая помощь? спасибо!
Комментарии:
1. Просто подсказка: если вы хотите, чтобы ваша программа обрабатывала каждую строку во входных данных, было бы разумно, что где-то вы будете преобразовывать входные данные (которые в настоящее время представляют собой только одно длинное строковое значение) в отдельные
lines
.2. Не имеет отношения к вашему вопросу, но
words ""
есть[]
, поэтому вы можете избавиться отstring2list
и просто использоватьwords
вместо этого.
Ответ №1:
str
это не список строк (это просто строка типа onentwo
) при чтении из readFile
. Делать
main = do
str <- readFile "no.txt"
mapM_ (x -> putStrLn (show(english x))) $ lines str
main
вместо этого и преобразуйте str
в список с помощью lines
(см. Документ с строками ).
Комментарии:
1. Ваш код работает, но я думаю, что ваше замечание о том, почему его сбой, неверно, поскольку это тот случай,
lines . words == words
и он использует слова. Я думаю, что следует обратить внимание на тот факт, что вы отображаетеenglish
в список строк. На стилистической нотеputStrLn . show == print
.
Ответ №2:
Это не ответ на ваш вопрос, а скорее стилистический совет. Вы можете избавиться от этих многословных head (string2list s)
вещей, используя сопоставление с шаблоном и заменив string2list
на words
; оба делают одно и то же:
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"
Комментарии:
1. Это также значительно повышает производительность (поскольку в исходном решении words вычисляется повторно, один раз для каждого защитника).
2. @Jonas кроме того, GHC достаточно умен, чтобы объединять похожие случаи, если вы используете обычный шаблон.
Ответ №3:
Ваша проблема в том, что english
просматривается только первое слово. Ваш файл поступает как
"onentwonthreenfour"
Затем words
превращает это в:
["one","two","three","four"]
Использование head on, которое дает вам:
"one"
И для этого 1
печатается.
Вместо этого мы хотели бы использовать английский для всех слов. Вот когда map
пригодится, но в данном случае мы отображаем действие ввода-вывода в список, поэтому мы хотим использовать mapM
. Кроме того, нас не интересует результат действия ввода-вывода (мы просто хотим, чтобы действие произошло), поэтому мы используем 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
Обратите внимание, что это можно записать с помощью map
instaid of mapM
, сначала создав ["one","two","three",...]
into ["1","2","3"]
, объединив эти строки, а затем используя putStrLn
, но приведенный выше способ короче и более идиоматичен.