2009-11-04 21 views
31

Napisałem kilka kodu w Haskell, aby utworzyć indeks tekstu. Górny funkcja wygląda tak:Funkcja Haskell typu: IO String-> String

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

Teraz chcę dać tę funkcję String odczytu z pliku:

index readFile "input.txt" 

które nie będą działać, ponieważ readfile jest typu filePath -> IO String .

Nie można oczekiwać Typ dopasowania 'String' przeciwko wywnioskować typu 'IO String'

widzę ten błąd, ale nie mogę znaleźć żadnej funkcji z typu:

IO String -> String 

Sądzę, że kluczem do sukcesu jest gdzieś pod kilkoma Monadami, ale nie mogłem znaleźć sposobu na rozwiązanie mojego problemu.

+3

Spójrz tutaj dobrego tutoriala monady: http://blog.sigfpe.com/2006/ 08/you-could-have-invented-monads-and.html –

+1

Inne dobre zasoby można znaleźć tutaj w SO. Po prostu spójrz na sekcję Powiązane, bezpośrednio na ekranie. –

Odpowiedz

37

Możesz z łatwością napisać funkcję, która wywołuje akcję readFile, i przekazuje wynik do funkcji indeksu.

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

Jednak monada IO obarczone wszystko, używa go, więc ta funkcja ma typ:

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

To tylko małe zdanie: "monogram IO splami wszystko, co go używa". Zakładałem, że tak jest, ale miło jest teraz to potwierdzić. Dzięki^^ – drumfire

15

Nie można się pozbyć części monadowej IO z IO String. Oznacza to, że będziesz musiał przywrócić swoją funkcję IO [(String, [Integer])].

polecam dowiedzieć się więcej o monad, ale teraz można uciec z liftM funkcję:

liftM index (readFile "input.txt") 

liftM ma ten podpis:

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

To trwa non-jednowartościowy funkcję i przekształca go w funkcję monadyczną.

27

istnieje bardzo dobry powód, dlaczego nie ma takiej funkcji.

Haskell ma pojęcie funkcjonalnej czystości. Oznacza to, że funkcja zawsze zwraca ten sam wynik, gdy zostanie wywołana z tymi samymi parametrami. Jedynym miejscem, w którym dozwolona jest IO, jest moneta IO.

jeśli nie było * funkcję

index :: IO String -> String 

wtedy moglibyśmy nagle zrobić działania IO Wszędzie wywołując na przykład:

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

czystość funkcjonalna jest to bardzo przydatna funkcja, że ​​don nie chce stracić, ponieważ pozwala kompilatorowi na kolejną zmianę i wbudowanie funkcji o wiele bardziej swobodnie, może zostać wywołany do różnych rdzeni bez zmiany semantyki, a także daje programistom poczucie bezpieczeństwa, ponieważ jeśli potrafisz k teraz, co funkcja może i czego nie może zrobić z jej typu.

* W rzeczywistości istnieje taka funkcja . Nazywa się to unsafePerformIO i nazywa się to na bardzo, bardzo, dobrych powodów. Nie używaj go, chyba że jesteś w 100% pewny, co robisz!

+13

Posunąłbym się aż do powiedzenia "Nie używaj tego, jeśli nie jesteś 200% pewny, co robisz" lub, jeszcze prostsze, "Nie rób". –

+6

Powiedziałbym, że najlepszym rozwiązaniem dla niebezpiecznego projektu jest wyprowadzenie procesu, który powinien zawsze zwracać to samo. tj. obliczenia systemowe, które nie są natywnie obsługiwane przez bibliotekę standardową. – alternative

+4

Dodawanie do mojego starego komentarza, który właśnie znalazłem podczas przeglądania SO: Również przydatne dla FFI – alternative

8
fmap index $ readFile "input.txt" 

lub

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

Możesz zajrzeć do monady i funktorów