En aquest tema, aplicarem tots els conceptes apresos al llarg del curs per construir una aplicació completa en Haskell. Aquest projecte servirà com a culminació del teu aprenentatge i et proporcionarà una experiència pràctica en el desenvolupament d'aplicacions reals amb Haskell.
Objectius del Projecte
- Aplicar els conceptes de programació funcional en un projecte real.
- Utilitzar el sistema de tipus de Haskell per garantir la seguretat i la correcció del codi.
- Implementar funcionalitats d'entrada i sortida (I/O).
- Gestionar errors i excepcions de manera robusta.
- Integrar amb bases de dades i altres serveis externs.
- Escriure proves per assegurar la qualitat del codi.
Descripció del Projecte
Construirem una aplicació de gestió de tasques (To-Do List) que permetrà als usuaris crear, llegir, actualitzar i eliminar tasques. L'aplicació tindrà una interfície de línia de comandes (CLI) i utilitzarà una base de dades SQLite per emmagatzemar les dades.
Requisits
- Haskell (GHC)
- Cabal o Stack (per gestionar les dependències)
- SQLite (per a la base de dades)
Estructura del Projecte
El projecte es dividirà en diversos mòduls per mantenir el codi organitzat i modular:
- Main.hs: Punt d'entrada de l'aplicació.
- Database.hs: Gestió de la base de dades.
- Task.hs: Definició del tipus de dades
Task
i funcions associades. - CLI.hs: Interfície de línia de comandes.
Pas 1: Configuració del Projecte
Primer, crea un nou projecte Haskell utilitzant Cabal o Stack.
Utilitzant Cabal
Utilitzant Stack
Pas 2: Definició del Tipus de Dades Task
Creem un nou fitxer src/Task.hs
per definir el tipus de dades Task
i les funcions associades.
module Task where data Task = Task { taskId :: Int , taskDescription :: String , taskCompleted :: Bool } deriving (Show, Eq) -- Funció per crear una nova tasca createTask :: Int -> String -> Task createTask id desc = Task id desc False -- Funció per marcar una tasca com a completada completeTask :: Task -> Task completeTask task = task { taskCompleted = True }
Pas 3: Gestió de la Base de Dades
Creem un nou fitxer src/Database.hs
per gestionar la base de dades SQLite.
module Database where import Database.SQLite.Simple import Task -- Funció per inicialitzar la base de dades initDB :: IO () initDB = do conn <- open "tasks.db" execute_ conn "CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY, description TEXT, completed BOOLEAN)" close conn -- Funció per afegir una tasca a la base de dades addTask :: Task -> IO () addTask task = do conn <- open "tasks.db" execute conn "INSERT INTO tasks (id, description, completed) VALUES (?, ?, ?)" (taskId task, taskDescription task, taskCompleted task) close conn -- Funció per obtenir totes les tasques getTasks :: IO [Task] getTasks = do conn <- open "tasks.db" tasks <- query_ conn "SELECT id, description, completed FROM tasks" :: IO [(Int, String, Bool)] close conn return $ map (\(id, desc, comp) -> Task id desc comp) tasks
Pas 4: Interfície de Línia de Comandes (CLI)
Creem un nou fitxer src/CLI.hs
per gestionar la interfície de línia de comandes.
module CLI where import System.Environment (getArgs) import Task import Database -- Funció principal de la CLI mainCLI :: IO () mainCLI = do args <- getArgs case args of ["init"] -> initDB ["add", desc] -> do tasks <- getTasks let newId = if null tasks then 1 else taskId (last tasks) + 1 let newTask = createTask newId desc addTask(newTask) putStrLn "Task added!" ["list"] -> do tasks <- getTasks mapM_ print tasks _ -> putStrLn "Unknown command"
Pas 5: Punt d'Entrada de l'Aplicació
Finalment, creem el fitxer app/Main.hs
com a punt d'entrada de l'aplicació.
Pas 6: Proves i Depuració
És important escriure proves per assegurar la qualitat del codi. Creem un fitxer test/Spec.hs
per a les proves.
module Main where import Test.Hspec import Task main :: IO () main = hspec $ do describe "Task" $ do it "creates a new task" $ do let task = createTask 1 "Test task" taskDescription task `shouldBe` "Test task" taskCompleted task `shouldBe` False it "completes a task" $ do let task = createTask 1 "Test task" let completedTask = completeTask task taskCompleted completedTask `shouldBe` True
Conclusió
En aquest projecte, hem construït una aplicació de gestió de tasques utilitzant Haskell. Hem aplicat conceptes de programació funcional, gestió de bases de dades, i hem creat una interfície de línia de comandes. Aquest projecte t'hauria de proporcionar una bona base per desenvolupar aplicacions més complexes en Haskell.
Exercicis Pràctics
- Afegir Funcionalitat de Supressió de Tasques: Implementa una funció per eliminar tasques de la base de dades.
- Marcar Tasques com a Completes: Implementa una funció per marcar tasques com a completes des de la CLI.
- Millorar la Interfície de Línia de Comandes: Afegeix més opcions i millora la usabilitat de la CLI.
Solucions als Exercicis
- Afegir Funcionalitat de Supressió de Tasques
-- Afegeix aquesta funció a Database.hs deleteTask :: Int -> IO () deleteTask id = do conn <- open "tasks.db" execute conn "DELETE FROM tasks WHERE id = ?" (Only id) close conn -- Afegeix aquesta opció a CLI.hs case args of ["delete", idStr] -> do let id = read idStr :: Int deleteTask id putStrLn "Task deleted!"
- Marcar Tasques com a Completes
-- Afegeix aquesta funció a Database.hs completeTaskInDB :: Int -> IO () completeTaskInDB id = do conn <- open "tasks.db" execute conn "UPDATE tasks SET completed = 1 WHERE id = ?" (Only id) close conn -- Afegeix aquesta opció a CLI.hs case args of ["complete", idStr] -> do let id = read idStr :: Int completeTaskInDB id putStrLn "Task completed!"
- Millorar la Interfície de Línia de Comandes
-- Afegeix més opcions i millora la usabilitat de la CLI case args of ["init"] -> initDB ["add", desc] -> do tasks <- getTasks let newId = if null tasks then 1 else taskId (last tasks) + 1 let newTask = createTask newId desc addTask(newTask) putStrLn "Task added!" ["list"] -> do tasks <- getTasks mapM_ print tasks ["delete", idStr] -> do let id = read idStr :: Int deleteTask id putStrLn "Task deleted!" ["complete", idStr] -> do let id = read idStr :: Int completeTaskInDB id putStrLn "Task completed!" _ -> putStrLn "Unknown command. Available commands: init, add, list, delete, complete"
Amb aquests exercicis i solucions, hauràs millorat la funcionalitat de la teva aplicació i hauràs adquirit més experiència en el desenvolupament amb Haskell.