Hacker News new | ask | show | jobs
by mattangriffel 3472 days ago
As someone who teaches coding to beginners for a living (I founded One Month and I teach Python to business students at Columbia University), this language looks really intimidating to beginners.

Maybe Pyret isn't for beginners, and it's intended to teach people who already have some basic knowledge more advanced concepts like functional programming. That's fine.

But to a total beginner, the syntax of Pyret is definitely a step back in terms of readability.

In what world is:

  fun square(n :: Number) -> Number:
    n * n
  end
...easier for a beginner to understand than:

  def square(n):
    return n * n
I get that the intention of this language seems to be to help beginners avoid some of the more common pitfalls that they may run into (ex. unexpected parameters and return values), but it seems like they do it at the expense of the total beginner's ability to understand and keep track of lots of new concepts when they're just starting out.
11 comments

Pyret is inspired from Racket, which starts at step 1 with functional programming. It's not about readability or getting people to learn as fast as possible to write basic code, but to try and teach core program design principles easily and build a solid base within a single semester. The syntax is not as clean as Python, but it offers much more clarity in terms of testing, signatures, and offers a very interesting method of writing loops with map/filter/foldr.

I have a bias here, as I help teach an introductory course using DrRacket, and many of my colleagues are very aware of Pyret, some even helping to develop it. In one semester, however, we have students with a full understanding of recursion, linked lists, many other common data structures, anonymous functions, functions as data, and understanding of map/filter/fold and how to use them. The class is specifically aimed at people who do not have prior programming skills, and works very well in my experience. Yes, it is a lot, but it builds an incredible base, and if taught to build on itself slowly, is actually very minimal conceptually. The optional features in Pyret are probably allowed with that in mind.

One of its weaknesses, arguably, is that it doesn't look like much else out there in common use, since it's a Scheme. This syntax is an attempt to try and make the same ideas translate to other languages easier, such as Python/Java.

> arguably, is that it doesn't look like much else out there in common use, since it's a Scheme.

That is a beauty of Lisp especially Racket. Every thought is explicitly inside a bracket.

I am a self-taught programmer started with Assembly Z80, Pascal etc.. I mostly work with R now a days and I was struggling with R to get to the next level. I picked up a book and learned Racket and the convergence of R and Racket was totally unexpected. I missed all the Scheme influence in R and most R programmer in the past didn't use that part of the language. So as a learner them brackets are golden especially for learning concepts.

If the goal is to teach functional programming with testing and signatures, is the awkward syntax (that isn't really very close to C#, Java, or Python) better than a set of macros on top of typed Racket?

It seems like it'd be easy to define a typedracket-derived #lang where you had to write:

    (define (sum a b) : [-> Integer Integer Integer]
      (where (= (sum 0 1) 1)
             (= (sum 2 2) 4))
      (+ a b))
And make the type signature and where clause non-optional with at least a single test.
I think that's a very valid question. I think Pyret is attempting to reach out to people who may not view Lisp's favorably and still convey many of the valuable concepts. Whether or not it is the right approach or if it will translate properly is yet to be tested.
It's not better [1], it's different. There's Typed Racket for people who want that. But many people suffer from visceral negative reactions when confronted with any kind of parenthetical syntax. Pyret was initially designed for them, and has since added on several of its own innovations.

[1] I, personally, love parenthetical syntax.

The syntax looks really Haskell to me, so it's not that awkward.
Can we stop assuming that only the syntaxes we are accustomed to are the only "readable" options?
This needs to be higher. So many people in these comments claiming that X, Y, Z are "more readable" or "friendlier to beginners" and providing no argument or evidence other than the implication that it's what they are used to because of their personal background.
Whether some is readable is always going to be subject to who's reading it. That's simply how readable/non-readable work. Now you can learn to read new languages (human or machine), but I suspect someone who knows a romance language will find other romance languages for more readable than Chinese. Romance languages share words, alphabets, and many syntactic features. You can draw from an existing body of knowledge and patterns when learning a new romance language. There's a lot less to draw from if you're learning Chinese.

The same applies to programming languages. The fact is most programmers learn popular languages. Languages that deviate from popular languages tend to become less readable.

So the answer is no. If you are accustomed to a syntax, it naturally follows you are most likely going to languages that adopt those syntactic features will initially be more "readable" because things only become readable when you learn how to read them.

However, when you apply your "I know these programming languages and their syntax" bias to evaluating the readability of a teaching language, you're rather missing the point.
Pyret draws from traditional algebra notation, Python, and OCaml/Haskell. If you do not know any of these, you must be a pretty weak programmer. If you do most of these, you ought to be able to recognize almost every part of it. Anyway, the good news is that programming beginners — who don't know any languages — have no real trouble with it, so any difficulties may say more about the reader's blind-spots than about the language itself.
Annotations are optional. This is equally valid:

  fun square(n):
    n * n
  end
Not that different after all! And I say this as a lover of python and significant whitespace, but not having it at first would be easier.
There should be optional syntax that allows:

    fun square(n):
      party in here
    unfun
    // no longer having fun here
Perhaps `unfun` can be incorporated into this:

http://blog.brownplt.org/2014/04/01/var-vs-yar.html

"def" is an abbreviation non-programmers are more likely to understand than "fun".
OK: opinion time. Some folks in this thread don't understand how pedagogy works.

When these people talk about easy-to-learn, they don't mean what a lot of people in this thread mean. Def / fun is such an easy thing that it's a non-issue. Anyone can learn programming language syntax pretty quickly.

It's the semantics that's hard. When you first start learning, the things that actually trip you up and that you can't just look up in a cheatsheet in two seconds are things like: Unexpected behavior, bad error messages, hidden rules, hidden complexity, complicated control flow, code that doesn't do much but must be there anyway, arcane things that you must do to make the compiler happy.

In that way, you don't have to assume that beginners are stupid. A lot of these things happen because languages are badly designed, or because they evolve to have too much cruft over time in an effort to be general purpose and catch up with the times. For learning, this just gets in the way. With better tools, learners can tackle much more complex concepts much quicker. Once those take place, you can introduce the arcane weirdness of other programming languages, and it makes a lot more sense.

You're right! To DEFine a FUNction, you should naturally type `def`, not `fun`. By the way, I tried to define a variable and got

  >>> def x = 3
    File "<stdin>", line 1
      def x = 3
            ^
  SyntaxError: invalid syntax
What's up with that? Is that not also a DEFinition?
Yeah, that should work (well, "def x: 3" should work). In my preferred language it does work.
But that's no fun. ;-)

Seriously, fun is obvious for function to anyone. (also, defun in some other languages fits the bill) In contrast, def doesn't explain what is defined. (See Groovy where it is a real problem or JavaScript where you can use var for everything.)

I remember Apache Groovy's use of the verb def to match the verbs and adverbs of the other statement-level keywords (e.g. switch, if, while, return) instead of a noun like any to match the type names it stands in for (e.g. int, bool, String, null) was, er, discussed at length on their mailing list back around 2005-06. The Nabble interface to those discussions has since been obfuscated by being redirected and embedded within a page from the groovy-lang.org website so I can't easily find a link to those discussions.
> In contrast, def doesn't explain what is defined. (See Groovy where it is a real problem or JavaScript where you can use var for everything.)

Does that matter? I'm used to Scala where `def x = 4` is just as good as `val x = 4` as far as a beginner's concerned.

How dare you suggest non-programmers can't understand fun! XD (I'm only teasing of course.)
The type annotations are optional, so you can write:

    fun square(n):
      n * n
    end
In fact, I believe the major motivation for making the type system optional was to not force beginning students to write types.
In what world is:

  def square(n):
    return n * n
... easier for a beginner to understand than:

  square n = n * n
Is square a function or object/data structure result of operation?

Welcome to the Real World. Please make different entities look different.

Usually when one starts to learn to program already have learned some math. So knows only this notation for funcions: square(x) = x*x

"Return" seems meaningless.

So that is the "real world" function declaration (if this phrase makes any sense for a math notation convention) for a nonprogrammer.

Is that what you mean? Because then I agree...

In the same world is easier to understand for advanced developers.

You know n is a number and the result is a number. You don't need to "type check in your head".

Remember Pascal? Being explicit is good for education and for regular sanity.

P.D: I like python very much, but all the time I'm wondering "ok, what is the meaning of this code, let's find elsewhere so I can remember what is supposed this return"

This also happens to me with F# (type inference is weird: The compiler know, but it hide to me what it know!).

Use IDE which runs type inference like the compiler when that's a problem. Can't do it in Python though.
Programmers use a variety of editors these days. They often don't want to be locked down to one single IDE. So "let the IDE do it" is not a universally satisfying answer either.
Don't fear or hasten to assume no expertise, Pyret is designed by professional educators. Those type annotations are optional, so this is not a fair comparison.
>> Maybe Pyret isn't for beginners, and it's intended to teach people who already have some basic knowledge more advanced concepts like functional programming <<

I often hear people say that functional programming is advanced concept. I think students are able to learn functional programming as their first model of computation, before they are even exposed to Turing machine computing. It's not like you have to first learn C, then some java and only after you become familiar with OO, you have enough knowledge to grasp functions as first class citizens.

Many of our functional programming students are ~12 years old, and have not yet been exposed to any other textual programming language. They handle it just fine. They don't write lambdas, but they do actually use functions-as-values (without fully realizing it). It's really not a big deal, except for people who were taught otherwise and don't realize the fog that permeates their thinking!
The Pyret style much more closely follows the abstract (divorces from any particular PL) analytical, contract-based problem solving approach taught as central to programming and as properly preceding actually writing code in, e.g. How to Design Programs (which uses Racket as the concrete programming language.)

So, for a curriculum based on that basic approach that starts with the analytical methods and then adds concrete programming on top of it, the Pyret approach -- which requires and gives effect to elements of the analytical product that Python would not require and provides no convenient means to clean express that also gives it concrete effect -- is probably both simpler (as the two-way correspondence between code and analysis is better) and more productive.

It's probably not particularly useful to discuss the quality of a pedagogically-focussed language outside of the context of an approach to pedagogy.

You saw one example, misunderstood it, and jumped to various unsubstantiated conclusions from there. So there's not much to reply to here, except to point out that the annotations are optional, and the following is an equally valid way of writing that same function in Pyret:

  fun square(n):
    n * n
  end
[Speaking of beginners and new concepts and so on: they wrote functions in school in math all the time, and didn't write `return` there either.]
The first version looks more like something you'd see in a math book, which is where a non-programmer's notion of what a "function" is would likely come from (assuming they have a notion at all).