J'ai lu le livre Learn You a Haskell jusqu'au point où ils présentent des monades et des trucs comme Just a. Celles-ci sont tellement contre-intuitives pour moi que j'ai juste envie d'arrêter d'essayer de l'apprendre.
Mais je veux vraiment essayer.
Je me demande si je peux au moins éviter les concepts avancés pendant un certain temps et commencer à utiliser les autres parties du langage pour effectuer de nombreuses tâches pratiques avec les parties les plus élémentaires de Haskell, à savoir les fonctions, les E / S standard, la gestion des fichiers, interface de base de données et similaires.
Est-ce une approche raisonnable pour apprendre à utiliser Haskell?
Réponses:
Distinguons d'abord entre l'apprentissage des concepts abstraits et l'apprentissage d'exemples spécifiques d'entre eux.
Vous n'irez pas très loin en ignorant tous les exemples spécifiques, pour la simple raison qu'ils sont tout à fait omniprésents. En fait, les abstractions existent en grande partie parce qu'elles unifient les choses que vous feriez de toute façon avec les exemples spécifiques.
Les abstractions elles-mêmes, en revanche, sont certainement utiles , mais elles ne sont pas immédiatement nécessaires. Vous pouvez obtenir assez loin en ignorant complètement les abstractions et en utilisant directement les différents types. Vous voudrez éventuellement les comprendre, mais vous pourrez toujours y revenir plus tard. En fait, je peux presque garantir que si vous faites cela, lorsque vous y reviendrez, vous vous claquerez le front et vous vous demanderez pourquoi vous avez passé tout ce temps à faire les choses à la dure au lieu d'utiliser les outils polyvalents pratiques.
Prenons
Maybe a
l'exemple. C'est juste un type de données:C'est tout sauf auto-documenté; c'est une valeur facultative. Soit vous avez "juste" quelque chose de type
a
, soit vous n'avez rien. Supposons que vous ayez une fonction de recherche quelconque, qui revientMaybe String
à représenter la recherche d'uneString
valeur qui peut ne pas être présente. Donc, votre motif correspond à la valeur pour voir de quelle valeur il s'agit:C'est tout!
Vraiment, vous n'avez besoin de rien d'autre. Pas de
Functor
s ouMonad
s ou autre chose. Ceux-ci expriment des façons courantes d'utiliser desMaybe a
valeurs ... mais ce ne sont que des idiomes, des "modèles de conception", peu importe comment vous pouvez l'appeler.Le seul endroit où vous ne pouvez vraiment pas l'éviter complètement est
IO
, mais c'est une mystérieuse boîte noire de toute façon, donc cela ne vaut pas la peine d'essayer de comprendre ce que cela signifie en tant queMonad
ou quoi que ce soit.En fait, voici une feuille de triche pour tout ce que vous devez vraiment savoir
IO
pour l'instant:Si quelque chose a un type
IO a
, cela signifie que c'est une procédure qui fait quelque chose et crache unea
valeur.Lorsque vous avez un bloc de code utilisant la
do
notation, écrivez quelque chose comme ceci:... signifie exécuter la procédure à droite de
<-
et affecter le résultat au nom à gauche.Alors que si vous avez quelque chose comme ça:
... cela signifie affecter la valeur de l'expression simple (pas une procédure) à droite de la
=
au nom à gauche.Si vous y mettez quelque chose sans assigner de valeur, comme ceci:
... cela signifie exécuter une procédure et ignorer tout ce qu'elle retourne. Certaines procédures ont le type
IO ()
- le()
type est une sorte d'espace réservé qui ne dit rien, ce qui signifie simplement que la procédure fait quelque chose et ne renvoie pas de valeur. Un peu comme unevoid
fonction dans d'autres langues.L'exécution de la même procédure plusieurs fois peut donner des résultats différents; c'est un peu l'idée. C'est pourquoi il n'y a aucun moyen de "supprimer"
IO
une valeur, car quelque choseIO
n'est pas une valeur, c'est une procédure pour obtenir une valeur.La dernière ligne d'un
do
bloc doit être une procédure simple sans affectation, où la valeur de retour de cette procédure devient la valeur de retour pour le bloc entier. Si vous souhaitez que la valeur de retour utilise une valeur déjà affectée, lareturn
fonction prend une valeur simple et vous donne une procédure sans opération qui renvoie cette valeur.À part cela, il n'y a rien de spécial
IO
; ces procédures sont en fait des valeurs simples et vous pouvez les transmettre et les combiner de différentes manières. Ce n'est que lorsqu'ils sont exécutés dans undo
bloc appelé quelque partmain
qu'ils font n'importe quoi.Donc, dans quelque chose comme ce programme d'exemple stéréotypé totalement ennuyeux:
... vous pouvez le lire comme un programme impératif. Nous définissons une procédure nommée
hello
. Une fois exécuté, il exécute d'abord une procédure pour imprimer un message vous demandant votre nom; ensuite, il exécute une procédure qui lit une ligne d'entrée et affecte le résultat àname
; puis il attribue une expression au nommsg
; puis il imprime le message; puis il renvoie le nom de l'utilisateur comme résultat de l'ensemble du bloc. Puisquename
est unString
, cela signifie quehello
c'est une procédure qui renvoie unString
, donc il a du typeIO String
. Et maintenant, vous pouvez exécuter cette procédure ailleurs, tout comme elle s'exécutegetLine
.Pfff, monades. Qui en a besoin?
la source
Ils sont essentiels. Sans eux, il est trop facile d'utiliser Haskell comme un autre langage impératif, et bien que Simon Peyton Jones ait appelé Haskell, "le meilleur langage de programmation impératif du monde", vous manquez toujours la meilleure partie.
Les monades, les transformées de monade, les monoïdes, les foncteurs, les foncteurs applicatifs, les foncteurs contraires, les flèches, les catégories, etc., sont des modèles de conception. Une fois que vous avez intégré la chose spécifique que vous créez dans l'une d'elles, vous pouvez utiliser une énorme richesse de fonctions écrites de manière abstraite. Ces classes de types ne sont pas simplement là pour vous dérouter, elles sont là pour vous faciliter la vie et vous rendre plus productif. Ils sont, à mon avis, la principale raison de la concision du bon code Haskell.
la source
Est-ce strictement nécessaire si vous voulez simplement faire fonctionner quelque chose? Non.
Est-ce nécessaire si vous voulez écrire de beaux programmes Haskell idiomatiques? Absolument.
Lors de la programmation dans Haskell, il est utile de garder à l'esprit deux choses:
Le système de typage est là pour vous aider. Si vous composez votre programme à partir de code très polymorphe et lourd de classes, vous pouvez très souvent vous retrouver dans une situation merveilleuse où le type de fonction que vous souhaitez vous guidera vers la (une seule!) Implémentation correcte .
Les différentes bibliothèques disponibles ont été développées en utilisant le principe # 1.
Donc, lorsque j'écris un programme en Haskell, je commence par écrire les types. Ensuite, je recommence et j'écris quelques types plus généraux (et s'ils peuvent être des instances de classes de caractères existantes, tant mieux). Ensuite, j'écris quelques fonctions qui m'obtiennent des valeurs des types que je veux. (Ensuite, je joue avec eux
ghci
et j'écris peut-être des tests QuickCheck.) Et enfin, je colle tout cela ensemblemain
.Il est possible d'écrire Haskell laid qui fait juste fonctionner quelque chose. Mais il y a tellement plus à apprendre une fois que vous avez atteint ce stade.
Bonne chance!
la source