Haskell或标准ML为初学者?

我将要以分散的结构教授一门低级课程。 我select了离散结构,逻辑和可计算性的教科书,部分原因是它包含有助于用函数式编程语言实现的示例和概念。 (我也认为这是一本很好的教科书。)

我想要一个易于理解的FP语言来说明DS的概念,并且学生可以使用。 充其量,大多math生在Java中只有一到两个学期的程序devise。 看过Scheme,Erlang,Haskell,Ocaml和SML之后,我已经select了Haskell或Standard ML。 我倾向于Haskell出于下面列出的原因,但我希望那些积极的程序员的意见,在一个或另一个。

  • Haskell和SML都有模式匹配,这使得描述recursionalgorithm变得简单。
  • 哈斯克尔有很好的列表理解,很好地匹配这样的列表在math上expression。
  • Haskell有懒惰的评价。 非常适合使用列表理解技术构build无限列表。
  • SML有一个真正的交互式解释器,可以在其中定义和使用函数。 在Haskell中,函数必须在单独的文件中定义并在交互式shell中使用之前进行编译。
  • SML以一种容易理解的语法给出了函数参数和返回types的明确确认。 例如:val foo = fn:int * int – > int。 哈斯克尔的隐含的咖喱语法更为呆板,但并不完全陌生。 例如:foo :: Int – > Int – > Int。
  • Haskell默认使用任意精度的整数。 这是SML / NJ的外部图书馆。 SML / NJ会将输出截断为70个字符。
  • Haskell的lambda语法是微妙的 – 它使用一个反斜杠。 SML更加明确。 不知道我们是否需要这门课的lambda。

本质上,SML和Haskell大致相同。 我倾向于Haskell,因为我喜欢Haskell中的列表理解和无限列表。 但是我担心Haskell的紧凑语法中大量的符号可能会导致学生的问题。 从我读过的其他文章中可以看出,Haskell不推荐用于FP的初学者。 但是我们不打算构build完整的应用程序,只是尝试简单的algorithm。

你怎么看?


编辑:在阅读你的一些很好的回应,我应该澄清我的一些要点。

在SML中,在解释器中定义函数和在外部文件中定义函数之间没有语法上的区别。 假设你想写出阶乘函数。 在Haskell中,你可以把这个定义放到一个文件中并加载到GHCi中:

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

对我来说,这是清楚的,简洁的,并符合书中的math定义。 但是如果你想直接在GHCi中编写函数,你必须使用不同的语法:

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

当使用交互式解释器时,从教学angular度来看,当学生可以在文件和命令行中使用相同的代码时,它是非常非常方便的。

通过“函数的明确确认”,我的意思是在定义函数时,SML马上告诉你函数的名字,参数的types和返回types。 在Haskell中,你必须使用:type命令,然后你得到一些令人困惑的咖喱记号。

关于Haskell更酷的一件事 – 这是一个有效的函数定义:

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

再次,这符合他们可能在教科书中find的定义。 不能在SML中做到这一点!

就像我喜欢Haskell一样,下面是我喜欢SML在离散math和数据结构(以及大多数其他初学者课程)中的一个类的原因:

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

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

  • 尽pipeSML中的运算符重载是完全错误的,但也很简单。 在Haskell中教授整个课程是很困难的,而不必进入types课程。

  • 学生可以使用print来debugging。 (尽pipe正如一位评论者所指出的那样,使用Debug.Trace.trace在Haskell中获得几乎相同的效果)。

  • 无限的数据结构打击了人们的思想。 对于初学者来说,最好让他们定义一个完整的reftypes的单元格和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 

    现在它不再是魔术了,你可以从这里到stream(无限列表)。

  • 布局不像在Python中那么简单,可能会让人困惑。

Haskell有两个地方有优势:

  • 在核心Haskell中,你可以在它的定义之前写一个函数的types签名。 这对学生和其他初学者非常有帮助。 在SML中处理types签名并不是一个好方法。

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

最后,还有一把双刃剑:

  • Haskell代码默认是纯粹的,所以你的学生不太可能偶然发现不纯的结构(IO monad,state monad)。 但同样的道理,他们不能打印,如果你想做I / O,那么最less必须解释符号, return是令人困惑的。

关于相关的话题,下面是你的课程准备的一些build议:不要忽视Chris Okasaki的纯function数据结构 。 即使你没有你的学生使用它,你一定会想要一个副本。

我们在我们的大学教哈斯克尔的第一年。 我对此的感觉有点混杂。 一方面,哈斯克尔一年级的教学意味着他们不需要忘记命令式的风格。 Haskell也可以生成非常简洁的代码,以前有一些Java的人可以欣赏。

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

  • 模式匹配起初可能有点困难。 学生们最初看到价值构build和模式匹配是如何相关的。 他们也有一些区分抽象的问题。 我们的练习包括编写简化算术expression式的函数,一些学生很难看到抽象表示(例如Const 1 )和元语言表示( 1 )之间的差异。

    此外,如果你的学生本身应该写清单处理函数,小心指出模式之间的差异

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

    根据你想在教程中教他们多lessfunction编程,你可以给他们一些库函数,让他们玩。

  • 我们没有教给我们的学生关于匿名function,我们只是告诉他们where条款。 对于某些任务来说,这有点冗长,但在其他方面效果不错。 我们也没有告诉他们部分的申请; 这可能很容易在Haskell中解释(由于其forms的写作types),所以它可能值得向他们展示。

  • 他们很快就发现了列表zipWith ,并优先考虑filtermapzipWith等高阶函数。

  • 我想我们错过了一些教他们如何让他们引导他们的想法的types。 不过,我不太确定这是否对初学者有帮助。

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

  • 对于小程序来说,可能发生空间泄漏的事情不是问题。

总的来说,Haskell是一门很好的教学语言,但有一些缺陷。 考虑到学生比高阶函数对列表理解感觉更舒适,这可能是你需要的论证。 我不知道你的课程有多长,或者你想要教授多less节目,但是要花点时间教他们基本的概念 – 他们会需要它。

顺便说一句,

#SML有一个真正的交互式解释器,可以在其中定义和使用函数。 在Haskell中,函数必须在单独的文件中定义并在交互式shell中使用之前进行编译。

是不准确的。 使用GHCi:

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

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

最后,如果你使用Haskell,你将能够教给他们多核并行:

许多大学教Haskell作为第一function语言,甚至第一编程语言,所以我不认为这是一个问题。

在完成了一门这样的课程的教学之后,我不同意你认为可能的混淆。 早期混淆的最可能的来源是parsing由错误布局导致的错误,以及数字文字不正确使用时关于types的神秘消息。

我也不同意任何build议Haskell不build议初学者从FP开始。 当然严格的语言与突变的方式是大爆炸的方式,但我认为这是一个非常有效的方法。

  • SML有一个真正的交互式解释器,可以在其中定义和使用函数。 在Haskell中,函数必须在单独的文件中定义并在交互式shell中使用之前进行编译。

虽然Hugs可能有这个限制,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以一种容易理解的语法给出了函数参数和返回types的明确确认。 例如:val foo = fn:int * int – > int。 哈斯克尔的隐含的咖喱语法更为呆板,但并不完全陌生。 例如:foo :: Int – > Int – > Int。

SML也有你所说的“隐式咖喱”语法。

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

本质上,SML和Haskell大致相同。 我倾向于Haskell,因为我喜欢Haskell中的列表理解和无限列表。 但是我担心Haskell的紧凑语法中大量的符号可能会导致学生的问题。 从我读过的其他文章中可以看出,Haskell不推荐用于FP的初学者。 但是我们不打算构build完整的应用程序,只是尝试简单的algorithm。

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

  • 借用nominolo的想法,列表理解确实会让学生不能进入更高级的function。
  • 如果你想懒惰和无限的名单,明确实施它是有益的。
  • 由于SML被热切地评估,所以执行模型更容易理解,“通过printfdebugging”的工作比Haskell要好得多。
  • SML的types系统也比较简单。 虽然你的类可能不会使用它们,但Haskell的types类仍然是一个额外的颠簸 – 让他们理解'a一对一''a ,SML ''a区别是足够强硬的。

大多数答案都是技术性的,但我认为你至less应该考虑一个:Haskell(作为OCaml)在这个时候有更大的社区在更广泛的环境中使用它。 在Hackage上还有一个大型的图书馆和应用程序数据库。 这可能是保持学生在课程结束后使用该语言的一个重要因素,也可能是在稍后尝试使用其他function性语言(如Standard ML)。

我很惊讶你不考虑OCaml和F#,因为他们解决了你很多的问题。 当然,体面和有益的发展环境是学习者的首要任务? SML落伍了,F#在这方面领先于所有其他FPLs。

另外,OCaml和F#都有列表parsing。

哈斯克尔。 因为我从使用Haskell学到的东西,我在CS的algorithm/理论课上领先了。 这是一个如此全面的语言,它会教你一大堆的CS, 只是使用它

但是,SML更容易学习。 Haskell具有懒惰的评估和控制结构等function,使其function更加强大,但是其学习曲线陡峭(ish)。 SML没有这样的曲线。

也就是说,Haskell绝大多数都是从Ruby,ObjC或Python等科学/math语言中解放出来的东西。