Update 2020-12-07: There was a bug in the macro expansion logic. I've backported the fix to the linked source and explained the bug in the 'mistakes' section.
What do you mean by Haskell-like type annotations?
Do you mean literally the syntax
foo :: Type0 -> Type1 -> Type2
? Or do you mean the ability to have the type annotation on a separate line from the function implementation itself (rather than e.g. annotating its arguments individually)?
Typed Racket is pretty close. I imagine that with some work and Racket's macro and module system that someone could rewrite it to be more ML-like in syntax.
In the Coursera course Programming Languages, I ported some of the first assignments from SML to F# and Typed Racket, and you can see the similarities of type annotations in the very simple examples below.
SML:
(* Helper function. Takes a generic list and an integer n and returns the nth element of the list. *)
fun get_nth_element (xs : 'a list, n : int) =
if n = 1
then hd xs
else get_nth_element(tl xs, n-1)
(* Takes a list of strings and an integer n and returns the nth element of the list. *)
fun get_nth (strings : string list, n : int) = get_nth_element(strings,n)
F#:
/// Helper function. Takes a generic list and an integer n and returns the nth element of the list.
let rec getNthElement (xs : 'a list, n : int) =
if n = 1
then List.head xs
else getNthElement(List.tail xs, n-1)
/// Takes a list of strings and an integer n and returns the nth element of the list.
let getNth (strings : string list, n : int) = getNthElement(strings,n)
Racket:
#lang typed/racket
;; Helper function. Takes a generic list and an integer n and returns the nth element of the list.
(: get-nth-element (All (T) (Listof T) Integer -> T))
(define (get-nth-element xs n)
(if (equal? n 1)
(first xs)
(get-nth-element (rest xs) (- n 1))))
;; Takes a list of strings and an integer n and returns the nth element of the list.
(: get-nth ((Listof String) Integer -> String))
(define (get-nth strings n) (get-nth-element strings n))
That book can get really dense really quickly. It DOES appeal to certain types of learners though. So since, you can find the HTML version for free, check it out. I personally suggest "The Little Schemer". It literally starts with Atoms and works its way out. It uses Scheme, which Racket is based on. I highly recommend it.
Forget about the perfect editor setup, idiomatic code and all that fuzz about becoming enlightened. (Common) Lisp is first and foremost a productive, pragmatic language to get things done, so just start hacking.
I am particularly looking to learn a LISP style language. Scheme and Racket caught my interest, given its concise, expressive syntax. Is it advisable to start with Common Lisp first, or go with Scheme/Racket?
Thanks for the tip btw.
They are really different languages with similar syntax.
Scheme is opinionated and wants you to program in a certain way (hence TCO being part of the standard), it's also more static and doesn't want to take over the whole machine like Common Lisp and Smalltalk want.
I started with Scheme but I am no longer my idealistic self so I am partial to Common Lisp since I use it for work and don't mind coding in ugly kitchen sink languages as long as they are fit for production use. Not that Scheme lacks amazing implementations such as Chez, Gambit or Chicken (my favourite) but I would have a harder time building something non trivial in those.
A vote for "Common Lisp [as] the best language to learn programming":
"Between Land of Lisp, David Touretzky's Common Lisp: A Gentle Introduction to Symbolic Computation (really great book for people new to programming, available for free) and The Little LISPer (3rd edition, editions four and up use Scheme) you have three really great resources to get started."
I really like the power and flexibility of Lisps, but I am so much more productive with good(!) statical typesystems.
Looking at both typed racket and now sugar, it doesn't look really good to me. I think I would rather decide to go straight for Haskell/Scala/... or Lisp/Clojure. Maybe it's not really possible to combine both in a good way _yet_, or maybe it's not possible in general. I hope for the former.
27 comments
[ 3.0 ms ] story [ 57.2 ms ] threadCompiler is incomplete but I have written some reasonably complex programs.
Interesting to read for the, very short, compiler.
This format uses S-expressions like lisp, and it's got a stack machine like forth. [1] [2]
I'm a bit surprised something so mainstream ended up being a lispy forth.
[1] https://ph1lter.bitbucket.io/blog/2020-12-03-webasm-forth-wi... [2] https://developer.mozilla.org/en-US/docs/WebAssembly/Underst...
Thanks for reading the post :)
Update 2020-12-07: There was a bug in the macro expansion logic. I've backported the fix to the linked source and explained the bug in the 'mistakes' section.
You may be interested to read this, which talks about a proposal to add additional stack instructions: https://github.com/WebAssembly/design/issues/1381
I am currently working on some of the "future directions" ideas and will post again soon about that.
Do you mean literally the syntax
? Or do you mean the ability to have the type annotation on a separate line from the function implementation itself (rather than e.g. annotating its arguments individually)?In the case of the former you have Hackett (https://lexi-lambda.github.io/hackett/reference-syntactic-fo...) which unfortunately I think isn't seeing too much work on it anymore.
In the latter case something like Typed Clojure may work (https://github.com/clojure/core.typed).
In the Coursera course Programming Languages, I ported some of the first assignments from SML to F# and Typed Racket, and you can see the similarities of type annotations in the very simple examples below.
SML:
F#: Racket:Or will you recommend learning sugar after learning some other lisp?
I'd probably suggest SICP: https://mitpress.mit.edu/sites/default/files/sicp/index.html if you want a "lisp intro"
Forget about the perfect editor setup, idiomatic code and all that fuzz about becoming enlightened. (Common) Lisp is first and foremost a productive, pragmatic language to get things done, so just start hacking.
Scheme is opinionated and wants you to program in a certain way (hence TCO being part of the standard), it's also more static and doesn't want to take over the whole machine like Common Lisp and Smalltalk want.
I started with Scheme but I am no longer my idealistic self so I am partial to Common Lisp since I use it for work and don't mind coding in ugly kitchen sink languages as long as they are fit for production use. Not that Scheme lacks amazing implementations such as Chez, Gambit or Chicken (my favourite) but I would have a harder time building something non trivial in those.
As a counter argument you have https://fare.livejournal.com/188429.html from a seasoned Lisper so YMMV.
Sugar is just a toy. Don't learn it. Maybe you can learn something about common lisp from reading the sugar compiler source code.
I agree with TurboHaskal. I too, learned Scheme first and liked it cos it was simpler/purer etc. than Common Lisp.
When I finally learned Common Lisp, my only regret was that I hadn't learned it earlier.
Common Lisp is not perfect, but it has a single standard. Very important. It's very mature and battle tested.
The people who you'll meet in the Common Lisp community are very smart and capable and you will learn a lot from them. I did.
Learning Scheme won't hurt but I recommend Common Lisp. Great, free compilers, lots of libraries for everything and a great community.
But please, do not learn sugar :)
"Between Land of Lisp, David Touretzky's Common Lisp: A Gentle Introduction to Symbolic Computation (really great book for people new to programming, available for free) and The Little LISPer (3rd edition, editions four and up use Scheme) you have three really great resources to get started."
https://carcaddar.blogspot.com/2011/10/common-lisp-is-best-l...
And here's a link to Shapiro's COMMON LISP: An Interactive Approach:
https://cse.buffalo.edu/~shapiro/Commonlisp/
Looking at both typed racket and now sugar, it doesn't look really good to me. I think I would rather decide to go straight for Haskell/Scala/... or Lisp/Clojure. Maybe it's not really possible to combine both in a good way _yet_, or maybe it's not possible in general. I hope for the former.
[1] https://github.com/carp-lang/Carp
[0]: https://github.com/wolfgangj/bone-lisp