适用于初学者的Haskell或Standard ML?[关闭]


77

我将要教授离散结构的低年级课程。我之所以选择教科书“离散结构,逻辑和可计算性”,部分原因是它包含有助于使用功能性编程语言实现的示例和概念。(我也认为这是一本好教科书。)

我希望使用一种易于理解的FP语言来说明DS概念并供学生使用。大多数学生充其量只用Java进行一两个学期的编程。在查看了Scheme,Erlang,Haskell,Ocaml和SML之后,我选择了Haskell或Standard ML。由于以下原因,我倾向于Haskell,但我希望那些积极参与其中的程序员的意见。

  • Haskell和SML都具有模式匹配,这使得描述递归算法变得很困难。
  • Haskell具有很好的列表理解能力,与此类列表的数学表达方式非常匹配。
  • Haskell的评价很懒。非常适合使用列表理解技术构造无限列表。
  • SML具有真正的交互式解释器,可以在其中定义和使用功能。在Haskell中,必须先在单独的文件中定义函数并进行编译,然后才能在交互式shell中使用这些函数。
  • SML以易于理解的语法明确确认了函数参数和返回类型。例如:val foo = fn:int * int-> int。Haskell的隐式咖喱语法有点晦涩,但并非完全陌生。例如:foo :: Int-> Int-> Int。
  • Haskell默认情况下使用任意精度整数。它是SML / NJ中的外部库。SML / NJ默认将输出截断为70个字符。
  • Haskell的lambda语法很微妙-它使用单个反斜杠。SML更明确。不过,不确定是否在此类中是否需要lambda。

本质上,SML和Haskell大致等效。我倾向于Haskell,因为我喜欢Haskell中的列表理解和无限列表。但是我担心Haskell紧凑语法中的大量符号可能会引起学生问题。从我在SO上的其他文章中收集的信息来看,不建议Haskell开始使用FP。但是,我们不会尝试使用简单的算法来构建功能完善的应用程序。

你怎么看?


编辑:在阅读了您的一些好评后,我应该澄清一些要点。

在SML中,在解释器中定义函数与在外部文件中定义函数之间在语法上没有区别。假设您要编写阶乘函数。在Haskell中,您可以将此定义放入文件中并将其加载到GHCi中:

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

对我来说,这很清楚,简洁,并且与书中的数学定义相符。但是,如果要直接在GHCi中编写函数,则必须使用其他语法:

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

从教学的角度来看,使用交互式口译员时,学生可以在文件和命令行中使用相同的代码非常方便。

通过“明确确认函数”,我的意思是在定义函数时,SML会立即告诉您函数的名称,参数的类型以及返回类型。在Haskell中,您必须使用:type命令,然后您会得到一些令人困惑的咖喱符号。

Haskell还有一件很酷的事情-这是一个有效的函数定义:

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

同样,这符合他们在教科书中可能找到的定义。在SML中无法做到这一点!


3
关于Haskell的解释器,这些只是GHCi的一些特定限制。也许其他一些Haskell解释器的行为可能更好。您可以在ghci中定义值和函数,而不能定义数据类型。您必须先说“让”。同样,每个输入都必须在一行上,因此对于“ let”中的多个定义或“ do”或“ case”中的语句,必须使用多行缩进对齐语法,而不必用分号将它们分开,并用方括号将其包围。例如:“ let {事实0 = 1;事实n = n *事实(n-1)}”。另外,“ where”子句也不起作用。它确实有点乏味
newacct

关于currying,SML具有与Haskell相同的currying支持和语法。例如,在SML中,“ fun foo xy = x * y”是咖喱乘法。仅仅是出于某种原因,SML中的约定是多个参数应作为单个元组参数而不是咖喱参数给出。(不过,请注意,OCaml与SML不同,遵循的是已遵循的约定。)通常在SML中使用部分常用的功能。例如,使用SML中的“地图”函数,其类型为“('a->'b)->'a列表->'b列表”。
2009年

默认情况下,Haskell具有固定精度整数(Int)和任意精度整数(Integers)。只是在不受限制的情况下,解释器才选择可能的最大范围,即Integer。但是,某些函数将仅接受Int,例如(!!)列表索引运算符。
newacct

11
不幸的是,fac(n + 1)语法已从下一个Haskell标准中删除,因此请不要过分习惯:hackage.haskell.org/trac/haskell-prime/wiki/RemoveNPlusK
GS-致歉莫妮卡

1
嘿,巴里,我想知道您对此怎么看?tryhaskell.org 我想知道您是否考虑使用此在线Haskell学习“引擎”来教学生。如果您想更改它,我会帮忙。可能的示例:tryhaskell.org/… 有关实现的更多信息:chrisdone.com/posts/… 我最初是为了希望有人将其用于教育而编写的。我们可以扩展它,使返回符表示“;”。
Christopher Done 2010年

Answers:


88

我非常喜欢Haskell,这是我更喜欢SML作为离散数学和数据结构课程(以及大多数其他初学者的课程)的原因:

  • 即使对于专家来说,Haskell程序的时间和空间成本也很难预测。SML提供了更多限制的吹气方式。

  • 交互式解释器中函数定义的语法与文件中使用的语法相同,因此可以剪切和粘贴。

  • 尽管SML中的运算符重载完全是虚假的,但它也很简单。在Haskell中要教一整堂课而不必进入类型课将是困难的。

  • 学生可以使用进行调试print。(尽管,正如评论者所指出的,使用可以在Haskell中获得几乎相同的效果Debug.Trace.trace。)

  • 无限的数据结构令人震惊。对于初学者来说,最好让他们定义一个包含引用单元和thunk的流类型,以便他们知道它是如何工作的:

    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
    

    现在它不再是魔术,您可以从此处转到流(无限列表)。

  • 布局不像Python那样简单,并且可能会造成混乱。

Haskell有两个优势:

  • 在核心Haskell中,您可以在定义函数之前编写函数的类型签名。这对学生和其他初学者很有帮助。在SML中,没有什么好方法可以处理类型签名。

  • Haskell具有更好的具体语法。Haskell语法是对ML语法的重大改进。我写了一个关于在ML程序中何时使用括号简短注释; 这会有所帮助。

最终,有一把剑可以双向切割:

  • 默认情况下,Haskell代码是纯代码,因此您的学生不太可能偶然偶然碰到不纯净的构造(IO monad,state monad)。但是出于同样的原因,它们无法打印,并且如果您要执行I / O,则必须至少解释一下do符号,并且return令人困惑。

在一个相关主题上,这里有一些关于课程准备的建议:不要忽视Chris Okasaki的Purely Functional Data Structures。即使您没有让学生使用它,您也一定会想要获得一份副本。


好答案!我将再看看SML。提醒您,我对Haskell和SML的了解仅限于几个小时,每一个小时都要通过在线教程和阅读书籍来进行。我还没有深入研究细节。您可以解决这个问题吗?stackoverflow.com/questions/740896
巴里·布朗

12
商定了除“打印”调试之外的所有内容。您可以在Haskell中使用它。两者都有,Debug.Trace.trace :: String -> a -> a并且都Debug.Trace.traceShow :: (Show a) => a -> b -> b可以解决IO()限制并急切地输出跟踪。
维珀尔

1
<“ Haskell语法是对ML语法的重大改进。我写了一条简短的注释,说明何时在ML程序中使用括号。这有点帮助>>的确……我不喜欢SML的一件事就是Case语句可能带来的歧义。我觉得SML应该在其周围加上括号,以免嵌套时产生歧义。总体而言,我对SML的悲痛不是很多,都是句法上的。
Hibou57 2011年

3
您可能想查看面向初学者的NICTA Haskell课程:github.com/NICTA/course
Erik Kaplun

3
在最新的GHC版本中,用于定义函数的语法相同(不再需要let)。
ThreeFx

29

我们在大学里教Haskell一年级。我对此的感觉有些复杂。一方面,向Haskell教授第一年的课程意味着他们不必学习必要的风格。Haskell还可以生成非常简洁的代码,以前使用过Java的人可以欣赏。

我注意到学生经常遇到的一些问题:

  • 首先,模式匹配可能会有些困难。最初,学生在了解价值构建和模式匹配之间的关系时遇到了一些问题。他们还存在一些区分抽象的问题。我们的练习包括编写简化算术表达式的函数,一些学生难以理解抽象表示(例如Const 1)和元语言表示(1)之间的区别。

    此外,如果您的学生应该自己编写列表处理功能,请小心指出模式之间的区别

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

    根据您希望在此过程中教给他们多少函数式编程,您可以只给他们一些库函数,然后让他们试用。

  • 我们没有教我们的学生有关匿名函数的知识,我们只是告诉他们有关where子句的知识。对于某些任务,这有​​点冗长,但否则效果很好。我们也没有告诉他们部分应用程序。这可能很容易在Haskell中进行解释(由于其写作形式),因此值得向他们展示。

  • 他们很快就发现列表内涵及以上的高阶功能,如首选它们filtermapzipWith

  • 我认为我们错过了教他们如何让他们按类型指导思想的方法。不过,我不确定这是否对初学者有用。

  • 错误消息通常对初学者不是很有帮助,他们有时可能需要一些帮助。我自己还没有尝试过,但是有一个专门针对新手的Haskell编译器,主要是通过更好的错误消息:Helium

  • 对于小型程序,诸如可能的空间泄漏之类的问题都不是问题。

总体而言,Haskell是一门很好的教学语言,但也有一些陷阱。鉴于学生对列表理解的理解要比高阶函数要舒服得多,所以这可能是您需要的参数。我不知道您的课程有多长时间,或者您想教他们多少编程知识,但是确实计划了一些时间来教他们基本概念,他们将需要它。


3
[x:xs]和[x:xs]模式之间有什么区别?
猕猴桃2010年

15
(x:xs)匹配非空列表,即,参数必须具有type [a][x:xs]匹配包含非空列表的单例列表,即,参数必须具有type [[a]][x:xs]是相同的[(x:xs)],其是相同的((x:xs):[])
nominolo 2011年

回复:“一方面,教Haskell入读第一年意味着他们不必学习命令式”:我不会认为这是理所当然的。许多学生已经从高中班,图形计算器等一些编程背景
ruakh

1
您提到的大多数陷阱都反映了一年级学生在学习SML时也会经历的事情(除了喜欢列表理解而不是良好的库函数之类的东西,因为SML都不具备)。知道他们遇到了哪些Haskell特定的挑战(例如应对懒惰)会很有趣。
Simon Shine

@SimonShine懒惰怎么可能是一个挑战?
viyps '18

13

顺便说一句,

#SML具有真正的交互式解释器,可以在其中定义和使用功能。在Haskell中,必须先在单独的文件中定义函数并进行编译,然后才能在交互式shell中使用这些函数。

是不准确的。使用GHCi:

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

在haskell.org edu上,Haskell的教育资源也不错。页面,并有来自不同老师的经验。http://haskell.org/haskellwiki/Haskell_in_education

最后,如果您使用Haskell,就可以以有趣的方式教他们多核并行性:-)


6
我澄清了有关SML与Haskell解释器的声明。诺曼·拉姆齐(Norman Ramsey)说得更好:将解释器复制并粘贴到文件中。
巴里·布朗

4
请注意,SML不仅仅是SML / NJ,它是单核的。Poly / ML支持本机线程及其Isabelle / ML附加方便的抽象,例如并行列表和期货。
Makarius 2015年

11

许多大学将Haskell作为第一门功能语言甚至第一门编程语言进行教学,因此我认为这不会成为问题。

在一门这样的课程上做了一些教学之后,我不同意您发现的可能的混淆是可能的。早期混乱的最可能原因是由于布局错误导致的解析错误,以及在数字文字使用不正确时有关类型类的神秘消息。

对于任何不建议使用FP的初学者不建议使用Haskell的建议,我也将不同意。从某种程度上讲,使用严格的语言进行突变肯定是最有效的方法,但是我认为这是一种非常有效的方法。


1
我看过有些大学在Haskell和ML之间交替学习,这取决于谁在教这门课程。
hbw

9
  • SML具有真正的交互式解释器,可以在其中定义和使用功能。在Haskell中,必须先在单独的文件中定义函数并进行编译,然后才能在交互式shell中使用这些函数。

尽管拥抱可能有该限制,但GHCi不会:

$ 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"

有很多原因使我比拥抱更喜欢GHC(i),这只是其中之一。

  • SML以易于理解的语法明确确认了函数参数和返回类型。例如:val foo = fn:int * int-> int。Haskell的隐式咖喱语法有点晦涩,但并非完全陌生。例如:foo :: Int-> Int-> Int。

SML也具有您所谓的“隐式咖喱”语法。

$ 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

本质上,SML和Haskell大致等效。我倾向于Haskell,因为我喜欢Haskell中的列表理解和无限列表。但是我担心Haskell紧凑语法中的大量符号可能会引起学生问题。从我在SO上的其他文章中收集的信息来看,不建议Haskell开始使用FP。但是,我们不会尝试使用简单的算法来构建功能完善的应用程序。

我更喜欢使用Haskell,而不是SML,但我仍然会先教SML。

  • 紧随诺米诺洛(nominolo)的思想,列表理解似乎确实在拖慢学生学习某些高阶函数的速度。
  • 如果您需要懒惰和无限列表,则明确实现它是有启发性的。
  • 由于急切地评估了SML,因此执行模型要容易理解得多,并且“通过printf进行调试”比在Haskell中工作要好得多。
  • SML的类型系统也更简单。当你的类可能不会反正使用它们,Haskell的类型类仍然是一个多余的突起拿到过-让他们了解'a''a在SML的区别是足够坚韧的。

7

大多数答案都是技术性的,但我认为您应该考虑至少一个不是的答案:Haskell(作为OCaml)目前拥有更大的社区,可以在更广泛的环境中使用它。在Hackage上也有大量的图书馆和应用程序数据库,它们是为牟利和娱乐而编写的。这可能是确保您的某些学生在课程结束后仍使用该语言的一个重要因素,并且可能稍后再尝试使用其他功能语言(例如Standard ML)。


5

令您惊讶的是,您没有考虑使用OCaml和F#,我感到很惊讶。对于学习者来说,确定体面和有益的开发环境是否是当务之急?在这方面,SML落后于其他所有FPL,而F#则领先于其他FPL。

同样,OCaml和F#都有列表推导。


1
我都看了看。特别是一件事,让我对OCaml感到困扰:定义递归和非递归函数的语法略有不同。对于我们来说,这似乎是微不足道的,但是对于语法有足够麻烦的初学者来说,这可能是一件大事。我正在寻找使我尽快处理问题的工具。我没有认真考虑过F#,因为它是一种仅限Microsoft的语言。
巴里·布朗

1
在OCaml中,将“ let”用于非递归值或函数定义,将“ let rec”用于递归定义。在SML中,通常将“ val”用于非函数值,将“ fun”用于函数,除非它们是对先前函数的非递归替换,在这种情况下,您必须在顶层使用“ val”和lambda函数,或者如果嵌套,则为“ let val”和一个lambda函数。可以说,OCaml方式对我来说似乎更清晰。另外,您没有类似相等类型的解释。
JD

尽管F#仅是Microsoft,但您仍可以在OCaml和F#的交汇中编写代码,同时仍然受益于F#的开发环境。这肯定会使初学者的生活变得更加轻松,因为他们不得不与SML和Haskell可用的相对糟糕的工具进行斗争。
JD

1
此外,尽早接触.NET库对于学生可能会有所帮助。无论如何,它们有可能在以后的某些C#工作中结束。尽管没有真正在替代方案上投入太多,但简单的GUI编程是.NET(窗体,wpf)的优点。有时您所需要的只是带有编辑框和2个按钮的表单...使用haskell,我将无法就如何做到这一点给出“首选”建议。(可能是Web服务器库和html?)。
BitTickler

4

哈斯克尔。由于我从使用Haskell中学到的东西,所以我在CS的算法/理论课上遥遥领先。这是一种全面的语言,只需使用它,它就会教给您大量的CS

但是,SML更容易学习。Haskell具有诸如惰性评估和控制结构之类的功能,这些功能使其功能更强大,但代价是学习曲线陡峭。SML没有这样的曲线。

就是说,大多数Haskell都是从不太科学/数学的语言(例如Ruby,ObjC或Python)中学习知识的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.