:PROPERTIES: :ID: d7d1398b-5b09-4eef-a193-3b2a9ca0abf7 :END: #+title: Haskell #+filetags: programmation * Démarrer un projet ** Nix [[file:Environnement%20Haskell%20avec%20Nix.md][Environnement Haskell avec Nix]] ** Script en un seul fichier (cabal) =cabal run= sur le script suivant (ou chmod +x) #+begin_src haskell #!/usr/bin/env cabal {- cabal: build-depends: base , turtle -} {-# LANGUAGE OverloadedStrings #-} import Turtle main = echo "Hello World!" #+end_src ** Script en un seul fichier (stack) `stack run` sur le script suivant (ou chmod +x) #+begin_src haskell -- stack --resolver lts-6.25 script --package turtle {-# LANGUAGE OverloadedStrings #-} import Turtle main = echo "Hello World!" #+end_src ** Avec stack #+begin_src sh stack script simple.hs --resolver lts-14.18 #+end_src * Librairies ** Data analysis : Frames :PROPERTIES: :CUSTOM_ID: data-analysis-frames :END: *** Minimal example :PROPERTIES: :CUSTOM_ID: minimal-example :END: #+begin_src haskell {-# LANGUAGE DataKinds, FlexibleContexts, QuasiQuotes, TemplateHaskell, TypeApplications, TypeApplications#-} import Lens.Micro.Extras import qualified Data.Foldable as F import Frames -- Data set from http://vincentarelbundock.github.io/Rdatasets/datasets.html tableTypes "TLeft" "data/prestige.csv" tableTypes "TRight" "data/test.csv" loadLeft :: IO (Frame TLeft) loadLeft = inCoreAoS (readTable "data/prestige.csv") loadRight :: IO (Frame TRight) loadRight = inCoreAoS (readTable "data/test.csv") main = do l <- loadLeft r <- loadRight -- Native way of showing a row print $ frameRow l 1 -- List-style way of showing a row print $ take 2 $ F.toList l let t = innerJoin @'[ColType] l r print $ frameRow t 1 #+end_src *** Lire des fichiers tsv :PROPERTIES: :CUSTOM_ID: lire-des-fichiers-tsv :END: #+begin_example {-# LANGUAGE DataKinds, FlexibleContexts, QuasiQuotes, TemplateHaskell, TypeApplications, OverloadedStrings #-} module Main where import qualified Control.Foldl as L import qualified Data.Foldable as F import Frames import Frames.TH (rowGen, RowGen(..)) tableTypes' (rowGen "ml-100k/u.user") { rowTypeName = "U2" , columnNames = ["index", "age", "sex", "job", "id"] , separator = "\t"} loadRows :: IO (Frame U2) loadRows = inCoreAoS (readTableOpt u2Parser "ml-100k/u.user") main = do ms <- loadRows mapM_ print (F.toList ms) #+end_example Il faut rajouter le parser "u2Parser" (cf [[https://github.com/acowley/Frames/issues/178]]) ** SQL: persistent :PROPERTIES: :CUSTOM_ID: sql-persistent :END: Pour se connecter à une base existante, il faut connaître le type de colonnes (avec `.schema`). Puis définir un type. *Important* on n'a pas besoin de remplir les types de toutes les colonnes. Seulement celles qui nous intéressent !! Exemple: pour org-roam, on regarde la table files #+begin_src sql sqlite> .schema files CREATE TABLE files (file UNIQUE PRIMARY KEY, title , hash NOT NULL, atime NOT NULL, mtime NOT NULL); #+end_src #+begin_src haskell {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE DataKinds #-} import qualified Database.Persist.TH as PTH import Database.Persist (Entity(..)) import Database.Persist.Sql (toSqlKey) import Data.Text import Database.Persist.Sqlite import Control.Monad.IO.Class import Control.Monad.Logger PTH.share [PTH.mkPersist PTH.sqlSettings, PTH.mkMigrate "migrateAll"] [PTH.persistLowerCase| File sql=files file Text Primary file title Text hask Text atime Text mtime Text deriving Show |] path = "/home/alex/.emacs.d/.local/cache/org-roam.db" main :: IO () main = runSqlite path $ do test <- selectList [] [LimitTo 1] liftIO $ print (test :: [Entity File]) #+end_src Note: il faut définir une autre clé primaire, voir [[https://hackage.haskell.org/package/persistent-2.14.5.0/docs/Database-Persist-Quasi.html]] #+begin_src haskell file Text Primary file #+end_src Si la clé primaire est une chaîne de caractères #+begin_src haskell Id Text sql=id #+end_src Pour chercher par clé directement (toujours org-roam avec une clé en chaine de caractère) #+begin_src haskell test <- get (NodeKey "1") return $ (test :: Maybe Node) #+end_src ** Pandoc :PROPERTIES: :CUSTOM_ID: pandoc :END: Voir [[file:Pandoc.md][Pandoc]] pour un exemple de customisation # Éditeur ## Emacs Utiliser haskell-compile Si on utilise haskell-proces-cabal-build (default =C-c c-c=), il ne trouve pas le fichier .cabal associé quand on éditer le code source * Éditeur ** Emacs :PROPERTIES: :ID: 2e84138f-7559-4933-8e8b-345c5a03fe8b :END: Mode mal documenté (avec lsp) C-c C-l pour charger code dans ghci C-c C-z si on perd le popup