Подтвердить что ты не робот

Функция Haskell типа: IO String-> String

Я написал кучу кода в Haskell, чтобы создать индекс текста. Верхняя функция выглядит так:

index :: String -> [(String, [Integer])]
index a = [...]

Теперь я хочу дать этой функции строку, считанную из файла:

index readFile "input.txt"

Что не будет работать, потому что readFile имеет тип FilePath → IO String.

Не удалось совместить ожидаемый тип 'String' против предполагаемого типа 'IO String'

Я вижу ошибку, но я не могу найти какую-либо функцию с типом:

IO String -> String

Я думаю, что ключ к успеху лежит где-то под некоторыми Монадами, но я не мог найти способ решить мою проблему.

4b9b3361

Ответ 1

Вы можете достаточно легко написать функцию, которая вызывает действие readFile, и передает результат вашей индексной функции.

readAndIndex fileName = do
    text <- readFile fileName
    return $ index text

Тем не менее, монашка IO уничтожает все, что ее использует, поэтому эта функция имеет тип:

readAndIndex :: FilePath -> IO [(String, [Integer])]

Ответ 2

Есть очень веская причина, почему такая функция отсутствует.

Haskell имеет понятие функциональной чистоты. Это означает, что функция всегда возвращает тот же результат при вызове с теми же параметрами. Место только, где разрешено IO, находится внутри монады IO.

Если была * функция

index :: IO String -> String

то мы могли бы внезапно совершать действия IO в любом месте, вызывая, например:

index (launchMissiles >> deleteRoot >> return "PWNd!")

Функциональная чистота - очень полезная функция, которую мы не хотим потерять, так как она позволяет компилятору изменять порядок и встроенные функции гораздо более свободно, их можно инициировать на разные ядра без изменения семантики, а также дает у программистов чувство безопасности, поскольку, если вы можете знать, что функция может и не может сделать из этого типа.

* На самом деле существует такая функция. Он назывался unsafePerformIO, и он назвал это по очень, очень веским причинам. Не используйте его, если вы на 100% не уверены в том, что делаете!

Ответ 3

Ну, вы не можете избавиться от монадной части IO IO String. Это означает, что вам нужно будет вернуть функцию IO [(String, [Integer])].

Я рекомендую узнать больше о монадах, но теперь вы можете уйти с помощью функции liftM:

liftM index (readFile "input.txt")

liftM имеет такую ​​подпись:

liftM :: Monad m => (a -> b) -> m a -> m b

Он принимает немонодическую функцию и преобразует ее в монадическую функцию.

Ответ 4

fmap index $ readFile "input.txt"

или

readFile "input.txt" >>= return . index

Возможно, вы захотите посмотреть на монады и функторы