Programmation fonctionnelle est le paradigme de la programmation où vous programmez sans utiliser les variables. Les fonctions appellent d’autres fonctions avec le variable passant entre.
Ce paradigme autorise les constantes et le transtypage fort. Il est également caractérisé par évaluation paresseuse: les expressions ne sont évaluées que lorsqu'un résultat est requis.
Haskell est un langage de programmation fonctionnel qui existe depuis 1987. Il est soutenu par une grande communauté de programmeurs et est disponible sur les plateformes Mac, Windows et Linux..
Dans ce tutoriel, je vais créer un Alfred bibliothèque pour aider à rendre les flux de travail dans Haskell. Ensuite, je vais créer un flux de travail en utilisant cette bibliothèque.
Dans ce tutoriel, je présume que vous connaissez déjà l'écriture de flux de travail dans Alfred. Si non, s'il vous plaît consulter ces tutoriels:
Depuis une description complète de Haskell la programmation dépasse le cadre de ce tutoriel, vous pouvez lire Une introduction de Gentile à Haskell: Version 98. J'ai personnellement appris Haskell du livre gratuit Écrivez-vous un programme en 48 heures. J'aime apprendre de nouvelles langues en écrivant un programme utile.
Utiliser Haskell sur le Mac, il faut d'abord XCode installée. Ceci est une installation gratuite de la Mac App Store. Une fois téléchargé, lancez XCode et ouvrez le Panneau de préférences.
dans le Panneau de préférences, clique sur le Emplacements article. En bas, assurez-vous que le Outils de ligne de commande pointe vers votre version de XCode. Il vous demandera un identifiant d'utilisateur. Une fois donnés, les outils en ligne de commande sont configurés pour utiliser.
Avec XCode installé et configuré, téléchargez le Haskell compilateur et fichiers de support de Haskell pour Mac OS X.
Après avoir décompressé le fichier, déplacez le ghc-7.10.1.app dans le dossier Applications (7.10.1 était la dernière version puisque j'ai écrit ce tutoriel).
Le programme d’installation affiche le code à ajouter à votre ~ / .bash_profile fichier et votre ~ / .zshrc fichier (si vous utilisez Z-shell). Une fois que vous avez ajouté ce code à vos fichiers shell, cliquez sur le bouton Actualiser la liste de contrôle. Toutes les cases à cocher doivent être vertes. Vous êtes maintenant prêt à créer Haskell programmes.
Haskell a un gestionnaire de paquets similaire à NodeJSde npm. Il est cabale. Avec cabale vous pouvez télécharger et installer de nombreuses bibliothèques tierces que d'autres ont écrites Haskel. Pour le Bibliothèque Alfred Haskell, vous devez installer le TagSoup bibliothèque. Cela aide à récupérer le bundleid du Alfred flux de travail. Sur la ligne de commande, tapez:
cabale installer des tags
Maintenant, créez un nouveau fichier appelé Alfred.hs
. Tout Haskell les fichiers de programme se terminent par le .hs
extension. Dans ce fichier, commencez à placer ce code:
module Alfred (début, fin, addItem, addItemBasic, getAlfredDataFileContents, putAlfredDataFileContents, getAlfredCacheFileContents, putAlfredCacheFileContents) où importer System.Process importer System.Directory importer System.Environment importer Text.HTML.TagSoup
le module Alfred (
commence un module. Tout Haskell les fichiers sont des modules. Dans la parenthèse définit les fonctions que ce module rendra disponibles. Tout Haskell les fonctions commencent par une lettre minuscule. Si le module doit être le programme principal, il doit avoir un principale
une fonction. Puisqu'il s'agit d'une bibliothèque, il ne reste que des déclarations de fonctions et de constantes.
Après avoir déclaré le module
et ce qu’elle exporte, vous écrivez la liste des différentes bibliothèques utilisées. Cette bibliothèque utilise trois bibliothèques: System.Process
, System.Directory
, System.Environment
, et le Text.HTML.TagSoup
que nous avons téléchargé avec cabale
.
cacheDirBasic :: String cacheDirBasic = "/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data /" dataDirBasic :: String dataDirBasic = "/ Bibliothèque / Application Support / Alfred 2 / Données de flux de travail /" begin :: String begin = ""end :: String end =" "
Ensuite, je définis trois constantes. La première ligne est la déclaration de type avec la définition réelle en dessous. le ::
symbol déclare que les éléments suivants sont des déclarations de type. Ici, nous définissons les constantes comme Chaîne
type.
addItem :: String -> String -> String -> String -> String -> String -> String -> String addItem a b c d e f g = "- "
"++ e ++" "++ f ++" "++ g ++"
le ajouter un item
la fonction prend sept Chaîne
entrées et crée l'élément XML Chaîne
en sortie. Notez que la déclaration de type ressemble à huit Chaîne
types séparés par ->
. le ->
Le symbole indique le type suivant. Les sept premiers types sont l’entrée, le dernier étant la valeur de retour. Toutes les fonctions dans Haskell avoir une valeur de retour.
addItemBasic :: String -> String -> String -> String -> String addItemBasic a b c d = addItem a b "oui" "" c d "icon.png"
le addItemBasic
utilise le ajouter un item
fonction pour créer un élément XML avec trois des entrées définies sur une valeur par défaut.
getBundleID :: IO (String) getBundleID = faire les balises <- fmap parseTags $ readFile "info.plist" let id = fromTagText $ dropWhile (~/= "") (partitions (~ ==") ") tags !! 0) !! 1 ID de retour
le getBundleID
obtenir l'ID du paquet Alfred Workflow à partir du info.plist fichier dans le répertoire de workflow. Ce fichier est un texte brut plist
. Puisqu'il s'agit d'un type de format XML ou HTML, TextSoup La bibliothèque fonctionne vraiment bien pour le lire et le décoder. Il s’agit d’une fonction monade (en bref, une fonction qui interagit avec l’élément en dehors du programme. Par exemple: fichiers, interface graphique, etc.) Pour en savoir plus sur les monades dans le tutoriel monades. Toute fonction avec le type de retour de IO ()
est une monade pour les fonctions d'entrée ou de sortie.
Ici, le style de programmation fonctionnel se décompose en une liste d'éléments. le faire
mot-clé dit, "faites ce qui suit dans l'ordre".
La première ligne après le faire
lit dans le info.plist fichier et analysé les balises en utilisant parseTags
du TextSoup bibliothèque. La deuxième ligne trouve la première dict
tag et laisse tomber tout jusqu'à ce que le chaîne
étiquette. Il extrait ensuite le contenu des balises et le place dans la constante de transition identifiant
. identifiant
est une constante car sa valeur ne peut pas changer. Puisque toutes Alfred info.plist les fichiers ont exactement la même disposition, je n'ai pas besoin de tester la clé pour être correct. le identifiant
la valeur est alors retournée.
getAlfredDataFileContents :: String -> IO (String) getAlfredDataFileContents nomFichier = do h <- getHomeDirectory id <- getBundleID let fPath = h ++ dataDirBasic ++ id ++ "/" ++ fileName fExist <- doesFileExist fPath if fExist then do contents <- readFile fPath return contents else return ""
La fonction suivante monade récupère le contenu d’un fichier qui se trouve dans Répertoire de données Alfred pour le flux de travail et le renvoie à la fonction appelante. La fonction obtient d’abord le répertoire de base de l’utilisateur, obtient l’ID du paquet, crée un chemin vers le Répertoire de données Alfred pour le flux de travail et renvoie le contenu de ce fichier s'il existe. Sinon, la fonction retourne une chaîne vide.
putAlfredDataFileContents :: String -> String -> IO () putAlfredDataFileContents nomFichier dataStr = do h <- getHomeDirectory id <- getBundleID writeFile (h ++ dataDirBasic ++ id ++ "/" ++ fileName) dataStr
La prochaine monade fait exactement le contraire. Il faut un nom de fichier et les données à stocker dans ce fichier. Étant donné que le contenu sera placé dans le fichier nommé, qu'il existe ou non, l'existence du fichier n'a pas besoin d'être déterminée.
getAlfredCacheFileContents :: String -> IO (String) getAlfredCacheFileContents nom_fichier = faire h <- getHomeDirectory id <- getBundleID let fPath = h ++ cacheDirBasic ++ id ++ "/" ++ fileName fExist <- doesFileExist fPath if fExist then do contents <- readFile fPath return contents else return "" putAlfredCacheFileContents :: String -> String -> IO () putAlfredCacheFileContents fileName dataStr = do h <- getHomeDirectory id <- getBundleID writeFile (h ++ cacheDirBasic ++ id ++ "/" ++ fileName) dataStr
Les deux dernières fonctions de monade dans la bibliothèque lisent et écrivent des fichiers dans le répertoire. Alfred Cache répertoire pour le workflow.
Avec la bibliothèque créée, il s’agit d’écrire un workflow. Créer un nouveau flux de travail dans Alfred appelé Haskell Text Converter comme montré:
le Filtre de script devrait ressembler à ceci:
Maintenant, cliquez sur Ouvrir le dossier de workflow. Cela ouvre le dossier du flux de travail dans le Finder. Mettez une copie du Alfred.hs en elle. Maintenant, créez le fichier cas.hs et placez ce code là:
module Principal où importer System.Environment import System.Exit import Data.List import Data.Char import qualifié Data.ByteString import qualifié Alfred comme AL - - Tous les mots devant être en majuscule uniquement. - upperWordsList = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "HTML", " CSS "," AT & T "," PHP "," UI "] - - Tous les mots qui doivent être en minuscules uniquement. - lowerWordsList = ["to", "an", "et", "at", "comme", "mais", "par", "pour", "si", "dans", "sur", " ou "," est "," avec "," un "," le "," de "," vs "," vs. "," via "," via "," en "] toWordLower :: String -> Chaîne toWordLower a = map toLower a toWordUpper :: String -> String toWordUpper a = map toUpper a toFirstLetterUpper :: [Char] -> [Char] toFirstLetterUpper [] = [] àFirstLetterUpper (a: []) = àUpper un: [] toFirstLetterUpper (a: ax) = toUpper a: toWordLower ax toFirstLetterUpperOnly :: [Char] -> [Char] toFirstLetterUpperOnly [] = [] àFirstLetterUpperOnly (a: []) = àUpper a: [] àFirstLetterUpperOnly ax: toFirstLetterLowerOnly :: [Char] -> [Char] toFirstLetterLowerOnly [] = [] toFirstLetterLowerOnly (a: []) = toPlower a: [] toFirstLetterLowerOnly (a: ax) = toPlower a: ax toTitleCase :: [Char] -> [Char] toTitleCase [] = [] toTitleCase a | elem (toWordUpper a) upperWordsList = toWordUpper a | elem (toWordLower a) lowerWordsList = toWordLower a | sinon = toFirstLetterUpper un processLine :: String -> (String -> String) -> [String] -> String processLine "" f [a] = concatMap f $ mots un processusLine cf [a] = init $ concatMap (++ c ) $ map f $ mots a procLower :: [Chaîne] -> Chaîne procLower [a] = toWordPlus a procUpper :: [Chaîne] -> Chaîne procUpper [a] = àWordUpper une procSentence :: [Chaîne] -> Chaîne procSentence [ a] = toFirstLetterUpper un procTitle :: [String] -> String procTitle a = toFirstLetterUpperOnly $ processLine "" toTitleCase un procCamel :: [String] -> String procCamel a = toFirstLetterLowerOnly $ processLine "" à un article procSlash > String procSlash a = processLine "/" toWordLower a procPascal :: [String] -> String procPascal a = processLine "" toFirstLetterUpper un procCobra :: [String] -> String procCobra a = processLine "_" toFirstLetterUpper un procDot :: [ String] -> String procDot a = processLine "." toWordLower un procDash :: [String] -> String procDash un = processLine "-" toWordLower un addItemCase :: String -> String -> String addItemCase abc = AL.addItemBasic abbc alfredScript :: [String] -> IO ( ) alfredScript [] = putStr "" alfredScript [caseStr] = do putStr AL.begin putStr (addItemCase "HTCTitle" (procTitle [casStr]) "Title Case") putStr (addItemCase "HTCLower" (procLower [caseStr]) "Minuscule ") putStr (addItemCase" HTCUpper "(procUpper [caseStr])" Majuscule ") putStr (addItemCase" HTCSentenccaseStr "(procSentence [caseStr])" putStr (addItemCase "HTCSentenccaseStr" (procSentence [caseStr]) "putStr (addItemCase" HTCamel " Case ") putStr (addItemCase" HTCSlash "(procSlash [caseStr])" Slash Case ") putStr (addItemCase" HTCPascal "(procPascal [caseStr])" Pascal Case ") putStr (addItemCase" HTCPascal "(procPascal [caseStr])" putStr (addItemCase "HTCobra" Cobra Case ") putStr (addItemCase" HTCDot "(procDot [casStr])" Dot Case ") putStr (addItemCase" HTCDash "(procDash [casStr])" Dash Case ") putStr AL .end main = do args <- getArgs alfredScript args
Ce code prend une chaîne à partir de la ligne de commande et génère le Filtre de script Alfred format XML avec neuf types de cas différents.
le cas de titre Le format utilise deux listes de mots pour faire toutes les majuscules ou toutes les minuscules. La fonction réelle toTitleCase
utilise des conditions pour voir si le mot est dans la liste des majuscules ou des minuscules. Si c'est le cas, faites-le ainsi. Sinon, il suffit de faire la première lettre en majuscule.
La fonction d'assistance processLine
prend une chaîne et une fonction, applique la fonction à toutes les entrées d'une liste de chaînes, ajoute la chaîne à chaque entrée et concatène les chaînes résultantes. Cette fonction traite de nombreuses conversions de cas sur une chaîne complète..
J'ai créé une fonction d'assistance addItemCase
qui fait double emploi se disputer
valeur à la Titre
valeur dans le addItemBasic
fonctionner dans le Alfred bibliothèque. La programmation fonctionnelle consiste à créer une fonction de fonctions qui font le travail sans varialbles!
La plupart des autres fonctions sont assez faciles à comprendre. Je vous donne la tâche d'étudier cela afin que vous puissiez faire votre propre Haskell flux de travail.
Pour compiler le programme, tapez ceci sur la ligne de commande dans le répertoire du workflow:
ghc cases.hs
Une fois le programme compilé et le flux de travail créé, vous pouvez maintenant l’utiliser pour convertir des chaînes. dans le Alfred invite, type ht: conv c'est un test
.
La photo ci-dessus montre le résultat. Sélectionnez celui que vous voulez et il est placé dans le presse-papiers. Le fichier de téléchargement contient une copie de ce flux de travail. J'ai aussi une version étendue disponible sur Haskell Text Converter sur Packal.org.
En outre, je suis constamment en train d’améliorer et d’ajouter Bibliothèque d'Alfred à Haskell. Vous pouvez toujours obtenir la dernière version à Alfred Library dans le référentiel GitHub de Haskell.
Dans ce tutoriel, je vous ai montré comment installer Haskell sur votre Mac, créez un Alfred bibliothèque pour aider à créer de nouveaux flux de travail, et fait un exemple de flux de travail avec la bibliothèque. Maintenant, à votre tour de faire de grands Alfred flux de travail. S'il vous plaît partagez-les dans les commentaires ci-dessous.