Haskell ReplicaM IO

Я пытаюсь создать функцию, которая позволяет пользователю вводить список строк. Функция принимает длину и позволяет пользователю ввести длину еще на 1 строку. Затем каждая строка проверяется, чтобы убедиться, что она имеет ту же длину, что и исходная строка. Однако у меня есть несколько проблем, и я не могу найти решение.

Проблема в том, что я могу ввести больше строк, чем count-1, и длина вычисляется не так, как я ожидал. Например, если я ввожу ["12", "13"], а затем ["121", "13" ] выдается ошибка, хотя они одинаковой длины!

read :: IO [Line]
read = do
  line <- getLine
  let count = length line
  lines <- replicateM (count-1) $ do
    line <- getLine
    if length line /= count
    then fail "too long or too short"
    else return line
  return $ line : lines

Строка имеет тип String.

readLn выдает ошибку синтаксического анализа.


person gdrules    schedule 12.03.2012    source источник
comment
Ваш код отлично работает для меня (за исключением проблемы с отступом в блоке if-then-else).   -  person Matvey Aksenov    schedule 12.03.2012
comment
В качестве уточнения, первая строка ввода должна быть числом, которое говорит вам, сколько других строк? Или это число на самом деле основано на длине (количестве символов) первой строки, как вы написали здесь?   -  person huon    schedule 12.03.2012
comment
Строки ["12","13"] и ["121","13"] имеют разную длину; у последнего на один символ больше, чем у первого. Вы хотите читать строки или списки строк?   -  person danr    schedule 12.03.2012
comment
Число основано на длине первой строки, хотя, глядя на комментарии, я думаю, что проблема может быть связана с моим использованием длины. Он основан на персонажах? В прелюдии длины [12,13] и [121,13] оба возвращают 2.   -  person gdrules    schedule 12.03.2012
comment
Как сообщает Даниэль Вагнер в своем ответе, из getLine вы получаете String, поэтому длина — это количество символов в строке. Чтобы попробовать это в ghci, попробуйте length (show ["12","13"]).   -  person danr    schedule 12.03.2012


Ответы (1)


Мне кажется, что вы запутались в разнице между получением строки как String и чтением/анализом строки ввода как пользовательского типа. Вы используете getLine, который всегда возвращает именно то String, которое вводит пользователь. Сравнивать:

Prelude> fmap length getLine
["12","13"]
11
Prelude> length "[\"12\",\"13\"]" -- explanation of the 11
11
Prelude> fmap length (readLn :: IO [String])
["12","13"]
2
Prelude> length ["12", "13"] -- explanation of the 2
2

Как показано здесь, вы, вероятно, захотите использовать readLn, который сначала получает строку ввода, а затем анализирует ее с помощью read.

-- defined in the Prelude
readLn = do
    s <- getLine
    return (read s)

Если я изменю ваш код, чтобы включить импорт и определения ниже:

import Control.Monad
type Line = [String]

...и вызывать readLn вместо getLine, тогда я смогу набирать буквальные строки ["12","13"] и ["121","13"] без ошибок.

person Daniel Wagner    schedule 12.03.2012
comment
Спасибо за объяснение, теперь я вижу, хотя мой тип Line = String и я не могу изменить его на [String], так как он используется в различных других функциях, которые я определил. Поэтому при использовании readLn в этом случае возвращается ошибка синтаксического анализа. - person gdrules; 12.03.2012
comment
@gdrules: так что измени свои другие функции. Или добавьте код клея. - person rampion; 12.03.2012