Haskell – Wejście/Wyjście
Transkrypt
Haskell – Wejście/Wyjście
Haskell – Wejście/Wyjście W Haskelu funkcje nie mogą zmieniać stanów (w tym np. zmieniać wartości zmiennej). Funkcja wywołana z pewnymi ustalonymi argumentami musi zwracać zawsze tą samą wartość niezależnie od tego ile razy i w jakim kontekście zostanie wywołana. Gdyby funkcje wejścia/wyjścia zwracały wartość np. odczytaną z klawiatury to zaprzeczały by idei Haskella, gdyż dla dwóch różnych wywołań z tymi samymi wartościami parametrów otrzymywalibyśmy różne wyniki. Haskell – Wejście/Wyjście Haskell rodzi sobie z tym problemem definiując typ wejściowo - wyjściowy, którego wartości zwracają funkcję wejścia – wyjścia np. funkcja getLine odczytuje linię ze standardowego wejścia: ghci> :t getLine getLine :: IO String Haskell – Wejście/Wyjście Ze względu na fakt zmiany stanu jako efekt uboczny działania funkcji w Hasklellu funkcje dzielimy na czyste i nieczyste: Funkcja czysta Funkcja nieczysta Przy tych samych argumentach zwraca ten sam wynik Przy tych samych argumentach może zwracać różny wynik Nie zmienia stanów Może zmieniać stany Nie posiada efektów ubocznych Może posiadać efekty uboczne Haskell – Wejście/Wyjście Wartosci zwracane przez funkcje nieczyste (w tym funkcje wejscia – wyjscia odczytujemy przez wiązanie wartości: name < getLine Należy przez to rozumie: wykonaj akcję wejścia wyjścia getLine i zwiąż jej wynik z name. Przypisanie: name = getLine spowodowałoby nadanie funkcji getLine nowej nazwy! Wiązanie jest odpowiednikiem let dla funkcji czystych. Haskell – Wejście/Wyjście Funkcje wejścia – wyjścia: putChar:: Char> IO () putStr::String> IO () putStrLn::String> IO () print: Show a =>a> IO () getChar:: IO Char getLine:: IO String Funkcje wyprowadzające dane zwracają wynik IO (), gdzie () oznacza typ pusty, zaś funkcje wprowadzające dane zwracają wynik IO a, gdzie a jest typem wczytywanej wartości. Haskell – Wejście/Wyjście Program w Haskellu: main = putStrLn "Hello, world" Zapisany w pliku hello.hs kompilujemy: ghc hello.hs o hello lub ghc make hello I wykonujemy: ./hello Haskell – Wejście/Wyjście Plik name.hs: main = do putStrLn"Podaj imie:" imie<getLine putStrLn(„Witaj" ++imie++".") Uruchamiamy: runhasklell name.hs Haskell – Wejście/Wyjście Taki kod przypomina nieco programowanie imperatywne. Użycie do pozwala na związanie wielu kroków wejścia – wyjścia w jedną operację. Użycie do tworzy akcję wejścia – wyjścia, której typ jest taki sam jak typ ostatniej operacji. W związku z tym funkcja main ma sygnaturę main :: IO <sth> gdzie <sth> jest konkretnym typem. Haskell – Wejście/Wyjście Zapis: imię = "Moje imię to:" ++ getLine jest niepoprawny. Haskell – Wejście/Wyjście Operator >>= przekazuje wynik jednej operacji wejścia – wyjścia innej np.: getChar >>= putChar Jeśli wynik pierwszej operacji nie jest interesujący można użyć operatora >>. Operator return pozwala zwrócić wartość typu IO <sth>. Haskell – Wejście/Wyjście readln :: IO String readln = do c < getChar if c == '\n' then return [] else do cs ← readln return ( c:cs ) Haskell – Wejście/Wyjście getContetnts – zwraca zawartość standardowego wejścia. Możliwe jest użycie uchwytów do plików przy pomocy funkcji: hgetContents, hPutStr, hPutStrLn, hGetChar, hgetLine oraz: openFile, readFile, writeFile, appendFile, withFile.