web-dev-qa-db-fra.com

Haskell ou Standard ML pour les débutants?

Je vais enseigner un cours de division inférieure dans des structures discrètes. J'ai choisi le manuel Structures discrètes, logique et calculabilité en partie parce qu'il contient des exemples et des concepts propices à la mise en œuvre avec un langage de programmation fonctionnel. (Je pense aussi que c'est un bon manuel.)

Je veux un langage facile à comprendre FP pour illustrer les concepts DS et que les étudiants peuvent utiliser. La plupart des étudiants auront eu seulement un ou deux semestres de la programmation en Java, au mieux. Après avoir examiné Scheme, Erlang, Haskell, Ocaml et SML, je me suis installé sur Haskell ou Standard ML. Je penche vers Haskell pour les raisons décrites ci-dessous, mais j'aimerais l'opinion de ceux qui sont des programmeurs actifs dans l'un ou l'autre.

  • Haskell et SML ont tous deux une correspondance de motifs, ce qui rend la description d'un algorithme récursif un jeu d'enfant.
  • Haskell a des compréhensions de listes Nice qui correspondent bien à la façon dont ces listes sont exprimées mathématiquement.
  • Haskell a une évaluation paresseuse. Idéal pour construire des listes infinies en utilisant la technique de compréhension de liste.
  • SML dispose d'un interpréteur vraiment interactif dans lequel les fonctions peuvent être définies et utilisées. Dans Haskell, les fonctions doivent être définies dans un fichier séparé et compilées avant d'être utilisées dans le shell interactif.
  • SML donne une confirmation explicite de l'argument de fonction et des types de retour dans une syntaxe facile à comprendre. Par exemple: val foo = fn: int * int -> int. La syntaxe implicite de curry de Haskell est un peu plus obtuse, mais pas totalement étrangère. Par exemple: foo :: Int -> Int -> Int.
  • Haskell utilise par défaut des entiers de précision arbitraire. C'est une bibliothèque externe en SML/NJ. Et SML/NJ tronque la sortie à 70 caractères par défaut.
  • La syntaxe lambda de Haskell est subtile - elle utilise une seule barre oblique inverse. SML est plus explicite. Je ne sais pas si nous aurons jamais besoin de lambda dans cette classe.

Essentiellement, SML et Haskell sont à peu près équivalents. Je penche vers Haskell parce que j'aime les compréhensions de listes et les listes infinies dans Haskell. Mais je crains que le nombre important de symboles dans la syntaxe compacte de Haskell puisse causer des problèmes aux étudiants. D'après ce que j'ai rassemblé en lisant d'autres articles sur SO, Haskell n'est pas recommandé pour les débutants débutant avec FP. Mais nous n'allons pas construire des applications à part entière, juste essayer des algorithmes simples.

Qu'est-ce que tu penses?


Edit: Après avoir lu certaines de vos excellentes réponses, je devrais clarifier certains de mes points.

En SML, il n'y a pas de distinction syntaxique entre la définition d'une fonction dans l'interpréteur et sa définition dans un fichier externe. Disons que vous voulez écrire la fonction factorielle. Dans Haskell, vous pouvez mettre cette définition dans un fichier et la charger dans GHCi:

fac 0 = 1
fac n = n * fac (n-1)

Pour moi, c'est clair, succinct et correspond à la définition mathématique du livre. Mais si vous voulez écrire directement la fonction dans GHCi, vous devez utiliser une syntaxe différente:

let fac 0 = 1; fac n = n * fac (n-1)

Lorsque vous travaillez avec des interprètes interactifs, d'un point de vue pédagogique, c'est très, très pratique lorsque l'étudiant peut utiliser le même code à la fois dans un fichier et sur la ligne de commande.

Par "confirmation explicite de la fonction", je voulais dire que lors de la définition de la fonction, SML vous indique tout de suite le nom de la fonction, les types d'arguments et le type de retour. Dans Haskell, vous devez utiliser le :type, puis vous obtenez la notation curry quelque peu confuse.

Encore une chose cool à propos de Haskell - c'est une définition de fonction valide:

fac 0 = 1
fac (n+1) = (n+1) * fac n

Encore une fois, cela correspond à une définition qu'ils pourraient trouver dans le manuel. Je ne peux pas faire ça en SML!

75
Barry Brown

Tout comme j'aime Haskell, voici les raisons pour lesquelles je préférerais SML pour une classe en mathématiques et structures de données discrètes (et la plupart des autres classes pour débutants):

  • Les coûts de temps et d'espace des programmes Haskell peuvent être très difficiles à prévoir, même pour les experts. SML propose des moyens beaucoup plus limités de souffler la machine.

  • La syntaxe de la définition de fonction dans un interpréteur interactif est identique à la syntaxe utilisée dans un fichier, vous pouvez donc couper et coller.

  • Bien que la surcharge des opérateurs en SML soit totalement fausse, elle est également simple. Il va être difficile d'enseigner toute une classe à Haskell sans avoir à entrer dans des classes de type.

  • L'élève peut déboguer en utilisant print. (Bien que, comme le souligne un commentateur, il soit possible d'obtenir presque le même effet dans Haskell en utilisant Debug.Trace.trace.)

  • Des structures de données infinies époustouflent l'esprit des gens. Pour les débutants, il vaut mieux leur faire définir un type de flux complet avec des cellules ref et des thunks, afin qu'ils sachent comment cela fonctionne:

    datatype 'a thunk_contents = UNEVALUATED of unit -> 'a
                               | VALUE of 'a
    type 'a thunk = 'a thunk_contents ref
    val delay : (unit -> 'a) -> 'a thunk
    val force : 'a thunk -> 'a
    

    Maintenant, ce n'est plus magique, et vous pouvez aller d'ici aux streams (listes infinies).

  • La mise en page n'est pas aussi simple qu'en Python et peut être source de confusion.

Il y a deux endroits où Haskell a un avantage:

  • Dans le noyau Haskell, vous pouvez écrire la signature de type d'une fonction juste avant sa définition. Ceci est extrêmement utile pour les étudiants et autres débutants. Il n'y a tout simplement pas de bonne façon de gérer les signatures de type en SML.

  • Haskell a une meilleure syntaxe concrète. La syntaxe Haskell est une amélioration majeure par rapport à la syntaxe ML. J'ai écrit un brève note sur le moment d'utiliser des parenthèses dans un programme ML ; cela aide un peu.

Enfin, il y a une épée qui coupe dans les deux sens:

  • Le code Haskell est pur par défaut, il est donc peu probable que vos élèves tombent sur des constructions impures (monade IO, monade d'état) par accident. Mais du même coup, ils ne peuvent pas imprimer, et si vous voulez faire des E/S, vous devez expliquer au minimum do notation, et return est déroutant.

Sur un sujet connexe, voici quelques conseils pour la préparation de votre cours: ne négligez pas Structures de données purement fonctionnelles par Chris Okasaki. Même si vos élèves ne l'utilisent pas, vous voudrez certainement en avoir une copie.

85
Norman Ramsey

Nous enseignons Haskell aux premières années de notre université. Mes sentiments à ce sujet sont un peu mitigés. D'une part, enseigner Haskell aux premières années signifie qu'ils n'ont pas à désapprendre le style impératif. Haskell peut également produire du code très concis que les gens qui en avaient Java avant peuvent apprécier.

Certains problèmes que j'ai remarqués chez les élèves sont souvent les suivants:

  • La correspondance de motifs peut être un peu difficile au début. Les élèves ont d'abord éprouvé des difficultés à voir comment la construction de valeur et l'appariement de motifs sont liés. Ils ont également eu des problèmes pour distinguer les abstractions. Nos exercices comprenaient des fonctions d'écriture qui simplifient l'expression arithmétique et certains élèves ont eu du mal à voir la différence entre la représentation abstraite (par exemple, Const 1) et la représentation du méta-langage (1).

    De plus, si vos élèves sont censés écrire eux-mêmes des fonctions de traitement de liste, faites attention à la différence entre les modèles

    []
    [x]
    (x:xs)
    [x:xs]
    

    Selon la quantité de programmation fonctionnelle que vous souhaitez leur enseigner en cours de route, vous pouvez simplement leur donner quelques fonctions de bibliothèque et les laisser jouer avec.

  • Nous n'avons pas enseigné à nos étudiants les fonctions anonymes, nous leur avons simplement parlé des clauses where. Pour certaines tâches, c'était un peu bavard, mais fonctionnait bien sinon. Nous ne leur avons pas non plus parlé de demandes partielles; cela est probablement assez facile à expliquer dans Haskell (en raison de sa forme d'écriture), il pourrait donc être utile de leur montrer.

  • Ils ont rapidement découvert les compréhensions de liste et les ont préférées aux fonctions d'ordre supérieur comme filter, map, zipWith.

  • Je pense que nous avons manqué un peu de leur apprendre à les laisser guider leurs pensées par les types. Je ne suis pas sûr, cependant, si cela est utile aux débutants ou non.

  • Les messages d'erreur ne sont généralement pas très utiles aux débutants, ils peuvent parfois avoir besoin d'aide pour ces derniers. Je ne l'ai pas essayé moi-même, mais il existe un compilateur Haskell spécifiquement destiné aux nouveaux arrivants, principalement au moyen de meilleurs messages d'erreur: Helium

  • Pour les petits programmes, des choses comme d'éventuelles fuites d'espace n'étaient pas un problème.

Dans l'ensemble, Haskell est une bonne langue d'enseignement, mais il y a quelques écueils. Étant donné que les étudiants se sentent beaucoup plus à l'aise avec les listes de compréhension que les fonctions d'ordre supérieur, cela pourrait être l'argument dont vous avez besoin. Je ne sais pas combien de temps votre cours est ou combien de programmation vous voulez leur enseigner, mais prévoyez du temps pour leur enseigner les concepts de base - ils en auront besoin.

29
nominolo

BTW,

# SML dispose d'un interpréteur vraiment interactif dans lequel les fonctions peuvent être définies et utilisées. Dans Haskell, les fonctions doivent être définies dans un fichier séparé et compilées avant d'être utilisées dans le shell interactif.

Est inexact. Utilisez GHCi:

Prelude> let f x = x ^ 2
Prelude> f 7
49
Prelude> f 2
4

Il y a également de bonnes ressources pour Haskell dans l'éducation sur l'edu haskell.org. page, avec des expériences de différents enseignants. http://haskell.org/haskellwiki/Haskell_in_education

Enfin, vous pourrez leur enseigner le parallélisme multicœur juste pour le plaisir, si vous utilisez Haskell :-)

13
Don Stewart

De nombreuses universités enseignent Haskell comme premier langage fonctionnel ou même comme premier langage de programmation, donc je ne pense pas que ce sera un problème.

Ayant fait une partie de l'enseignement sur un de ces cours, je ne suis pas d'accord que les confusions possibles que vous identifiez sont aussi probables. Les sources les plus probables de confusion précoce sont les erreurs d'analyse causées par une mauvaise disposition et les messages mystérieux sur les classes de type lorsque les littéraux numériques sont utilisés de manière incorrecte.

Je suis également en désaccord avec toute suggestion selon laquelle Haskell n'est pas recommandé pour les débutants débutant avec la PF. C'est certainement l'approche du big bang d'une manière que les langages stricts avec mutation ne sont pas, mais je pense que c'est une approche très valable.

10
  • SML dispose d'un interpréteur vraiment interactif dans lequel les fonctions peuvent être définies et utilisées. Dans Haskell, les fonctions doivent être définies dans un fichier séparé et compilées avant d'être utilisées dans le shell interactif.

Bien que les câlins puissent avoir cette limitation, GHCi ne:

$ ghci
GHCi, version 6.10.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> let hello name = "Hello, " ++ name
Prelude> hello "Barry"
"Hello, Barry"

Il y a de nombreuses raisons pour lesquelles je préfère GHC (i) à Hugs, ce n'est que l'une d'entre elles.

  • SML donne une confirmation explicite de l'argument de fonction et des types de retour dans une syntaxe facile à comprendre. Par exemple: val foo = fn: int * int -> int. La syntaxe implicite de curry de Haskell est un peu plus obtuse, mais pas totalement étrangère. Par exemple: foo :: Int -> Int -> Int.

SML a également ce que vous appelez la syntaxe "curry implicite".

$ sml
Standard ML of New Jersey v110.69 [built: Fri Mar 13 16:02:47 2009]
- fun add x y = x + y;
val add = fn : int -> int -> int

Essentiellement, SML et Haskell sont à peu près équivalents. Je penche vers Haskell parce que j'aime les compréhensions de listes et les listes infinies dans Haskell. Mais je crains que le nombre important de symboles dans la syntaxe compacte de Haskell puisse causer des problèmes aux étudiants. D'après ce que j'ai rassemblé en lisant d'autres articles sur SO, Haskell n'est pas recommandé pour les débutants débutant avec FP. Mais nous n'allons pas construire des applications à part entière, juste essayer des algorithmes simples.

J'aime utiliser Haskell beaucoup plus que SML, mais j'enseignerais tout d'abord SML en premier.

  • Appuyant sur les pensées du nominolo, les compréhensions de listes do semblent ralentir les étudiants d'accéder à certaines fonctions d'ordre supérieur.
  • Si vous voulez la paresse et des listes infinies, il est instructif de l'implémenter explicitement.
  • Parce que SML est évalué avec impatience, le modèle d'exécution est beaucoup plus facile à comprendre et le "débogage via printf" fonctionne beaucoup mieux que dans Haskell.
  • Le système de type de SML est également plus simple. Bien que votre classe ne les utiliserait probablement pas de toute façon, les classes de types de Haskell sont toujours un bosse supplémentaire à surmonter - pour leur faire comprendre le 'a contre ''a la distinction en SML est assez difficile.
9
ephemient

La plupart des réponses étaient techniques, mais je pense que vous devriez en considérer au moins une qui ne l'est pas: Haskell (en tant qu'OCaml), à l'heure actuelle, a une plus grande communauté l'utilisant dans un éventail plus large de contextes. Il y a aussi une grande base de données de bibliothèques et d'applications écrites pour le profit et le plaisir à Hackage . Cela peut être un facteur important pour garder certains de vos étudiants à utiliser la langue après la fin de votre cours, et peut-être essayer d'autres langues fonctionnelles (comme Standard ML) plus tard.

7

Je suis étonné que vous n'envisagiez pas OCaml et F # étant donné qu'ils répondent à tant de vos préoccupations. Des environnements de développement sûrement décents et utiles sont une priorité élevée pour les apprenants? SML est loin derrière et F # est loin devant tous les autres FPL à cet égard.

De plus, OCaml et F # ont des compréhensions de liste.

4
Jon Harrop

Haskell. Je suis en avance dans ma classe d'algos/théorie en CS à cause des choses que j'ai apprises en utilisant Haskell. C'est un langage tellement complet, et il vous apprendra une tonne de CS, juste en l'utilisant.

Cependant, SML est beaucoup plus facile à apprendre. Haskell a des fonctionnalités telles que l'évaluation paresseuse et les structures de contrôle qui le rendent beaucoup plus puissant, mais avec le coût d'une courbe d'apprentissage abrupte (ish). SML n'a pas une telle courbe.

Cela dit, la plupart de Haskell désapprendait des trucs de langages moins scientifiques/mathématiques tels que Ruby, ObjC ou Python.

2
Nate Symer