2013-02-17 14 views
5

Wie kann ich reine Funktionen in IO-Funktionen verwenden? : -/Haskell - Wie kann ich reine Funktionen in IO-Funktionen verwenden?

Zum Beispiel: Ich lese eine Datei (IO-Funktion) und ich möchte seinen Kontext, eine Zeichenfolge, analysieren, indem Sie eine reine Funktion mit referenzieller Transparenz verwenden.

Es scheint, dass solche Welten, reine Funktionen und IO-Funktionen, getrennt sind. Wie kann ich sie möglicherweise überbrücken?

+3

welche Tutorials haben Sie gelesen - jede Einführung zu IO in Haskell deckt Ihre Frage ab. Die Lösung besteht darin, die IO-Monade zu erstellen. – epsilonhalbe

+0

Danke. Ich habe das Problem gelöst. Siehe unten: –

Antwort

1

Alex Horsman hat mir geholfen. Er sagte:

"Vielleicht ich bin Missverständnis, aber das klingt ziemlich einfach tun {x < - ioFunc; return (pureFunc x)}?"

Und dann löste ich mein 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

Sie können die Funktion liftM auch von Control.Monad aus betrachten.
Ein kleines Beispiel, um Ihnen (es in GHCI laufen, wie Sie unter dem IO Monade sind)

$ 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

Der einfachste Weg fmap zu verwenden, die den folgenden Typ hat:

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

IO implementiert Functor, was bedeutet, dass wir die oben genannte Art durch Substitution IO für f erhalten spezialisieren können:

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

Mit anderen Worten, wir nehmen eine Funktion, die a s zu b s konvertiert, und verwenden, um das Ergebnis einer IO Aktion zu ändern. Zum Beispiel:

getLine :: IO String 

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

Was ist gerade dort passiert? Nun, map toUpper Typ hat:

map toUpper :: String -> String 

Es hat eine String als Argument und gibt eine String als Ergebnis. Insbesondere wird die gesamte Zeichenfolge großgeschrieben. Jetzt

, schauen wir uns die Art von fmap (map toUpper) aussehen:

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

Wir haben ein Upgrade unsere Funktion auf IO Werten zu arbeiten. Es transformiert das Ergebnis einer IO Aktion, um eine Großbuchstaben-Zeichenfolge zurückzugeben.

Wir können auch implementieren diese do Notation, zu:

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

>>> getUpperCase 
Test<Enter> 
TEST 

Es stellt sich heraus, dass jede Monade die folgende Eigenschaft hat:

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

Mit anderen Worten, wenn irgendein Typ Monad implementiert, Dann sollte es immer in der Lage sein, auch Functor mit der obigen Definition zu implementieren.In der Tat können wir immer die liftM als Implementierung Standard verwenden von fmap:

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

liftM ist identisch mit fmap, außer spezialisiert auf Monaden, die als functors nicht so allgemein sind.

Also, wenn Sie das Ergebnis eines IO Aktion zu transformieren möchten, können Sie entweder:

  • fmap,
  • liftM oder
  • do Notation

Es ist wirklich zu dir welche du bevorzugst. Ich empfehle persönlich fmap.

+0

Erklärt dies nicht, wie man das Ergebnis einer IO-Aktion extrahiert, anstatt wie man eine reine Funktion * von * einer IO-Aktion aufruft? –

0

Die eigentliche Antwort lautet wie folgt:

main = do 
    val <- return (purefunc) 

return wickelt es in der entsprechenden Monade, so dass es zu val zuweisen tun können.

Verwandte Themen