We need better languages for introductory computing. A good introductory language makes good compromises between expressiveness and performance, and between simplicity and feature-richness. Pyret is our evolving experiment in this space.
Pyret looks very well designed, but the compiler implementation looks very frustrating. It’s a 4-stage bootstrapping process involving massive compiled JS blobs checked into the source tree. I wonder why it’s not a 2-stage compiler, with a minimal compiler written in JS and the full compiler written in Pyret.
I’ve thought about writing another compiler so that Pyret can be used without the bootstrapping madness.
Are there any weird language corners/features/bugs that a future interpreter/compiler implementor should know about? Things like Python’s descriptor protocol, etc, etc
i’ve daydreamed of exactly that too, though i was envisioning a gradual migration of the existing compiler to bucklescript. not something i could do on my own but if there were people doing it i would love to jump in and help!
a command line interpreter in ocaml would be awesome too.
Following through to the main Pyret description page, I don’t know if this is new to Pyret or half-inched from some amazing promethean functional language I’ve never heard of, but this is one of the best things I’ve come across in a new-to-me language for a very long time:
Functions can end in a where: clause that holds unit tests for the function. These assertions are checked dynamically.
Maybe not awesome for performance but what a boon for function-level correctness without having to dive deep into complex types. Also
you can also write check: blocks at the top level, for general program testing
All-round good thinking about consistency and coherence from the ground up. Rad.
Might be taking contracts from Eiffel/OO languages and/or pattern matching guards from Erlang/Elixir/functional languages. Not sure what the lineage of Pyret is though.
That’s what I thought at first, too. But a look at their example shows that they aren’t contracts/invariants, they’re literally just standard unit tests. The only difference between these and, say, a D unit test, is that these are syntactically tied to the function. This affords you better test failure messages, at least.
That “where: “ clause is kinda neat, and I’ve never seen it before either. Seems like there shouldn’t be any performance impact if the compiler is smart enough.
It’s refreshing to see the rationale for the language laid out so clearly. I like what I see here a lot; they obviously know their stuff when it comes to language design having come from a Racket background, but they aren’t afraid to point out that Racket has a lot of complexity that gets in the way of using it for teaching; the bewildering selection of equality predicates being the best example.
Just because the motivations here are all stemming from the creators of Pyret, I wanted to mention how I discovered Pyret originally.
I’m primarily a Python, JavaScript, and Clojure programmer these days, and Python above most else. I took a course for learning from the classic book, the Structure and Interpretation of Computer Programs (SICP), and for that course, I used Racket, and its implementation of “the SICP dialect of Scheme” (aka #lang sicp). I described my SICP course motivations here.
While in the midst of working through SICP and examples, I stumbled upon “How to Design Programs”, which goes by the acronym HtDP, available freely in HTML here. I never went through that book, but it’s a book that teaches programming using Racket as a kind of “programming language exploration” environment.
Well, it turns out, Brown University has a textbook and course called Programming and Programming Languages, which goes by the acronym PAPL, and is available freely in HTML here. It’s a book inspired by HtDP, but instead of using Racket, which has a Scheme/Lisp style, it uses Pyret, the language discussed in the OP here. Pyret is designed primarily as a teaching language that combines concepts from Python, Scheme, and Racket for teaching code and data abstraction concepts, and PAPL is the book that teaches programming and abstraction concepts with Pyret.
As a Python programmer who even spent some time teaching Python, I was very pleased with Pyret’s design. It really feels like a language designed very much to ease someone into programming, while also making it quite easy to switch to Python as your “production” language after you’ve become comfortable with the concepts. It’s all rather fascinating if you are curious about learning or teaching computing from first principles, and especially so for Python programmers, since the history of Python and its well-regarded code readability stems from the fact that it was inspired by ABC, which was itself originally a teaching language.
BTW, the pyret.org frontpage has some nice examples that give a taste of the language.
I think a major issue with intro CS education is that it is trying to do a couple of orthogonal things -
Make people good programmers
Get people interested and invested in programming
For the former, for someone already hooked and committed to learning how to become a good programmer you can use something like Scheme that allows you to teach deeper concepts easier (e.g. metacircular evaluator), even if Scheme isn’t as used in industry and is harder to use for a hobby project. For the latter, you need something like Javascript, Python, etc. where people who are on the fence about learning programming get to see some cool application from what they have learned quickly (e.g. a webpage, a script that uses some Python library to do something) and are enticed by the idea of learning a marketable skill. Trying to do both things at the same time means at there will be a mismatch with whatever language you choose for at least one of these.
Having written some amount of ruby and python in my life, using colons to start blocks and “end” to end blocks seems sort of warped to me. This is a minor nitpick, of course.
Yes, I tend to agree. In Python, a block statement suffixed by a colon, a line break, and indentation starts a block, and balanced de-indentation ends the block. This is nice because it removes the need for “end sigils”, like the “end” keyword in Pyret. But, at least, the Pyret authors have an elaborated rationale with the opposite perspective: that “end” is a good thing. Here is their explainer:
We believe indentation is critical for readable code, but we don’t want the whitespace of the program to determine its meaning. Rather, the meaning of the program should determine its indentation structure. Indentation becomes just another context-sensitive rule.
Unambiguous syntax (the reason for explicit end delimiters) means you can copy-and-paste code from email or the Web, and its meaning won’t change. Your IDE can help you reindent code without worrying that doing so will change the meaning of the program.
Pyret looks very well designed, but the compiler implementation looks very frustrating. It’s a 4-stage bootstrapping process involving massive compiled JS blobs checked into the source tree. I wonder why it’s not a 2-stage compiler, with a minimal compiler written in JS and the full compiler written in Pyret.
I’ve thought about writing another compiler so that Pyret can be used without the bootstrapping madness.
I work on Pyret. You’re not wrong. I’ve often daydreamed about writing an interpreter, or a compiler in OCaml with bucklescript!
If you ever get around to writing that compiler, our group would love to hear about it. :-)
This is such a small thing but I love how pyret lets you use dashes in identifiers! I’ve never seen this in a non-lisp before, other than forth.
COBOL allows dashes in identifiers. Only a dash surrounded by spaces is interpreted as a minus.
Are there any weird language corners/features/bugs that a future interpreter/compiler implementor should know about? Things like Python’s descriptor protocol, etc, etc
i’ve daydreamed of exactly that too, though i was envisioning a gradual migration of the existing compiler to bucklescript. not something i could do on my own but if there were people doing it i would love to jump in and help!
a command line interpreter in ocaml would be awesome too.
Following through to the main Pyret description page, I don’t know if this is new to Pyret or half-inched from some amazing promethean functional language I’ve never heard of, but this is one of the best things I’ve come across in a new-to-me language for a very long time:
Maybe not awesome for performance but what a boon for function-level correctness without having to dive deep into complex types. Also
All-round good thinking about consistency and coherence from the ground up. Rad.
Might be taking contracts from Eiffel/OO languages and/or pattern matching guards from Erlang/Elixir/functional languages. Not sure what the lineage of Pyret is though.
That’s what I thought at first, too. But a look at their example shows that they aren’t contracts/invariants, they’re literally just standard unit tests. The only difference between these and, say, a D unit test, is that these are syntactically tied to the function. This affords you better test failure messages, at least.
That “where: “ clause is kinda neat, and I’ve never seen it before either. Seems like there shouldn’t be any performance impact if the compiler is smart enough.
I wish they did not use
where
as the keyword. I like howHaksell
uses where to define small local functions, and it fits better there.It’s refreshing to see the rationale for the language laid out so clearly. I like what I see here a lot; they obviously know their stuff when it comes to language design having come from a Racket background, but they aren’t afraid to point out that Racket has a lot of complexity that gets in the way of using it for teaching; the bewildering selection of equality predicates being the best example.
Notice that none of the other languages under the section “Highlights vs. Existing Languages” were released this millennium.
Just because the motivations here are all stemming from the creators of Pyret, I wanted to mention how I discovered Pyret originally.
I’m primarily a Python, JavaScript, and Clojure programmer these days, and Python above most else. I took a course for learning from the classic book, the Structure and Interpretation of Computer Programs (SICP), and for that course, I used Racket, and its implementation of “the SICP dialect of Scheme” (aka
#lang sicp
). I described my SICP course motivations here.While in the midst of working through SICP and examples, I stumbled upon “How to Design Programs”, which goes by the acronym HtDP, available freely in HTML here. I never went through that book, but it’s a book that teaches programming using Racket as a kind of “programming language exploration” environment.
Well, it turns out, Brown University has a textbook and course called Programming and Programming Languages, which goes by the acronym PAPL, and is available freely in HTML here. It’s a book inspired by HtDP, but instead of using Racket, which has a Scheme/Lisp style, it uses Pyret, the language discussed in the OP here. Pyret is designed primarily as a teaching language that combines concepts from Python, Scheme, and Racket for teaching code and data abstraction concepts, and PAPL is the book that teaches programming and abstraction concepts with Pyret.
As a Python programmer who even spent some time teaching Python, I was very pleased with Pyret’s design. It really feels like a language designed very much to ease someone into programming, while also making it quite easy to switch to Python as your “production” language after you’ve become comfortable with the concepts. It’s all rather fascinating if you are curious about learning or teaching computing from first principles, and especially so for Python programmers, since the history of Python and its well-regarded code readability stems from the fact that it was inspired by ABC, which was itself originally a teaching language.
BTW, the pyret.org frontpage has some nice examples that give a taste of the language.
I think a major issue with intro CS education is that it is trying to do a couple of orthogonal things -
For the former, for someone already hooked and committed to learning how to become a good programmer you can use something like Scheme that allows you to teach deeper concepts easier (e.g. metacircular evaluator), even if Scheme isn’t as used in industry and is harder to use for a hobby project. For the latter, you need something like Javascript, Python, etc. where people who are on the fence about learning programming get to see some cool application from what they have learned quickly (e.g. a webpage, a script that uses some Python library to do something) and are enticed by the idea of learning a marketable skill. Trying to do both things at the same time means at there will be a mismatch with whatever language you choose for at least one of these.
They know what they are doing, which is indeed refreshing.
Having written some amount of ruby and python in my life, using colons to start blocks and “end” to end blocks seems sort of warped to me. This is a minor nitpick, of course.
Yes, I tend to agree. In Python, a block statement suffixed by a colon, a line break, and indentation starts a block, and balanced de-indentation ends the block. This is nice because it removes the need for “end sigils”, like the “end” keyword in Pyret. But, at least, the Pyret authors have an elaborated rationale with the opposite perspective: that “end” is a good thing. Here is their explainer: