To jest stara wersja strony!
Interakcja z użytkownikiem i IO
Kompilacja programów i monada IO
Programy w języku Haskell można kompilowac do postaci uruchamialnej, niewymagajacej interpretera.
Polcenie do kompilacji:
ghc -o executable_name source_file.hs
Kod, który ma się wykonać po uruchomieniu programu wrzucamy do funkcji main:
main :: IO ()
main = putStrLn "Hello, World!"
I kompilacja:
ghc -o hello hello.hs
./hello
Zwróć uwagę na nagłówek funkcji main, która jest typu IO i zwraca () – coś na wzór void.
IO to specjalna wbudowana monada (podobnie jak Maybe)
Funkcja main jest tak naprawdę akcją IO, czyli komponentem programu zintegrowanym ze światem zewnętrznym, który może potencjalnie mieć wpływ na zmianę stanu tego świata zewnętrznego.
Analogicznie funkcja wczytująca napis z klawiatury, będzie akcją zdefiniowaną jako:
getLine' :: IO String
Czyli, jest akcją typu IO i zwraca String.
Interakcja z użytkownikiem
Przykład najprostszej interakcji z użytkownikiem:
main = do
putStrLn "Hello, what's your name?"
name <- getLine
putStrLn $ "Hello " ++ name ++ " good to see you!"
Spotykamy tutaj nową rzecz: do. Nie jest to jednak żaden nowy operator, tylko syntaktyczny sugar dla łączenia akcji w ciąg o ustalonej kolejności przy pomocy operatora `»=` i `»`
Uwaga Każda z linii w bloku do musi być IO akcją.
Na przykład alternatywnym zapisem dla powyższego z wykorzystaniem operatorów `»` i `»=` jest kod poniżej:
main = putStrLn "Hello, what's your name?" >> ( getLine >>= (\ name -> putStrLn $ "Hello " ++ name ++ " good to see you!"))
Uwaga na return
Spójrz na kod poniżej i zastanów się, co powinno się wydarzyć.
Następwnie skompiluj, uruchom i zweryfikuj swoje podejrzenia.
main = do
putStrLn "Hello, what's your name?"
return ()
name <- getLine
putStrLn $ "Hello " ++ name ++ " good to see you!"
Polecenie return w bloku do nie kończy wcale wykonywania kodu i nie powoduje zwrócenia wartości na zewnątrz bloku.
Jest ono traktowane jak kolejna akcja, która w przypadku powyżej nie robi nic.
Pliki
Czytanie z plików pokazano na przykładzie poniżej (zakładajac, ze istnieje jakiś plik 'machine.txt', np:
- machine.txt
Welcome my son, welcome to the machine
Where have you been?
It's alright we know where you've been
You've been in the pipeline, filling in time
Provided with toys and 'scouting for boys'
You brought a guitar to punish your ma
And you didn't like school, and you
Know you're nobody's fool
So welcome to the machine
Welcome my son, welcome to the machine
What did you dream?
It's alright we told you what to dream
You dreamed of a big star
He played a mean guitar
He always ate in the Steak Bar
He loved to drive in his Jaguar
So welcome to the machine
import System.IO
main = do
handle <- openFile "machine.txt" ReadMode
contents <- hGetContents handle
putStr contents
hClose handle
Jak widzisz uzyskanie uchwytu do pliku odbywa się za pomocą funkcji `openFile`, o sygnaturze:
openFile :: FilePath -> IOMode -> IO Handle
Gdzie `FilePath` to po prostu datatype będący synonimem Stringa, IOMode to typ opisany jak poniżej:
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
Zwracana jest natomiast akcja IO będąca uchwytem do pliku.
Funkcja `hGetContents` realizuje lazy IO, czyli nie wczytuje całego pliku do pamięci, tylko czyta go kiedy jest to potrzebne.
Istnieje też wersja do realizowania lazy IO w terminalu (poczytaj o getContents).
W przypadku, jeśli chcemy wczytać całośc pliku do pamięci, bez lazy IO, możemy użyc `readFile`:
import System.IO
main = do
contents <- readFile "machine.txt"
putStr contents
Pisanie do pliku jest wykonywane w analogiczny sposób:
import System.IO
main = do
contents <- readFile "machine.txt"
writeFile "new_machine.txt" contents
Zadania
Napisz grę „Guess a number”, gdzie system losuje losową liczbę od 0-10, a użytkownik ma 3 próby odgadnięcia tej liczby, za każdym razem otrzymując podpowiedź, że wpisana liczba była mniejsza, lub większa od szukanej. Aby wygenerować losową liczbę, użyj:
import System.Random
main = do
num <- randomIO :: IO Int
print num
Napisz program odwracający i wyświetlający napis, który wcześniej został podany przez użytkownika. Program powinien wczytywać i odwracać stringi do czasu, aż użytkownik poda pustą linię.
Napisz program wczytujący plik i zapisujący jego zawartość w wersji CAPSLOCK
Napisz program czytający plik i zapisujący w osobnym pliku słowa, które nie występują w '/usr/share/dict/words'. Sprawdzeni nie powinno być case-sensitive.