Haskell — Печать чисел

#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 , но приведенный выше способ короче и более идиоматичен.