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
.
jakie samouczki przeczytałeś - każde wprowadzenie do IO w haskell obejmuje twoje pytanie. Rozwiązaniem jest utworzenie IO Monad. – epsilonhalbe
Dziękuję. Rozwiązałem problem. Patrz poniżej: –