#!/usr/bin/env runghc -- https://hackage.haskell.org/package/base/docs/Data-List.html import Data.List ( lines, unlines, words ) -- https://hackage.haskell.org/package/base/docs/Data-Char.html import Data.Char ( chr, ord ) -- https://hackage.haskell.org/package/base/docs/Data-Maybe.html import Data.Maybe ( fromJust ) -- | program začne spuštěním funkce main main :: IO () main = do -- přečteme soubor content <- readFile "zadani02.aut" -- soubor rozdělíme na řádky, ty zpracujeme pomocí process -- na řákdy výstupu, které opět spojíme a zobrazíme na obrazovku putStrLn (unlines (process (lines content))) -- | tato funkce rozdělí vstup a automat a slova, následně vytvoří automat -- pomocí 'mkaut' a spustí jej na každém slově a do výsledného seznamu dá -- příslušný řetězec "0" nebo "1" za každé vstupní slovo process :: [String] -> [String] process lines = map (show10 . runAutomaton automaton) words where -- popis automatu je vše před volným řádkem automatonDesc = takeWhile (/= "") lines -- slova jsou vše za volným řádkem (volný řádek vynecháme) words = tail (dropWhile (/= "") lines) -- získáme automat automaton = mkaut automatonDesc -- zobrazení podle požadovaného výstupu show10 True = "1" show10 False = "0" -- | Automat se skládá z iniciálního stavu, seznamu akceptujících stavů a z -- tabulky přechodové funkce: vnější seznam je seznam řádků tabulky (pro -- každý stav postupně jeden řádek), vnitřní seznam představuje přechody -- pod jednotlivými písmeny -- -- type značí typový alias type Automaton = (Int, [Int], [[Int]]) -- | spustí automat na daném vstupu, vrátí 'True' pokud akceptoval runAutomaton :: Automaton -> String -> Bool runAutomaton (init, acc, delta) xs = run init xs where -- použijeme pomocnou funkci, která postupně zpracovává slova vstupu -- skončili jsme, patří aktuální stav mezi akceptující? run st [] = st `elem` acc -- výpočetní krok: podle stavu vyhledáme příslušný řádek přechodové tabulky -- podle písmene v měm pak najdeme odpovídající cílový stav run st (x:xs) = run ((delta !! (st - 1)) !! (ord x - ord 'a')) xs -- automat vytvoříme tak, že z 3. řádku vezmeme číslo iniciálního stavu -- na čtvrtém řádku vezmeme čísla akceptujících stavů (rozdělíme je pomocí -- funkce 'words') a tabulku získáma z řádků 6 až po konec (opět každý -- řádek rozdělíme podle mezer). Zbylé řádky nepotřebujeme, obsahují -- jen počty stavů/písmen. -- -- Funkce 'read' parsuje hodnotu z řetězce, zde na 'Int' (viz typ 'Automaton') mkaut :: [String] -> Automaton mkaut lines = (read (lines !! 2), map read (words (lines !! 4)), table) where table = map (map read . words) (drop 5 lines)