2013-02-17 4 views
5

Как я могу использовать чистые функции внутри функций ввода-вывода? : -/Haskell - Как я могу использовать чистые функции внутри функций ввода-вывода?

Например: Я читаю файл (функция ввода-вывода), и я хочу проанализировать его контекст, строку, используя чистую функцию с ссылочной прозрачностью.

Кажется, что такие миры, чистые функции и функции ввода-вывода отделены друг от друга. Как я могу их скрыть?

+3

Какие учебники вы прочитали - каждое введение в IO в haskell охватывает ваш вопрос. Решение заключается в создании IO Monad. – epsilonhalbe

+0

Спасибо. Я решил проблему. Посмотрите ниже: –

ответ

1

Алекс Хорсман помог мне. Он сказал:

"Может быть, я недоразумение, но это звучит довольно просто сделать {х < - ioFunc; возвращение (pureFunc х)}?"

И тогда я решил мою проблему:

import System.IO 
import Data.List 

getFirstPart line Nothing = line 
getFirstPart line (Just index) = fst $ splitAt index line 

eliminateComment line = 
getFirstPart line $ elemIndex ';' line 

eliminateCarriageReturn line = 
getFirstPart line $ elemIndex '\r' line 

eliminateEntersAndComments :: String -> String 
eliminateEntersAndComments text = 
concat $ map mapFunction $ lines text 
where 
    mapFunction = (++ " ") . eliminateCarriageReturn . eliminateComment 

main = do { 
contents <- readFile "../DWR-operators.txt"; 
return (eliminateEntersAndComments contents) 
} 
2

Вы также можете рассмотреть функцию liftM от Control.Monad.
Небольшой пример, чтобы помочь вам (запустить его в GHCI, как вы находитесь под IO Монады)

$ import Control.Monad -- to emerge liftM 
$ import Data.Char  -- to emerge toUpper 
$ :t map to Upper -- A pure function 
map toUpper :: [Char] -> [Char] 
$ :t liftM 
liftM :: Monad m => (a1 -> r) -> m a1 -> m r 
$ liftM (map toUpper) getLine 
8

Самый простой способ заключается в использовании fmap, которая имеет следующий вид:

fmap :: (Functor f) => (a -> b) -> f a -> f b 

IO реализует Functor, что означает, что мы можем специализироваться выше типа путем замены IO для f получить:

fmap :: (a -> b) -> IO a -> IO b 

Другими словами, мы берем некоторую функцию, которая преобразует a s в b s и использует это для изменения результата действия IO. Например:

getLine :: IO String 

>>> getLine 
Test<Enter> 
Test 
>>> fmap (map toUpper) getLine 
Test<Enter> 
TEST 

Что именно произошло? Ну, map toUpper имеет тип:

map toUpper :: String -> String 

Он принимает String в качестве аргумента и возвращает String в результате. В частности, это верхняя часть всей строки.

Теперь давайте посмотрим на тип fmap (map toUpper):

fmap (map toUpper) :: IO String -> IO String 

Мы обновили нашу функцию для работы на IO значений. Он преобразует результат действия IO, чтобы вернуть строку с верхним обсазом.

Мы также можем реализовать это с помощью do обозначения, чтобы:

getUpperCase :: IO String 
getUpperCase = do 
    str <- getLine 
    return (map toUpper str) 

>>> getUpperCase 
Test<Enter> 
TEST 

Оказывается, что каждая монада обладает следующим свойством:

fmap f m = do 
    x <- m 
    return (f x) 

Другими словами, если тип реализует Monad, то он должен всегда иметь возможность реализовать Functor, используя приведенное выше определение.На самом деле, мы всегда можем использовать liftM как реализация по умолчанию fmap:

liftM :: (Monad m) => (a -> b) -> m a -> m b 
liftM f m = do 
    x <- m 
    return (f x) 

liftM идентичен fmap, за исключением специализированных для монады, которые не являются в целом как функторы.

Так что, если вы хотите, чтобы преобразовать результат IO действия, вы можете использовать:

  • fmap,
  • liftM или
  • do обозначения

Это действительно до вам, который вы предпочитаете. Я лично рекомендую fmap.

+0

Не объясняет ли это, как извлечь результат действия IO, а не как вызывать чистую функцию * из * действия ввода-вывода? –

0

Фактический ответ заключается в следующем:

main = do 
    val <- return (purefunc) 

return оборачивает его в соответствующей монаде, что сделать ее можно отнести к Валу.