2013-02-17 27 views
5

Jak mogę korzystać z czystych funkcji wewnątrz funkcji IO? : -/Haskell - Jak mogę korzystać z czystych funkcji wewnątrz funkcji IO?

Na przykład: Czytam plik (funkcja IO) i chcę przeanalizować jego kontekst, ciąg, używając czystej funkcji z referencyjną przezroczystością.

Wygląda na to, że takie światy, czyste funkcje i funkcje IO są rozdzielone. Jak mogę je połączyć?

+3

jakie samouczki przeczytałeś - każde wprowadzenie do IO w haskell obejmuje twoje pytanie. Rozwiązaniem jest utworzenie IO Monad. – epsilonhalbe

+0

Dziękuję. Rozwiązałem problem. Patrz poniżej: –

Odpowiedz

1

Pomógł mi Alex Horsman. Powiedział:

"Być może jestem nieporozumienie, ale to brzmi całkiem proste zrobić {x < - ioFunc; return (pureFunc x)}?"

I wtedy rozwiązać mój problem:

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

Można również rozważyć funkcję liftM z Control.Monad.
Trochę przykład pomóc (uruchom go do ghci jak jesteś pod IO Monady)

$ 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

Najprostszym sposobem jest użycie fmap, który posiada następujące rodzaje:

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

IO implementuje Functor, co oznacza, że ​​możemy wyspecjalizować powyższy typ, zastępując IO dla f, aby uzyskać:

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

Innymi słowy, bierzemy jakąś funkcję, która konwertuje a s na b s, i używa się jej do zmiany wyniku akcji IO. Na przykład:

getLine :: IO String 

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

Co się tam stało? Cóż, map toUpper ma typ:

map toUpper :: String -> String 

Zajmuje String jako argument i zwraca String wyniku. Mówiąc dokładniej, zwiększa on cały ciąg znaków.

Teraz spójrzmy na rodzaj fmap (map toUpper):

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

Byliśmy przeniesieni z funkcji do pracy na IO wartości. Przekształca wynik działania IO, aby zwrócić łańcuch o wielkich literach.

Możemy również zaimplementować to korzystając do notacji, aby:

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

>>> getUpperCase 
Test<Enter> 
TEST 

Okazuje się, że każda monada ma następującą właściwość:

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

Innymi słowy, jeśli typ implementuje Monad, wtedy zawsze powinna być w stanie implementować Functor, używając powyższej definicji.W rzeczywistości, zawsze możemy skorzystać z liftM jako domyślną implementację fmap:

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

liftM jest identyczna fmap, z wyjątkiem wyspecjalizowanych do monad, które nie są w ogóle jako funktorów.

Więc jeśli chcesz przekształcić wynikiem działania IO, Można użyć:

  • fmap,
  • liftM lub
  • do notacja

To naprawdę się do ciebie, który wolisz. Osobiście polecam fmap.

+0

Czy to nie wyjaśnia, w jaki sposób wyodrębnić wynik działania zamówienia reklamowego, a nie jak wywołać czystą funkcję * z * działania IO? –

0

Rzeczywista odpowiedź jest następująca:

main = do 
    val <- return (purefunc) 

return zawija je w odpowiednim monady takie, że można zrobić przypisać go do val.