Haskell或Standard ML适合初学者?

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

我想要一个易于理解的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。 哈斯克尔的隐式咖喱语法稍微钝了一点,但并不完全陌生。 例如:foo :: Int - > Int - > Int。
  • Haskell默认使用任意精度的整数。 这是SML / NJ的外部图书馆。 默认情况下,SML / NJ会将输出截断为70个字符。
  • Haskell的lambda语法很微妙 - 它使用一个反斜杠。 SML更加明确。 但是,不确定我们是否需要这门课的lambda。
  • 实质上,SML和Haskell大致相同。 我倾向于Haskell,因为我热爱Haskell中的列表理解和无限列表。 但是我担心Haskell紧凑语法中大量符号可能会导致学生出现问题。 从我读过的其他文章中可以看到,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中做到这一点!


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

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

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

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

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

  • 无限的数据结构打击了人们的思想。 对于初学者来说,最好让他们定义一个完整的参考单元格和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,然后在minumum你必须解释do记号,并return是令人困惑的。

  • 关于相关主题,以下是您的课程准备建议:不要忽视Chris Okasaki的纯功能数据结构。 即使你没有你的学生使用它,你一定会想要一个副本。


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

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

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

    此外,如果您的学生本身应该编写列表处理函数,请小心指出模式之间的差异

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

    根据你想要在途中教他们多少功能性编程,你可以给他们一些库函数,让他们玩弄它。

  • 我们没有向我们的学生讲授匿名函数,我们只是告诉他们有关where子句。 对于某些任务来说,这有点冗长,但在其他方面效果不错。 我们也没有告诉他们有关部分申请; 这可能很容易在Haskell中解释(由于它的书写类型),所以它可能值得向他们展示。

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

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

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

  • 对于小型项目来说,可能的空间泄漏等问题不是问题。

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


    顺便说一句,

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

    不准确。 使用GHCi:

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

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

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

    链接地址: http://www.djcxy.com/p/43317.html

    上一篇: Haskell or Standard ML for beginners?

    下一篇: Haskell: Composition of morphisms in monoidal categories