2010-11-16 9 views
5

OK, staram się owijać głowę wokół IO w Haskell, i pomyślałem, że napiszę krótką małą aplikację do stron internetowych, aby to zrobić. Fragment jestem coraz nogę w Is (z przeprosinami do bobince, choć aby być uczciwym, ja nie próbuję parse HTML, po prostu wyodrębnić jedną lub dwie wartości):Haskell Curl Pomoc

titleFromUrl url = do 
    (_, page) <- curlGetString url [CurlTimeout 60] 
    matchRegex (mkRegexWithOpts "<title>(.*?)</title>" False True) page 

Powyższy powinien pobrać URL w postaci ciągu znaków, zeskanować stronę, na którą wskazuje: matchRegex, i zwrócić albo Nothing lub Just [a], gdzie a jest dopasowanym (prawdopodobnie wieloliniowym) ciągiem znaków. Frustrujące jest to, że gdy próbuję wykonywać interpretację w tłumaczu, robi dokładnie to, co chcę. Kiedy próbuję wczytać to samo wyrażenie i powiązać z nim plik imports, otrzymuję błąd wnioskowania typu informujący, że jest on couldn't match expected type 'IO b' against inferred type 'Maybe [String]'. To mówi mi, że brakuje mi czegoś małego i podstawowego, ale nie wiem, co. Próbowałem jawnie rzucić page na ciąg znaków, ale to tylko programowanie przez przesąd (i to nie działało w żadnym wypadku).

Jakieś wskazówki?

Odpowiedz

8

Tak, GHCi akceptuje jakąkolwiek wartość. Można powiedzieć:

ghci> 4 
4 
ghci> print 4 
4 

Ale te dwie wartości (4 i print 4) wyraźnie nie są równe. Magiczny GHC polega na tym, że jeśli to, co napisałeś, ocenia się na IO something, to wykonuje to działanie (i wypisze wynik, jeśli something nie jest ()). Jeśli nie, to wywołuje show na wartości i drukuje, że. W każdym razie magia ta nie jest dostępna z twojego programu.

Kiedy mówisz: ma być typu IO something

do foo <- bar :: IO Int 
    baz 

baz, i jest to błąd typu inaczej. Pozwoliłoby to wykonać I/O, a następnie zwrócić czystą wartość. Można sprawdzić, które z zauważając, że desugaring powyższe plonów:

bar >>= (\foo -> baz) 

I

-- (specializing to IO for simplicity) 
(>>=) :: IO a -> (a -> IO b) -> IO b 

Dlatego

bar :: IO a 
foo :: a 
baz :: IO b 

Sposób, aby naprawić to, aby Twoje wartości zwracanej do wartości IO przy użyciu funkcji return:

Kod jest następnie:

titleFromUrl url = do 
    (_, page) <- curlGetString url [CurlTimeout 60] 
    return $ matchRegex (mkRegexWithOpts "<title>(.*?)</title>" False True) page 

Dla większości dyskusji powyżej, można zastąpić dowolną monady dla IO (np. Maybe, [], ...) i nadal będzie to prawda.

+0

Działa, ale jako kontynuacja; czy rozumiem poprawnie, że to zasadniczo oznacza, że ​​nie mogę zwrócić regularnego ciągu znaków z funkcji, która wykonuje IO?że raczej musi to być 'IO String' (lub jak w powyższym przypadku' IO (Maybe [String]) '? Co jeśli chcę coś takiego jak połączyć wartość zwracaną' titleFromUrl' z innym ciągiem lub wydrukować to bez "Just [~ a]" owijanie go? Przepraszam, jeśli to jest głupie pytanie, jestem trochę nowy na silną maszynę do pisania – Inaimathi

+0

To dobrze, po prostu trzeba związać. Jeśli masz wartość ' m 'typu' IO a', możesz napisać 'do {x <- m; stuff}', a 'x' będzie miał typ' a', do którego możesz zrobić cokolwiek chcesz. Jedyne ograniczenie to to, że 'stuff' musi być pewnego rodzaju wartością' IO', która może być wartością lub wywołaniem funkcji, lub może być więcej powiązań '<-' .Dlatego możesz zrobić wszystko z wewnątrz' String', tak długo jak w końcu zwracasz coś typu "IO", sugeruję lekturę tutoriala z monadą, są tu tony, tutaj są dwa: http://blog.sigfpe.com/2006/08/you- mógłby-pozwolony-przypadku-monads-and. html lub LYAH rozdział 11 i 12. – luqui

+0

[facepalm] Ok, ja ** myślę ** że link pomógł. Nie miałem racji, zapominając, że nie można zagwarantować porządku wykonania w leniwym, czysto funkcjonalnym języku. Twoja modyfikacja do fragmentu kodu mówi kompilatorowi, aby wymusił wynik 'matchRegex' zanim użyje go w dowolnym miejscu. Czy jestem blisko? – Inaimathi