Haskell o ML estándar para principiantes?
functional-programming sml (8)
Enseñaré un curso de baja división en estructuras discretas. He seleccionado el libro de texto Estructuras discretas, Lógica y Computabilidad, en parte porque contiene ejemplos y conceptos que conducen a la implementación con un lenguaje de programación funcional. (También creo que es un buen libro de texto).
Quiero un lenguaje FP fácil de entender para ilustrar los conceptos de DS y que los estudiantes puedan usar. La mayoría de los estudiantes solo tendrán uno o dos semestres de programación en Java, en el mejor de los casos. Después de mirar a Scheme, Erlang, Haskell, Ocaml y SML, me he decidido por Haskell o por ML estándar. Me inclino por Haskell por las razones que se detallan a continuación, pero me gustaría conocer la opinión de aquellos que son programadores activos en uno u otro.
- Tanto Haskell como SML tienen una coincidencia de patrones que hace que describir un algoritmo recursivo sea fácil.
- Haskell tiene una buena lista de comprensiones que coinciden muy bien con la forma en que esas listas se expresan matemáticamente.
- Haskell tiene una evaluación perezosa. Ideal para construir listas infinitas usando la técnica de comprensión de listas.
- SML tiene un intérprete verdaderamente interactivo en el que las funciones se pueden definir y usar. En Haskell, las funciones deben definirse en un archivo separado y compilarse antes de ser utilizadas en el shell interactivo.
- SML da una confirmación explícita del argumento de la función y los tipos de retorno en una sintaxis que es fácil de entender. Por ejemplo: val foo = fn: int * int -> int. La sintaxis de curry implícita de Haskell es un poco más obtusa, pero no totalmente ajena. Por ejemplo: foo :: Int -> Int -> Int.
- Haskell usa enteros de precisión arbitraria por defecto. Es una biblioteca externa en SML / NJ. Y SML / NJ trunca la salida a 70 caracteres por defecto.
- La sintaxis lambda de Haskell es sutil: usa una sola barra invertida. SML es más explícito. Sin embargo, no estoy seguro si alguna vez necesitaremos lambda en esta clase.
Básicamente, SML y Haskell son aproximadamente equivalentes. Me inclino hacia Haskell porque me encantan las listas de comprensiones y las listas infinitas en Haskell. Pero me preocupa que la gran cantidad de símbolos en la sintaxis compacta de Haskell pueda causar problemas a los estudiantes. De lo que he reunido leyendo otras publicaciones sobre SO, Haskell no es recomendable para principiantes que comienzan con FP. Pero no vamos a construir aplicaciones completas, solo probando algoritmos simples.
¿Qué piensas?
Editar: Después de leer algunas de sus excelentes respuestas, debería aclarar algunas de mis viñetas.
En SML, no hay distinción sintáctica entre definir una función en el intérprete y definirla en un archivo externo. Digamos que quieres escribir la función factorial. En Haskell puedes poner esta definición en un archivo y cargarlo en GHCi:
fac 0 = 1
fac n = n * fac (n-1)
Para mí, eso es claro, sucinto, y coincide con la definición matemática en el libro. Pero si quiere escribir la función en GHCi directamente, debe usar una sintaxis diferente:
let fac 0 = 1; fac n = n * fac (n-1)
Cuando se trabaja con intérpretes interactivos, desde una perspectiva docente es muy, muy útil cuando el alumno puede usar el mismo código tanto en un archivo como en la línea de comando.
Por "confirmación explícita de la función", quise decir que al definir la función, SML de inmediato le dice el nombre de la función, los tipos de argumentos y el tipo de devolución. En Haskell tienes que usar el comando :type
y luego obtienes la notación curry algo confusa.
Una cosa más genial sobre Haskell: esta es una definición de función válida:
fac 0 = 1
fac (n+1) = (n+1) * fac n
Una vez más, esto coincide con una definición que puedan encontrar en el libro de texto. No se puede hacer eso en SML!
- SML tiene un intérprete verdaderamente interactivo en el que las funciones se pueden definir y usar. En Haskell, las funciones deben definirse en un archivo separado y compilarse antes de ser utilizadas en el shell interactivo.
Mientras que los abrazos pueden tener esa limitación, GHCi no:
$ 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"
Hay muchas razones por las que prefiero GHC (i) a través de Hugs, este es solo uno de ellos.
- SML da una confirmación explícita del argumento de la función y los tipos de retorno en una sintaxis que es fácil de entender. Por ejemplo: val foo = fn: int * int -> int. La sintaxis de curry implícita de Haskell es un poco más obtusa, pero no totalmente ajena. Por ejemplo: foo :: Int -> Int -> Int.
SML tiene también la sintaxis de "curry implícito".
$ 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
Básicamente, SML y Haskell son aproximadamente equivalentes. Me inclino hacia Haskell porque me encantan las listas de comprensiones y las listas infinitas en Haskell. Pero me preocupa que la gran cantidad de símbolos en la sintaxis compacta de Haskell pueda causar problemas a los estudiantes. De lo que he reunido leyendo otras publicaciones sobre SO, Haskell no es recomendable para principiantes que comienzan con FP. Pero no vamos a construir aplicaciones completas, solo probando algoritmos simples.
Me gusta usar Haskell mucho más que SML, pero aún así le enseñaría primero a SML.
- En segundo lugar, los pensamientos de nominolo, la lista de comprensiones parecen retrasar a los estudiantes para llegar a algunas funciones de orden superior.
- Si desea la pereza y las listas infinitas, es instructivo implementarlo explícitamente.
- Debido a que SML es evaluado con entusiasmo, el modelo de ejecución es mucho más fácil de comprender, y "depurar a través de printf" funciona mucho mejor que en Haskell.
- El sistema de tipos de SML también es más simple. Aunque es probable que tu clase no los use de todos modos, las clases de Haskell todavía son un bache extra para superar, hacer que entiendan la distinción
''a
versus''''a
en SML es bastante difícil.
Enseñamos a Haskell a los primeros años en nuestra universidad. Mis sentimientos sobre esto son un poco mixtos. Por un lado, enseñar Haskell a los primeros años significa que no tienen que desaprender el estilo imperativo. Haskell también puede producir un código muy conciso que las personas que tenían algo de Java antes pueden apreciar.
Algunos problemas que he notado los estudiantes a menudo tienen:
La coincidencia de patrones puede ser un poco difícil, al principio. Los estudiantes inicialmente tuvieron algunos problemas al ver cómo se relacionan la construcción de valores y la coincidencia de patrones. También tuvieron algunos problemas para distinguir entre abstracciones. Nuestros ejercicios incluyeron funciones de escritura que simplifican la expresión aritmética y algunos estudiantes tuvieron dificultades para ver la diferencia entre la representación abstracta (por ejemplo,
Const 1
) y la representación de metalenguaje (1
).Además, si se supone que los alumnos deben escribir funciones de procesamiento de listas, tenga cuidado al señalar la diferencia entre los patrones.
[] [x] (x:xs) [x:xs]
Dependiendo de la cantidad de programación funcional que desee enseñarles en el camino, puede darles algunas funciones de biblioteca y dejar que jueguen con eso.
No enseñamos a nuestros estudiantes sobre las funciones anónimas, simplemente les dijimos sobre las cláusulas
where
. Para algunas tareas esto fue un poco detallado, pero funcionó bien de lo contrario. Tampoco les informamos sobre las aplicaciones parciales; esto es probablemente bastante fácil de explicar en Haskell (debido a su forma de escribir tipos) por lo que podría valer la pena mostrarles.Descubrieron rápidamente las listas de comprensión y las preferían sobre las funciones de orden superior como
filter
,map
,zipWith
.Creo que nos perdimos un poco al enseñarles cómo dejar que guíen sus pensamientos por los tipos. Sin embargo, no estoy muy seguro de si esto es útil para principiantes o no.
Los mensajes de error generalmente no son muy útiles para los principiantes, de vez en cuando pueden necesitar ayuda con estos. No lo he probado yo solo, pero hay un compilador Haskell específicamente dirigido a los recién llegados, principalmente por medio de mejores mensajes de error: Helium
Para los programas pequeños, cosas como posibles pérdidas de espacio no eran un problema.
En general, Haskell es un buen lenguaje de enseñanza, pero hay algunas trampas. Dado que los estudiantes se sienten mucho más cómodos con las listas de comprensión que con las funciones de orden superior, este podría ser el argumento que necesita. No sé cuánto dura su curso o la cantidad de programación que desea enseñarles, pero planifique algún momento para enseñarles los conceptos básicos: lo necesitarán.
Haskell. Estoy adelantado en mi clase de algos / teoría en CS por las cosas que aprendí al usar Haskell. Es un lenguaje tan completo, y te enseñará un montón de CS, simplemente utilizándolo .
Sin embargo, SML es mucho más fácil de aprender. Haskell tiene características tales como evaluación perezosa y estructuras de control que lo hacen mucho más poderoso, pero con el costo de una curva de aprendizaje abrupta (ish). SML no tiene tal curva.
Dicho esto, la mayor parte de Haskell estaba desaprendiendo cosas de lenguajes científicos / matemáticos como Ruby, ObjC o Python.
La mayoría de las respuestas fueron técnicas, pero creo que debería considerar al menos una que no lo es: Haskell (como OCaml), en este momento, tiene una comunidad más grande que lo usa en una gama más amplia de contextos. También hay una gran base de datos de bibliotecas y aplicaciones escritas con fines de lucro y diversión en Hackage . Ese puede ser un factor importante para evitar que algunos de sus alumnos utilicen el idioma una vez finalizado el curso, y tal vez intente con otros lenguajes funcionales (como el estándar ML) más adelante.
Me sorprende que no estés considerando OCaml y F # dado que abordan muchas de tus preocupaciones. Sin duda, los entornos de desarrollo decentes y útiles son una alta prioridad para los estudiantes? SML está muy por detrás y F # está muy por delante de todos los otros FPL en ese aspecto.
Además, tanto OCaml como F # tienen una lista de comprensiones.
Muchas universidades enseñan a Haskell como primer lenguaje funcional o incluso como primer lenguaje de programación, así que no creo que esto sea un problema.
Después de haber impartido parte de la enseñanza en uno de esos cursos, no estoy de acuerdo en que las posibles confusiones que identifiques sean tan probables. Las fuentes más probables de confusión temprana son los errores de análisis causados por el mal diseño y los mensajes misteriosos sobre las clases de tipo cuando los literales numéricos se utilizan de forma incorrecta.
También estoy en desacuerdo con cualquier sugerencia de que Haskell no se recomienda para principiantes que comienzan con FP. Ciertamente es el enfoque del Big Bang de maneras que los lenguajes estrictos con mutación no lo son, pero creo que es un enfoque muy válido.
Por cierto,
# SML tiene un intérprete realmente interactivo en el que las funciones se pueden definir y usar. En Haskell, las funciones deben definirse en un archivo separado y compilarse antes de ser utilizadas en el shell interactivo.
Es inexacto Use GHCi:
Prelude> let f x = x ^ 2
Prelude> f 7
49
Prelude> f 2
4
También hay buenos recursos para Haskell en educación en haskell.org edu. página, con experiencias de diferentes profesores. http://haskell.org/haskellwiki/Haskell_in_education
Finalmente, podrás enseñarles el paralelismo multinúcleo solo por diversión, si usas Haskell :-)
Por mucho que ame a Haskell, aquí están las razones por las que preferiría SML para una clase en matemáticas discretas y estructuras de datos (y la mayoría de las otras clases para principiantes):
Los costos de tiempo y espacio de los programas de Haskell pueden ser muy difíciles de predecir, incluso para los expertos. SML ofrece formas mucho más limitadas de explotar la máquina.
La sintaxis para la definición de funciones en un intérprete interactivo es idéntica a la sintaxis utilizada en un archivo, por lo que puede cortar y pegar.
Aunque la sobrecarga del operador en SML es totalmente falsa, también es simple. Va a ser difícil enseñar toda una clase en Haskell sin tener que entrar en clases de tipo.
El estudiante puede depurar usando
print
. (Aunque, como señala un comentarista, es posible obtener casi el mismo efecto en Haskell usandoDebug.Trace.trace
).Las estructuras de datos infinitas impresionan a las personas. Para los principiantes, es mejor que ellos definan un tipo de flujo completo con células ref y thunk, para que sepan cómo funciona:
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
Ahora ya no es magia, y puedes ir desde aquí a las transmisiones (listas infinitas).
El diseño no es tan simple como en Python y puede ser confuso.
Hay dos lugares en los que Haskell tiene una ventaja:
En Core Haskell puede escribir la firma de tipo de una función justo antes de su definición. Esto es de gran ayuda para los estudiantes y otros principiantes. Simplemente no hay una buena manera de lidiar con las firmas de tipos en SML.
Haskell tiene una mejor sintaxis concreta. La sintaxis Haskell es una mejora importante sobre la sintaxis ML. He escrito una breve nota sobre cuándo usar paréntesis en un programa de ML ; esto ayuda un poco
Finalmente, hay una espada que corta en ambos sentidos:
- El código de Haskell es puro por defecto, por lo que es improbable que los alumnos tropiecen accidentalmente con constructos impuros (mónada IO, mónada de estado). Pero por la misma razón, no pueden imprimir, y si quiere hacer E / S, entonces al mínimo debe explicar la notación de
do
, y elreturn
es confuso.
Sobre un tema relacionado, aquí hay algunos consejos para la preparación de su curso: no pase por alto las estructuras de datos puramente funcionales de Chris Okasaki. Incluso si no hace que sus alumnos lo usen, definitivamente querrá tener una copia.