Haskell способ присоединить [IO String] в IO String - PullRequest
4 голосов
/ 09 декабря 2010

Моя цель - написать функцию на Haskell, которая читает N строк из ввода и объединяет их в одну строку.Ниже приведена первая попытка:

readNLines :: Int -> IO String
readNLines n = do
  let rows = replicate n getLine
  let rowsAsString = foldl ++ [] rows 
  return rowsAsString  

Здесь жалобы haskell на foldl:

Не удалось найти ожидаемый тип [a]' against inferred type (a1 -> b -> a1)-> a1 -> [b] -> a1 '

Как я понимаю, тип строк - [IO String], возможно ли как-то объединить такой список в один IO String?

Ответы [ 5 ]

19 голосов
/ 09 декабря 2010
6 голосов
/ 09 декабря 2010

Кроме того, на что указывает эпимент, я думаю, у вас есть проблема с синтаксисом: то, как вы используете оператор ++, создает впечатление, что вы пытаетесь вызвать оператор ++ с операндами foldl и * 1004. *. Поставьте оператор ++ в скобки, чтобы прояснить свое намерение:

foldl (++) [] rows
5 голосов
/ 10 декабря 2010

Вы ищете следующие функции: sequence, однако следует отметить, что

sequence (replicate n f)

совпадает с

replicateM n f

И foldl (++) [] эквивалентноconcat.Итак, ваша функция:

readNLines n = liftM concat (replicateM n getLine)

В качестве альтернативы, если вы хотите сохранить разрывы строк:

readNLines n = liftM unlines (replicateM n getLine)
1 голос
/ 10 декабря 2010

Самый короткий ответ, который я могу придумать:

import Control.Applicative
import Control.Monad

readNLines :: Int -> IO String
readNLines n = concat <$> replicateM n getLine
0 голосов
/ 10 декабря 2010

replicate возвращает список IO String действий.Для выполнения этих действий их нужно запустить в монаде IO.Поэтому вы не хотите присоединяться к массиву действий ввода-вывода, а просто запускать их все по порядку и возвращать результат.

Вот что я бы сделал

readNLines :: Int -> IO String
readNLines n = do
  lines <- replicateM n getLine
  return $ concat lines

Или в аппликативномstyle:

import Control.Applicative

readNLines :: Int -> IO String
readNLines n = concat <$> replicateM n getLine

Оба они используют монадическую реплику (replicateM), которая оценивает список монадических значений в последовательности, а не просто возвращает список действий

...