哈斯克尔之后学什么语言?

作为我的第一门编程语言,我决定学习 Haskell。我的专业是分析哲学,哈斯克尔允许我快速、正确地创建感兴趣的程序,例如,自然语言解析的传感器、定理证明程序和解释程序。虽然我只编写了两个半月的程序,但是我发现 Haskell 的语义和语法比传统的命令式语言更容易学习,而且现在对它的大多数结构都感觉很舒服。

然而,在哈斯克尔编程就像巫术一样,我想扩展我的编程知识。我想选择一种新的编程语言来学习,但是我没有足够的时间去学习一种任意的语言,放弃它,然后重复。因此,我想在这里提出这个问题,同时对我所寻找的语言类型做出一些规定。有些是主观的,有些是为了缓解从哈斯克尔的过渡。

  • 强类型系统。在哈斯克尔,我最喜欢的编程部分之一就是编写类型声明。这有助于构建我对单个函数及其与整个程序的关系的想法。它还使得非正式地推理我的程序的正确性变得更加容易。我关心的是正确性,而不是效率。
  • 强调递归而不是迭代。我在哈斯克尔使用迭代构造,但是递归地实现它们。然而,与复杂的迭代过程相比,理解递归函数的结构要容易得多,特别是在使用组合子和高阶函数(如映射、折叠和绑定)时。
  • 值得学习。Haskell 是一种用于工作的 值得语言。这有点像读康德。然而,我几年前在 C 的经历却不是这样。我不是在找 C。语言应该强制实施一个概念上有趣的范例,在我完全主观的看法,C 喜欢不。

权衡答案 : 当然,这些只是笔记。我只想回答每一个给出正确答案的人。你帮了大忙。

1)一些回复表明,强调递归的强大的静态类型语言意味着另一种函数式语言。虽然我想继续与 Haskell 紧密合作,camccann 和 larsmans 正确地指出,另一种这样的语言将“过于简化转换”这些评论非常有帮助,因为我不想在 Caml 给 Haskell 写信!在证明助理中,考克和阿格达看起来都很有趣。特别是,Coq 将为构造逻辑和形式类型理论提供一个扎实的介绍。我在一阶谓词和模态逻辑(Mendellsohn,Enderton,还有一些 Hinman)方面花了一些时间,所以我可能会从 Coq 中获得很多乐趣。

2)其他人非常喜欢 Lisp (Common Lisp,Scheme 和 Clojure)。据我所知,Common Lisp 和 Scheme 都有优秀的入门材料(在 Lisp 上理性的策划者SICP)。SICP中的材料使我倾向于 Scheme。特别是,Scheme 到 SICP将涵盖不同的评估策略、惰性的实现,以及关注延续、解释器、符号计算等主题的机会。最后,正如其他人指出的那样,Lisp 对待代码/数据的方式将是全新的。因此,我倾向于选项(2) ,一个 Lisp。

3)第三,Prolog。Prolog 有大量有趣的材料,它的 初选域正是我感兴趣的。它有一个简单的语法和易于阅读。我现在不能给出更多的评论,但是在读了 Prolog 的概述和略读了一些介绍性的材料之后,它的排名是(2)。似乎 Prolog 的回溯程序总是被黑进 Haskell!

4)在主流语言中,Python 看起来最有趣。Tim Yates 让这些语言听起来很有吸引力。显然,Python 经常被教给计算机科学专业的一年级学生; 所以它要么概念丰富,要么容易学。我得做更多的研究。

谢谢大家的推荐!它看起来像 Lisp (Scheme,Clojure)、 Prolog,或者像 Coq 或 Agda 这样的证明助手是被推荐的主要语言。

15146 次浏览

You could start looking into Lisp.

Prolog is a cool language too.

From the standpoint of what suits your major, the obvious choice seems like a logic language such as Prolog or its derivatives. Logic programming can be done very neatly in a functional language (see, e.g. The Reasoned Schemer) , but you might enjoy working with the logic paradigm directly.

An interactive theorem proving system such as twelf or coq might also strike your fancy.

In my experience, strong typing + emphasis on recursion means another functional programming language. Then again, I wonder if that's very rewarding, given that none of them will be as "pure" as Haskell.

As other posters have suggested, Prolog and Lisp/Scheme are nice, even though both are dynamically typed. Many great books with a strong theoretical "taste" to them have been published about Scheme in particular. Take a look at SICP, which also conveys a lot of general computer science wisdom (meta-circular interpreters and the like).

Despite its failure to meet one of your big criteria (static* typing), I'm going to make a case for Python. Here are a few reasons I think you should take a look at it:

  • For an imperative language, it is surprisingly functional. This was one of the things that struck me when I learned it. Take list comprehensions, for example. It has lambdas, first-class functions, and many functionally-inspired compositions on iterators (maps, folds, zips...). It gives you the option of picking whatever paradigm suits the problem best.
  • IMHO, it is, like Haskell, beautiful to code in. The syntax is simple and elegant.
  • It has a culture that focuses on doing things in a straightforward way, rather than focusing too minutely on efficiency.

I understand if you are looking for something else though. Logic programming, for instance, might be right up your alley, as others have suggested.


* I assume you mean static typing here, since you want to declare the types. Techincally, Python is a strongly typed language, since you can't arbitrarily interpret, say, a string as an number. Interestingly, there are Python derivatives that allow static typing, like Boo.

I'd advise you learn Coq, which is a powerful proof assistant with syntax that will feel comfortable to the Haskell programmer. The cool thing about Coq is it can be extracted to other functional languages, including Haskell. There is even a package (Meldable-Heap) on Hackage that was written in Coq, had properties proven about its operation, then extracted to Haskell.

Another popular language that offers more power than Haskell is Agda - I don't know Agda beyond knowing it is dependently typed, on Hackage, and well respected by people I respect, but those are good enough reasons to me.

I wouldn't expect either of these to be easy. But if you know Haskell and want to move forward to a language that gives more power than the Haskell type system then they should be considered.

How about a stack-oriented programming language? Cat hits your high points. It is:

  • Statically typed with type inference.
  • Makes you re-think common imperative languages concepts like looping. Conditional execution and looping are handled with combinators.
  • Rewarding - forces you to understand yet another model of computation. Gives you another way to think about and decompose problems.

Dr. Dobbs published a short article about Cat in 2008 though the language has changed slightly.

Given your description, I would suggest Ocaml or F#.

The ML family are generally very good in terms of a strong type system. The emphasis on recursion, coupled with pattern matching, is also clear.

Where I am a bit hesitant is on the rewarding to learn part. Learning them was rewarding for me, no doubt. But given your restrictions and your description of what you want, it seems you are not actually looking for something much more different than Haskell.

If you didn't put your restrictions I would have suggested Python or Erlang, both of which would take you out of your comfort zone.

I would like to broaden my knowledge of programming. (...) I thought I would pose the question here, along with several stipulations about the type of language I am looking for. Some are subjective, some are intended to ease the transition from Haskell.

Strong type system. (...) It also makes informally reasoning about the correctness of my program easier. I'm concerned with correctness, not efficiency.

Emphasis on recursion rather than iteration. (...)

You may be easing the transition a bit too much here, I'm afraid. The very strict type system and purely functional style are characteristic of Haskell and pretty much anything resembling a mainstream programming language will require compromising at least somewhat on one of these. So, with that in mind, here are a few broad suggestions aimed at retaining most of what you seem to like about Haskell, but with some major shift.

  • Disregard practicality and go for "more Haskell than Haskell": Haskell's type system is full of holes, due to nontermination and other messy compromises. Clean up the mess and add more powerful features and you get languages like Coq and Agda, where a function's type contains a proof of its correctness (you can even read the function arrow -> as logical implication!). These languages have been used for mathematical proofs and for programs with extremely high correctness requirements. Coq is probably the most prominent language of the style, but Agda has a more Haskell-y feel (as well as being written in Haskell itself).

  • Disregard types, add more magic: If Haskell is sorcery, Lisp is the raw, primal magic of creation. Lisp-family languages (also including Scheme and Clojure) have nearly unparalleled flexibility combined with extreme minimalism. The languages have essentially no syntax, writing code directly in the form of a tree data structure; metaprogramming in a Lisp is easier than non-meta programming in some languages.

  • Compromise a bit and move closer to the mainstream: Haskell falls into the broad family of languages influenced heavily by ML, any of which you could probably shift to without too much difficulty. Haskell is one of the strictest when it comes to correctness guarantees from types and use of functional style, where others are often either hybrid styles and/or make pragmatic compromises for various reasons. If you want some exposure to OOP and access to lots of mainstream technology platforms, either Scala on the JVM or F# on .NET have a lot in common with Haskell while providing easy interoperability with the Java and .NET platforms. F# is supported directly by Microsoft, but has some annoying limitations compared to Haskell and portability issues on non-Windows platforms. Scala has direct counterparts to more of Haskell's type system and Java's cross-platform potential, but has a more heavyweight syntax and lacks the powerful first-party support that F# enjoys.

Most of those recommendations are also mentioned in other answers, but hopefully my rationale for them offers some enlightenment.

I would recommend you Erlang. It is not strong typed language and you should try it. It is very different approach to programming and you may find that there are problems where strong typing is not The Best Tool(TM). Anyway Erlang provides you tools for static type verification (typer, dialyzer) and you can use strong typing on parts where you gain benefits from it. It can be interesting experience for you but be prepared, it will be very different feeling. If you are looking for "conceptually interesting paradigm" you can found them in Erlang, message passing, memory separation instead sharing, distribution, OTP, error handling and error propagation instead of error "prevention" and so. Erlang can be far away from your current experience but still brain tickling if you have experience with C and Haskell.

I'm going to be That Guy and suggest that you're asking for the wrong thing.

First you say that you want to broaden your horizons. Then you describe the kind of language that you want, and its horizons sound incredibly like the horizons you already have. You're not going to gain very much by learning the same thing over and over.

I would suggest you learn a Lisp — i.e. Common Lisp, Scheme/Racket or Clojure. They're all dynamically typed by default, but feature some sort of type hinting or optional static typing. Racket and Clojure are probably your best bets.

Clojure is more recent and has more Haskellisms like immutability by default and lots of lazy evaluation, but it's based on the Java Virtual Machine, which means it has some odd warts (e.g. the JVM doesn't support tail call elimination, so recursion is kind of a hack).

Racket is much older, but has picked up a lot of power along the way, such as static type support and a focus on functional programming. I think you'd probably get the most out of Racket.

The macro systems in Lisps are very interesting and vastly more powerful than anything you'll see anywhere else. That alone is worth at least looking at.

Go with one of the main streams. Given the resources available, future marketability of your skill, rich developer ecosystem I think you should start with either Java or C#.

As you didn't mention any restrictions besides your subjective interests and emphasize 'rewarding to learn' (well, ok, I'll ignore the static typing restriction), I would suggest to learn a few languages of different paradigms, and preferably ones which are 'exemplary' for each of them.

  • A Lisp dialect for the code-as-data/homoiconicity thing and because they are good, if not the best, examples of dynamic (more or less strict) functional programming languages
  • Prolog as the predominant logic programming language
  • Smalltalk as the one true OOP language (also interesting because of its usually extremely image-centric approach)
  • maybe Erlang or Clojure if you are interested in languages forged for concurrent/parallel/distributed programming
  • Forth for stack oriented programming
  • (Haskell for strict functional statically typed lazy programming)

Especially Lisps (CL not as much as Scheme) and Prolog (and Haskell) embrace recursion.

Although I am not a guru in any of these languages, I did spend some time with each of them, except Erlang and Forth, and they all gave me eye-opening and interesting learning experiences, as each one approaches problem solving from a different angle.

So, though it may seem as if I ignored the part about your having no time to try a few languages, I rather think that time spent with any of these will not be wasted, and you should have a look at all of them.

If you want a strong(er)ly typed Prolog, Mercury is an interesting choice. I've dabbled in it in the past and I liked the different perspective it gave me. It also has moded-ness (which parameters need to be free/fixed) and determinism (how many results are there?) in the type system.

Clean is very similar to Haskell, but has uniqueness typing, which are used as an alternative to Monads (more specifically, the IO monad). Uniqueness typing also does interesting stuff to working with arrays.

Factor will be a good choice.

Great question-- I've been asking it myself recently after spending several months thoroughly enjoying Haskell, although my background is very different (organic chemistry).

Like you, C and its ilk are out of the question.

I've been oscillating between Python and Ruby as the two practical workhorse scripting languages today (mules?) that both have some functional components to them to keep me happy. Without starting any Rubyist/Pythonist debates here, but my personal pragmatic answer to this question is:

Learn the one (Python or Ruby) that you first get an excuse to apply.

If you decide to stray from your preference for a type system,you might be interested in the J programming language. It is outstanding for how it emphasizes function composition. If you like point-free style in Haskell, the tacit form of J will be rewarding. I've found it extraordinarily thought-provoking, especially with regard to semantics.

True, it doesn't fit your preconceptions as to what you'd like, but give it a look. Just knowing that it's out there is worth discovering. The sole source of complete implementations is J Software, jsoftware.com.

I'm a bit late but I see that no one has mentioned a couple of paradigms and related languages that can interest you for their high-level of abstraction and generality: