[HN Gopher] Pyret Programming Language
       ___________________________________________________________________
        
       Pyret Programming Language
        
       Author : kristianp
       Score  : 202 points
       Date   : 2021-08-22 01:27 UTC (21 hours ago)
        
 (HTM) web link (pyret.org)
 (TXT) w3m dump (pyret.org)
        
       | dTal wrote:
       | I was excited that Pyret, which I was previously familiar with as
       | a Racket #lang, had evidently gained enough independence to
       | warrant its own website that does not even mention Racket. What a
       | vindication of the #lang system! Then I read this:
       | 
       | "Ultimately, Racket's #lang facilities, though designed to create
       | new languages--and a great prototyping ground for Pyret--proved
       | to not be quite enough to support a language creation process of
       | the scale of Pyret"
       | 
       | I find this rather sad. The PLT group, dogfooding their flagship
       | product's unique selling point, was not able to achieve their
       | goals and switched to Javascript. I hope that one day it may once
       | again be a Racket #lang.
        
         | srfsrvsr wrote:
         | Is #lang really Racket's USP?
         | 
         | I vaguely get that the idea is an extension of the Unix
         | "shebang" convention to files which define modules. It might be
         | preferable to a system based on file extensions or file
         | associations (it's certainly less brittle). I guess the
         | question is whether it's better than directives of the form
         | "import(lang, file)", in other words, explicitly naming the
         | interpretation language for each file that's imported.
         | Naturally one could set a default so that a plain
         | "import(file)" would do the right thing. A project full of
         | files in extremely heterogenous languages would make make #lang
         | more appealing, but it would also be possible to build some
         | kind of file association system within Racket--personally I
         | would prefer to put the #lang info in the filename or the path
         | than stick it ("intrusively") into the file.
        
           | travisjungroth wrote:
           | I think they were using "#lang system" as a synecdoche[0] for
           | "Racket's language support". Racket's USP is definitely that
           | it's a platform for language design and implementation[1].
           | 
           | On the other hand, I don't think it's a big deal they moved
           | off of Racket. I actually think it's a success story that
           | they were able to build on the platform and then move off.
           | 
           | [0]https://en.wikipedia.org/wiki/Synecdoche [1]https://en.wik
           | ipedia.org/wiki/Racket_(programming_language)
        
             | dTal wrote:
             | I like your positive attitude towards it - when you phrase
             | it like that, it does indeed sound more like a success
             | story. You may have changed my mind!
        
           | dTal wrote:
           | #lang is much more than shebangs. Racket #langs are
           | implemented on top of Racket - they can be nothing more than
           | alternative syntaxes, or they can have different semantics
           | (written in Racket). This has the effect of rendering
           | different Racket #langs interoperable within a project. This
           | is wildly powerful - someone reimplemented Python entirely as
           | a #lang, for instance, which meant that Racket could use
           | (pure) Python libraries directly, and vice versa.
           | 
           | It's an entirely different philosophy, which aims to allow to
           | use "the best tool for the job" even within a project. Need a
           | DSL? Write one!
        
             | adsfsdfdsg wrote:
             | I understand all that. You don't seem to have understood my
             | comment, which was asking questions about the
             | suitability/fitness of the "#lang" mechanism, rather than
             | questioning the idea of polyglot code on top of Racket.
             | 
             | I guess it seems to me like it hasn't been established
             | whether the "#lang" mechanism is a brilliant invention, or
             | something cheesy. My initial reaction is that it seems
             | cheesy.
        
               | dTal wrote:
               | I'm not sure I'm following, then. You think the basic
               | idea of polyglot programming on top of Racket is sound;
               | but that's what #lang does, and is the interesting bit of
               | what we're talking about. The fact that it's specified
               | with a line at the top of the file is a boring
               | implementation detail - albeit the correct decision in my
               | view, since the information about what language a file is
               | written in clearly belongs with that file - exactly the
               | same reason we have shebangs. But it seems like a minor
               | thing to pick on to deem it "not Racket's USP".
        
       | teruakohatu wrote:
       | I really like the in-function documentation and unit like testing
       | in the where clause.
       | 
       | > # this is true
       | 
       | > ((1 / 3) * 3) == 1
       | 
       | This worries me. I know it is true mathamatically, but experience
       | tells me trusting floats is a recipe for disaster. A approximate
       | equal operator is safer.
       | 
       | Floats are such a leaky abstraction it is in my opinion better
       | students know this early on.
        
         | klyrs wrote:
         | The article doesn't really say what's going on under the hood
         | but I'd guess that division of integers makes rationals...
         | 
         | > Pyret has _numbers_ , because we believe an 8GB machine
         | should not limit students to using just 32 bits.
         | 
         | Emphasis mine. WTF, author.
         | 
         | But the Java sample below saying "this is false" implies that
         | floats are a problem that is being avoided. The only reasonable
         | solution is rationals... right?
        
           | adjkant wrote:
           | Yep, this is a project out of the same world as Racket which
           | does a similar thing.
           | 
           | If you go into the editor/REPL
           | (https://code.pyret.org/editor) and enter 1/3, you'll see
           | that it gets rendered as 0.3 repeating (with a bar, not some
           | arbitrary rounding) or if you click on it, directly as 1/3.
        
         | recursive wrote:
         | `1 / 3` doesn't produce a float in pyret.
        
         | skrishnamurthi wrote:
         | You should try it and see what it does when you force it to use
         | floats. You may find it interesting in light of your "leaky
         | abstraction" comment. Pyret is designed precisely to make that
         | point clear.
        
         | agumonkey wrote:
         | it's a lisp descendant it has, most probably, a full numerical
         | tower
        
           | skrishnamurthi wrote:
           | Partial, not as full as Scheme.
        
         | na85 wrote:
         | Many languages treat the construction                  1/3
         | 
         | As a rational type, and do not convert to float unless you
         | cast. Common Lisp comes immediately to mind. Evidently pyret is
         | another.
        
           | tromp wrote:
           | Haskell supports rationals with module Data.Ratio, but uses a
           | slightly different syntax: 1 % 3
        
       | ilyash wrote:
       | I have considered different constructs like "where:" to be placed
       | in code blocks (such as function) when working on Next Generation
       | Shell. I have decided against because these constructs will not
       | be executed at runtime (when the function is called) and
       | therefore I assume it will be at least somewhat confusing.
       | 
       | For tests, NGS has "TEST" keyword which can be placed at
       | beginning of any line. The test is everything till end of that
       | line. I typically place these below functions that they test.
        
       | 8589934591 wrote:
       | A new book which serves as an introduction to CS in Brown
       | university has been released just yesterday. It uses Pyret.
       | 
       | https://dcic-world.org/2021-08-21/index.html
       | 
       | PAPL - https://papl.cs.brown.edu/2020/ is an older version of the
       | current book.
        
       | replyifuagree wrote:
       | Am I the only one who came to this thread looking for good code
       | pirate jokes?
        
       | eterevsky wrote:
       | > # this is true > ((1 / 3) * 3) == 1
       | 
       | This is a slippery slope. Early versions of Dart tried to use
       | rational numbers by default, but then it was cancelled because
       | denominator size can grow exponentially.
       | 
       | Also, I seriously doubt you can make a language that will
       | correctly resolve checks like this one:
       | 
       | sin(pi / 6) == 1 / 2
        
         | mscharrer wrote:
         | I ran into this issue once while trying to render the
         | Mandelbrot set while learning Haskell. It defaulted to a
         | rational type based on two bignum integers with unlimited
         | precision.
         | 
         | With every Mandelbrot iteration* the integers doubled in size,
         | producing exponential complexity. With 100 iterations this
         | essentially means that the program never completes and even
         | runs out of memory at some point.
         | 
         | The newbie-friendly feature turned out to be not so friendly.
         | 
         | * complex z_{n+1} = z_n^2 + c
        
         | skrishnamurthi wrote:
         | I've used rationals by default in Racket/Scheme for literally
         | 3+ _decades_ now. It 's fine. Dart is trying to be an
         | industrial-strength language. We're trying to create an awesome
         | initial programming experience. To the beginner, those
         | denominators are nowhere near as much of a problem as "numbers"
         | that don't make sense.
         | 
         | But we draw limits. Did you try the `sin(pi / 6)` example?
         | You'll find that Pyret produces a rather interesting result
         | that is also instructive. (Hint: it will produce neither true
         | nor false.)
        
           | IshKebab wrote:
           | I'm a bit dubious that magic stuff like this really makes
           | anything easier. It's like JavaScript's truthiness and type
           | coersion. It's trying to be friendly and work most of the
           | time, but in reality it is _more_ complex because now you
           | have to remember a whole set of rules about how exactly the
           | magic behaves.
        
             | justinpombrio wrote:
             | Waaaay less magic than Javascript. Looks like the rules are
             | described here. Two kinds of numbers: exact and rough.
             | Unless you use trig functions it will all be exact.
             | https://www.pyret.org/docs/latest/numbers.html
             | 
             | Fun fact about Javascript: there are string and number
             | constants x, y, and z, such that `x < y` and `y < z` and `z
             | < x`. No NaN shenanigans, just regular small strings and
             | numbers. Hint: it involves a string containing digits that
             | starts with "0", thus sometimes getting implicitly coerced
             | to octal.
             | 
             | Think about what this means for sorting!
        
             | epidemian wrote:
             | My guess is that you didn't try @skrishnamurthi suggestion:
             | 
             | > Did you try the `sin(pi / 6)` example? You'll find that
             | Pyret produces a rather interesting result that is also
             | instructive.
             | 
             | The result of this doesn't feel like magic and doesn't
             | resemble "JavaScript's truthiness and type coersion" at all
             | IMO.
             | 
             | Here's a live code editor where you can try it out:
             | https://code.pyret.org/editor
             | 
             | I found it to be a very refreshing and intuitively-guiding
             | experience :)
             | 
             | ---
             | 
             | Spoiler alert!
             | 
             | So, fist i had to find how to access pi and sin(), which
             | was simple enough googling for documentation. Typing `num-
             | sin(PI / 6)` on he editor already gives an interesting
             | result:                 ~0.49999999999999994
             | 
             | That ~ there looks suspicious!
             | 
             | Then i tried `num-sin(PI / 6) == 1 / 2`, which seems to be
             | syntactically invalid and yields an _awesome_ error
             | message:                 Reading this expression errored:
             | num-sin(PI / 6) == 1 / 2              The == and /
             | operations are at the same grouping level. Add parentheses
             | to group the operations, and make the order of operations
             | clear.
             | 
             | Kudos to the Pyret team for such a nice error message!
             | 
             | So finally, adding those missing parens, `num-sin(PI / 6)
             | == (1 / 2)`, yields another informative and useful error
             | message:                 Attempted to compare a Roughnum to
             | an Exactnum for equality, which is not allowed:
             | The left side was:              ~0.49999999999999994
             | The right side was:              0.5              Consider
             | using the within function to compare them instead.
             | 
             | All in all, i'm very impressed with the clarity and
             | approachability of the language. Thanks @skrishnamurthi for
             | the suggestion of trying this out! :D
        
         | empressplay wrote:
         | Really? Even our Logo interpreter successfully resolves that
         | one (although you have to use radsin instead of sin because our
         | sin works in degrees)
        
         | lifthrasiir wrote:
         | > Early versions of Dart tried to use rational numbers by
         | default, but then it was cancelled because denominator size can
         | grow exponentially.
         | 
         | While I'm generally in favor of rational numbers as a default
         | and believe that its "danger" is no different from that of big
         | integers, there is some truth in this because Guido van Rossum
         | of the Python fame has said the same thing [1]. It seems that
         | you need some adjustments if you are already familiar to
         | languages where rational numbers are not default.
         | 
         | [1] https://python-history.blogspot.com/2009/03/problem-with-
         | int...
        
         | 0-_-0 wrote:
         | The Wolfram language successfully resolves it:
         | 
         | https://www.wolframalpha.com/input/?i=sin%28pi+%2F+6%29+%3D%...
        
           | mscharrer wrote:
           | Wolfram works with the full mathematical expression tree. It
           | works very well in practice but the equality test is
           | undecidable in general.
        
           | eterevsky wrote:
           | Yes, I should have written "practical programming language".
           | It definitely possible to resolve many equations like this
           | (though not all of them), but is quite a slow process, which
           | is ok for a math system like Mathematica, but not for a real-
           | life programming language.
        
             | lolinder wrote:
             | "Real-life programming language" or "practical programming
             | language" assumes that there's only one acceptable set of
             | trade-offs for all "real-life" or "practical" problems. I
             | suspect that what you actually meant was "a programming
             | language designed to create industrial-strength consumer or
             | business software".
             | 
             | As one of the maintainers has noted repeatedly on this
             | thread, Pyret is a "real-life programming language" whose
             | purpose is educational. Mathematica is a "real-life
             | programming language" whose purpose is solving math
             | equations. Performance isn't much of an issue in either
             | case, so it's a perfectly acceptable trade-off.
             | 
             | That these languages weren't designed with your use case in
             | mind doesn't make them illegitimate or inferior languages.
        
       | da39a3ee wrote:
       | It seems like a bad idea to use the same "where" syntax for
       | definitions and test cases, especially since a major aim of this
       | is education.
        
       | cormacrelf wrote:
       | It seems pretty bad to have kebab-case identifiers in a language
       | that also has an infix subtraction operator -. The only languages
       | I know that allow kebab-case idents are lisps, where subtraction
       | is (- prefix notation). From the examples:
       | lam(actual): num-abs(actual - target) < delta end
       | 
       | This is a new, even worse kind of "whitespace significance" than
       | indentation. Is it a function called `num-abs` or a variable
       | `num` minus `abs(actual - target)`? I can't tell if the language
       | would allow `actual-target` as subtraction.
        
         | cabalamat wrote:
         | > It seems pretty bad to have kebab-case identifiers in a
         | language that also has an infix subtraction operator -.
         | 
         | Indeed. What's wrong with using _ in identifiers?
        
           | scns wrote:
           | > Indeed. What's wrong with using _ in identifiers?
           | 
           | Nothing wrong with it. It is usually easier to type '-'
           | though. Use in when naming scripts and files for the same
           | reason. Ergonomics matter IMHO.
        
         | [deleted]
        
         | nostrademons wrote:
         | Dylan had kebab-case idents and infix operators. It worked okay
         | because you have to separate infix operators with a space
         | anyway; omitting it is a syntax error.
         | 
         | In practice I doubt this would trip me up because every coding
         | standard I've worked with has mandated spaces around infix
         | operators. I suppose it might be a lot more confusing if you're
         | used to coding standards that allow you to omit them, but my
         | understanding is that's a minority.
        
           | cormacrelf wrote:
           | Maybe it would be okay with syntax highlighting and a
           | careerful of code formatting muscle memory, but how would
           | that fare in an educational context?
           | 
           | > "Pyret is a programming language designed to serve as an
           | outstanding choice for programming education"
        
             | skrishnamurthi wrote:
             | It's been working great, actually.
             | 
             | https://news.ycombinator.com/item?id=28265117
        
             | chowells wrote:
             | Only having one correct way to do something with very
             | simple rules (always put whitespace around operators) is
             | easy for students. It's when the rules are complicated with
             | exceptions and multiple correct ways that things get hard
             | to learn.
        
           | justinpombrio wrote:
           | Same thing in Pyret, it's a syntax error to not put a space
           | around infix operators.
        
         | DonaldPShimoda wrote:
         | Always requiring whitespace around infix operators is, in my
         | opinion, _easier_ to explain to people than  "you can do
         | whatever you want with the whitespace." It's consistent and
         | regular. I don't think it's as much of an issue as you're
         | making it out.
         | 
         | Pyret is the result of decades of research in computer science
         | education, helmed by Shriram Krishnamurthi, who was one of the
         | original members of the Racket project (itself a language
         | designed for CS education in the '90s, a descendant of Scheme
         | with kebab case and prefix notation). The full list of authors
         | of Pyret is lengthy, but includes a number of well-established
         | researchers in the PL and CSed communities. Knowing who they
         | are, I would happily assume that they spent plenty of time
         | debating this exact issue of mixing kebab case with infix
         | subtraction, and either decided the benefits were worth the
         | cost or else decided that the cost was practically nonexistent.
         | 
         | In any case, I trust their decisions better than those of
         | someone who glanced at the website only long enough to inform a
         | condescending (and highly superficial) comment on Hacker News.
        
           | cabalamat wrote:
           | > Always requiring whitespace around infix operators is, in
           | my opinion, easier to explain to people than "you can do
           | whatever you want with the whitespace."
           | 
           | It might be easier to explain, but it also makes the code
           | look ugly. Consider the expressions:                   a := b
           | + c*d         if e > f-g then ...
           | 
           | Here the * and - are more tighly bound than the + or >, and
           | I'm using the whitespace to make that obvious.
        
             | skrishnamurthi wrote:
             | But if you write instead                 a := b+c * d
             | 
             | you aren't going to get an error. You're just going to get
             | awfully surprising behavior, because you may think you were
             | expressing one precedence with the spaces but the language
             | has its own mind and doesn't care.
             | 
             | In contrast, Pyret doesn't bind anything more tightly than
             | anything else. You parenthesize to make your intent clear.
             | 
             | If your expression gets too large, you should consider
             | breaking it down with names for the intermediates. That
             | will improve its readability by others anyway.
        
               | psykotic wrote:
               | A space-aware syntax can allow optional spacing around
               | operators but make it an error if it does not respect the
               | precedence hierarchy or is deemed inconsistent by other
               | rules.
        
               | zem wrote:
               | I believe fortress did that.
        
             | scns wrote:
             | Beauty lies in the eye of the beholder, ie aesthetics are
             | subjective. For me, using proximity instead of parentheses
             | to signify grouping would raise an eyebrow. I'd make an
             | exception for cases of base*exponent, i think Python has
             | it?
        
               | cabalamat wrote:
               | > Beauty lies in the eye of the beholder, ie aesthetics
               | are subjective.
               | 
               | Then allow everyone to do things according to their own
               | aesthetics.
        
               | scns wrote:
               | Sure. In math education i learned to signify grouping
               | with parens and in this case i would favour
               | function/consistency over form/typing efficiency.
        
               | verdagon wrote:
               | I personally appreciate when languages have a consistent
               | style. I think on the whole it helps readability more
               | than it hurts.
               | 
               | We're enforcing whitespace around infix operators in
               | Vale, and it's working pretty well. It's also enabling us
               | to use <> for generics with no ambiguity =)
        
               | scns wrote:
               | Need to reply to myself for correction since it is to
               | late to edit.
               | 
               | It should say base*exponent.
               | 
               | I think other languages use base^exponent, which would be
               | fine with me too.
        
           | xpe wrote:
           | > Pyret is the result of decades of research in computer
           | science education, helmed by Shriram Krishnamurthi, who was
           | one of the original members of the Racket project (itself a
           | language designed for CS education in the '90s, a descendant
           | of Scheme with kebab case and prefix notation). The full list
           | of authors of Pyret is lengthy, but includes a number of
           | well-established researchers in the PL and CSed communities.
           | 
           | On one hand, this historical context is relevant. Thanks for
           | sharing it.
           | 
           | On the other hand, when this section is taken in context with
           | with the following sentence...
           | 
           | > Knowing who they are, I would happily assume that they
           | spent plenty of time debating this exact issue of mixing
           | kebab case with infix subtraction, and either decided the
           | benefits were worth the cost or else decided that the cost
           | was practically nonexistent.
           | 
           | ...it looks the fallacy of appealing to authority.
           | 
           | Many people like to debate the ideas and tradeoffs, not the
           | credentials of people involved.
        
           | xpe wrote:
           | > Knowing who they are, I would happily assume that they
           | spent plenty of time debating this exact issue of mixing
           | kebab case with infix subtraction, and either decided the
           | benefits were worth the cost or else decided that the cost
           | was practically nonexistent.
           | 
           | We don't need to assume when we can search. I did a few
           | minutes of searching and found the following:
           | 
           | https://groups.google.com/g/pyret-
           | discuss/c/rPe7gYBLdPs/m/3O...
           | 
           | Shiriam K. wrote in 2013:
           | 
           | > I have tried just about every possible experiment to stay
           | closer to Lisp, including even the one you have in Wart. None
           | of them scaled well _for me_. Ultimately, also, I am totally
           | unconvinced about the idea of having an identifier named e^i
           | _pi-1 for anything other than cute illustration purposes.
           | Since_ surface* syntax is designed for humans, I think a
           | compromise between expressiveness, readability, and
           | predictability is a good way to go.
           | 
           | (This is just one comment, I'm not saying that is captures
           | the full thinking and discussion around these syntax
           | decisions.)
        
             | cormacrelf wrote:
             | It only makes more sense when you do look at the
             | background, so thanks for the link. They're lisp folks.
             | They use kebab-case. I completely get it. It may be the
             | product of decades of research, but it is also the product
             | of default choices and comfort for the people who wrote it.
             | ALL programs have an element of this: I write Rust and you
             | can tell without looking when some tool is written in it --
             | TOML config? Apache-2.0/MIT dual-licensed? Few such
             | decisions have no downsides, and yet exceptions are rare.
             | 
             | It takes a lot to make a choice for reasons other than your
             | own familiarity. From the linked thread, they clearly
             | agonized over this. Apparently they talked themselves down
             | from the usual Lisp ultra-permissiveness on idents, so good
             | on them -- but it was still explicitly a compromise between
             | their comfort and the aims of the project.
             | 
             | There is an obvious and very good reason why the number of
             | languages that do this can be counted on one hand. The
             | authors know that. It is a problem they decided to accept
             | because it was the default for them, and they "just
             | couldn't give up on how pleasing hyphens in identifiers are
             | to the eye and the shift-finger", and then mitigated it via
             | other whitespace changes. They were content when
             | "Anecdotally, no one in our courses ha[d] complained". I
             | disagree with it. I find it really hard to read. I guess I
             | am used to other languages, but so is everyone who has
             | dabbled in python, likely writing primarily numeric code
             | for their stats/bio/physics courses.
             | 
             | Consider me a student reporting it as a problem. Consider
             | the 2013 thread a student reporting it as a problem as
             | well. How about that?
             | 
             | I'll finish with a quote from Krishnamurthi himself:
             | "Saying 'add spaces around binops' is easy to learn,
             | recognize, and implement."
             | 
             | Does this not speak for itself?                   fun
             | subtract(a, b):           a-b         end
             | >>> The identifier a-b is unbound:
             | definitions://:3:2-3:5                  4 | a-b
             | It is used but not previously defined.
             | 
             | Edit: I dug up an old thread from the guy @estebank who
             | makes all the amazing Rust error messages, responding to a
             | paper of Krishnamurthi's that argues, true to form, that
             | you shouldn't ever actually "Say 'add spaces around
             | binops'"
             | (https://twitter.com/ekuber/status/1140791186858266624).
             | The paper itself is an interesting read, particularly the
             | interviews where beginners don't have the vocabulary to
             | decipher error messages. But I think Esteban is right.
        
               | skrishnamurthi wrote:
               | I understand where you're coming from. Feedback and
               | engagement noted and appreciated.
               | 
               | But I stand by my remarks from 2013 in 2021. I've now had
               | well over 1000 students go through Pyret (in addition to
               | tens of thousands elsewhere). We've also spent hours and
               | hours literally watching new learners work with the
               | language. I can assure you that of the many, many, many
               | issues that have percolated up to us, spaces-around-
               | binops has _literally not a single time_ been one. If
               | anything, when people write that and we say  "just put
               | spaces around the `-`", the response is, "Oh, okay", and
               | people move on.
               | 
               | So, we feel very good about this decision. And I,
               | personally, actually really like how it makes code read.
        
               | cormacrelf wrote:
               | Hey, thanks for the reply. The discussion has been
               | centred on explaining why you have to type the spaces,
               | but I never really cared about that -- my problem was
               | with reading. That's my fault, the usual complaint about
               | whitespace sensitivity is about having to type it, and
               | this is different. I'm talking mixed kebab-idents and
               | really any math operators in the same expression.
               | Unrealistic example but: `(n-1 + n-2) / (n-1 - n-2)`. We
               | may naturally differ on that through familiarity, but it
               | really does get my brain stuck. It doesn't surprise me at
               | all that the mechanics of adding spaces were so easy to
               | learn, but I'm not totally convinced you would have
               | received explicit feedback on readability from students
               | who don't have much to compare to. On the flipside, if
               | you don't get feedback on reading tricky numeric
               | expressions, then they don't care, it doesn't come up for
               | beginners as they're not optimising sqrt routines, and it
               | doesn't matter to a language made for them. I think
               | that's the end of the road.
               | 
               | On the binops, it may be that forcing whitespace around
               | them is a good idea even for a language without kebab-
               | idents, and perhaps the risk you took there was worth it
               | to find that out. I could get around a world in which C's
               | `a & b` and `&ptr` were completely incompatible. (I'm
               | sure you could find a CVE or two for that one.) Heck,
               | every code formatter out there does it. Compared to some
               | suggestions around here and apparently back in 2013 as
               | well to ditch BODMAS, the one bit of math that everyone
               | on the planet learns in school, in favour of whitespace-
               | sensitive precedence... goodness me. Give me forced
               | spaces around binops any day.
        
               | scns wrote:
               | That could be fixed by checking the identifier for valid
               | operators and offer: "Did you mean a - b?"
        
               | cormacrelf wrote:
               | It seems obvious now, but that's not low hanging fruit,
               | and even when you think to do it, it's not easy to do. It
               | took and is still taking real ingenuity and hard work
               | from Rust folks to do. Their syntax trees are insane,
               | they carry so much information around to make these kinds
               | of messages possible. Every source of ambiguity in intent
               | adds to the problem. Making binops work only with
               | whitespace is an easy change to the parser; telling
               | people as you look over their shoulder is also easy.
               | Producing this error message when it is valid syntax and
               | means something else is a different beast entirely. For a
               | general purpose language I just wouldn't recommend it
               | when you have an easy choice available to avoid the
               | ambiguity in intent. It will save so much work if you
               | aspire to have better errors.
        
           | Ericson2314 wrote:
           | Yes not requiring spaces around infix operators is terrible
           | even when there is no ambiguity. Frankly, everything about
           | programs-as-text is terrible for beginners, but this softens
           | the blow.
        
             | chakkepolja wrote:
             | I disagree that programs-as-text is bad idea for beginers.
             | Anyone with a bit of abstract thinking can understand
             | program as text just like how they can understand a multi
             | step mathematical operation.
        
               | Ericson2314 wrote:
               | I'm no expert on education, but having been a TA and
               | helped out a few people since, I repeatedly see text
               | getting in the way of everything else.
               | 
               | Beginners often find _both_ the things you are saying
               | some what hard.
               | 
               | First, note that there is reading vs editing. Perhaps in
               | grade school people learn to parse large expressions
               | (though I find that people generally are not prepared
               | well, because grade school expressions are too small).
               | But editing code and keeping track of what changes you
               | made --- essential to debug your first programs --- is
               | much more new to people who are used to just rewriting a
               | few short algebra expresions with pencils. It's _then_ ,
               | when the beginner is most mentally taxed, that the syntax
               | errors creep in --- and further interrupt their thinking
               | process.
               | 
               | Hopefully we can agree the second challenge is completely
               | fundamental to the field, while the first however is just
               | an artifact of the way things are implemented today.
               | Well, based on the above scenario and others I repeated
               | see the cognitive burden of the first interrupting the
               | second, and so student waste effort and loose focus over
               | "easy stupid text syntax", and therefore long delay
               | mastery of trees, term rewriting and substitution in
               | particular, etc.
        
           | xpe wrote:
           | > In any case, I trust their decisions better than those of
           | someone who glanced at the website only long enough to inform
           | a condescending (and highly superficial) comment on Hacker
           | News.
           | 
           | I didn't interpret it as condescending.
           | 
           | > (and highly superficial)
           | 
           | I didn't interpret it as highly superficial. Comments about
           | the appearance (including whitespace, kebab-case, and infix
           | operators) of a language are fair game, particularly if it is
           | intended for teaching.
        
         | darrenf wrote:
         | Raku has kebab-case as well as infix subtraction. Sigils
         | disambiguate when the operands are variables ($foo-$bar), and
         | callables must be made explicit:                   sub foo-bar
         | { 10 }         sub bar-foo { 7 }         say foo-bar-bar-foo; #
         | Undeclared routine error         say foo-bar()-bar-foo; # 3
        
           | lizmat wrote:
           | Or just do:                   say foo-bar - bar-foo;
           | 
           | which would improve readability as well!
        
         | runarberg wrote:
         | In mathup[1] I actually use whitespace around infix operators
         | to group expressions. E.g. `1 + 2/3 + 4` is _not_ the same as
         | `1+2  / 3+4`. I find this leads to a much cleaner expressions.
         | 
         | When you are designing your own language, you can make these
         | choices. The author of Pyret obviously thought that clearly
         | named identifiers were worth it.
         | 
         | 1. https://runarberg.github.io/mathup/
        
       | satyanash wrote:
       | The ruby comparison is unfair:                   o = Object.new
       | def o.my_method(x)           self.y + x         end         def
       | o.y           10         end         o.my_method(5) == 15 # true
       | method_as_fun = o.my_method         # Wrong number of arguments,
       | 0 for 1
       | 
       | The last line is actually doing: method_as_fun = o.my_method()
       | 
       | Which should make the error message obvious. Ruby makes this
       | syntax optional for readability purposes, which becomes obvious
       | once you start going through real world ruby code.
        
         | catwell wrote:
         | Yes, that would be:                   method =
         | o.method(:my_method)         method.call(5)         # or
         | method[5], or method.(5)
         | 
         | If you really want a "function" that you can call with parens:
         | Kernel.define_method(:method_as_fun, &method)
         | 
         | (Definitely don't do that last bit in a real project...)
        
           | jonnytran wrote:
           | And before someone criticizes Ruby for being inconsistent in
           | how the method is called, Ruby isn't a callable oriented
           | language [1]. The common case is calling methods, so the fact
           | that you need to say `.call(5)` both makes it more consistent
           | and makes real code more concise, especially when making DSLs
           | where chaining is really useful.
           | 
           | 1: https://yehudakatz.com/2010/02/21/ruby-is-not-a-callable-
           | ori...
        
         | danwills wrote:
         | I think if you put more newlines in your code example (at least
         | two per code-line) it might come through the HN formatting
         | thing better?
        
         | lluu wrote:
         | The way to do the last bit in Ruby is:
         | method_as_fun = o.method(:my_method)
         | method_as_fun.call(5) # 15
        
       | trombonechamp wrote:
       | I love this. I think people often underestimate the value of
       | dynamic runtime checks. For certain applications, e.g. many types
       | of scientific/exploratory software, dynamic checks and static
       | checkcs have nearly identical utility. But static checks can get
       | really tricky to work with as a developer.
       | 
       | I built a library for doing modular runtime verification in
       | Python (https://github.com/mwshinn/paranoidscientist) and
       | evaluated it for scientific software. In the end, it was pretty
       | effective, but not perfect, and there are some major changes I
       | would make if I were to do this again. One problem was that some
       | of the most important cases to check were important _because_
       | they were difficult to check. (E.g. some function arguments
       | change the meaning other arguments - this is extremely common in
       | major frameworks like numpy /scipy.) By contrast, the flashiest
       | feature in my package was runtime checking of hyperproperties
       | (i.e. checking properties like monotonicity or concavity that
       | depend on relationships between multiple executions of the
       | function), but this was rarely used in practice.
       | 
       | The two most common criticisms I hear about runtime checking are
       | (a) it is just an assert statement under the hood, and (b) the
       | performance hit is unacceptable and the only solution is static
       | checks. Regarding (a), sure, they may reduce to assert
       | statements, but most idioms in programming also "reduce to
       | something under the hood". The question is whether dynamically-
       | checked (refinement) types/predicates are a useful abstraction,
       | and in my experience, yes they are. Regarding (b), you probably
       | don't want to use runtime checks on software intended to be run
       | primarily by people other than the developers. But many classes
       | of problems, software is written as a means of discovery rather
       | than as a tool for someone else to accomplish a particular task.
       | For these problems, runtime checks and static checks are
       | approximately equally useful. Static checks are nice to avoid
       | because they can get you into deep water really quickly, so their
       | scope can be quite limited. Also, people tend to overestimate the
       | performance penalty of dynamic checks. Even complex checks often
       | incur no more than a 10% performance penalty.
        
         | odipar wrote:
         | hey, I like your work on Paranoid Scientist. I've never come
         | across hyper-properties: is this something you invented?
         | 
         | Regarding hyper-properties: I assume they only work on
         | immutable data values, otherwise it would be hard to manage
         | historical objects so that they can be part of any of the
         | predicates.
         | 
         | I'm working on a similar project that you may find interesting:
         | https://odipar.github.io/manikin/. I may want to include hyper-
         | properties in future releases.
         | 
         | edit: found this on hyperproperties:
         | https://lamport.azurewebsites.net/pubs/hyper2.pdf
        
           | trombonechamp wrote:
           | Glad you like Paranoid Scientist, and thanks for the link to
           | your project!
           | 
           | Yes, you're right that it only works on immutable data types.
           | At first I had implemented something which copies the object,
           | but this used way too much ram and ended up being quite buggy
           | with a lot of edge cases.
           | 
           | I didn't invent the term hyperproperties (sadly). If you do
           | end up implementing hyperproperties in runtime checks, you'll
           | definitely want to look into to doing a statistical approach.
           | The key to making this work is reservoir sampling
           | (https://en.wikipedia.org/wiki/Reservoir_sampling) - there
           | are some more details of how I did this in the Paranoid
           | Scientist paper (https://arxiv.org/abs/1909.00427).
        
           | still_grokking wrote:
           | > https://lamport.azurewebsites.net/pubs/hyper2.pdf
           | 
           | What the parent post talks about is not even close what is
           | described in that PDF above.
           | 
           | "Proving" (or better verifying) stuff at runtime is trivial
           | as it's only some asserts at the end.
           | 
           | Analyzing the properties of programs before you run them is
           | in an entire different league OTOH.
        
       | Maksadbek wrote:
       | The syntax is pretty much like Python and ruby: "end" to declare
       | end of block statements and colon to start a block statement. But
       | why to use "fun" to declare a function when "def" could be used.
       | 
       | The same in other languages: function, func, fun, fn, etc.
        
         | Okkef wrote:
         | python doesn't use end. To be honest, as a python programmemr
         | the syntax looks quite alien.
        
         | skrishnamurthi wrote:
         | Because `def` suggests there is only one kind of thing we're
         | defining (functions), when we could be defining any number of
         | things: functions, type aliases, algebraic datatypes, tests,
         | etc. So we use `fun` for functions, and different keywords
         | (e.g., `examples` for examples) for other things. You should
         | really be questioning why `def` was used for functions.
        
         | Mikeb85 wrote:
         | Lol the syntax is basically Ocaml with a tad less noise.
        
         | scns wrote:
         | Maybe because it should be fun to use? NSI. I prefer fun to fn
         | and func, because it aligns nicely with four spaces a tab
         | formatting.
        
       | bayesian_horse wrote:
       | My criticism is that this language is very similar to Python and
       | might very well confuse students who ultimately have to switch to
       | Python or other languages.
        
         | AlphaSite wrote:
         | Honestly this looks much closer to ruby than Python, implicit
         | returns etc are very unpythonic, it's not white space
         | sensitive, etc.
        
           | keithalewis wrote:
           | If you only know python...
        
         | aranchelk wrote:
         | To me it looks a lot more like Haskell than anything, e.g. ::
         | for type signatures, sum types, pattern matches, etc.
         | 
         | And some Ruby with the end keyword to close blocks.
        
         | scns wrote:
         | Students switching from this to a "real world language" would
         | be disappointed if it does not have Algebraic Data Types,
         | pretty sure about this. Once you learned about them in SML,
         | OCaml, Haskell or one of their descendants, which include
         | Pyret, Elm, ReasonML/ReScript, Rust and Purescript, you feel
         | lucky if you can use Kotlin and approximate them with sealed
         | classes. We will see, maybe C++, Java and C# add them in the
         | next 5 years.
        
           | gsliepen wrote:
           | C++17 added std::variant
           | (https://en.cppreference.com/w/cpp/utility/variant) and other
           | types so algebraic data types are now officially part of the
           | standard. Of course, it's not as compact to write as in
           | Pyret, especially since there's no pattern matching switch
           | statement (yet).
        
             | mlazos wrote:
             | they do have the godforsaken visit function which requires
             | you to write the lambda syntax for each variant type, I end
             | up writing chained if's 99% of the time because it's
             | clearer.
        
               | chakkepolja wrote:
               | There's another way using switch if I recall properly.
               | 
               | That said I don't like C++'s library additions just to
               | stay modern. They are not expressive, increase build
               | times, make debug builds slower and can fail compiler
               | optimizers.
        
       | gigatexal wrote:
       | I like the idea of the where clause to include tests.
        
         | xpe wrote:
         | I don't care for the name "where" since it makes me think that
         | is is a place to define bindings, like Haskell. I would prefer
         | a term like "expect" or "tests".
        
           | skrishnamurthi wrote:
           | It doesn't read fluidly. We care a lot about how our programs
           | are verbalized.
           | 
           | We were well aware of the Haskell use, but most of our users
           | have not seen or even heard of Haskell before. So that's not
           | a real problem here.
           | 
           | People who don't have Haskell experience find it utterly
           | unsurprising that what follows `where` are the
           | examples/tests. So I think your expectation is being set
           | overly by your Haskell experience.
        
       | dang wrote:
       | Some past related threads:
       | 
       |  _Pyret - A language exploring scripting and functional
       | programming_ - https://news.ycombinator.com/item?id=13185759 -
       | Dec 2016 (267 comments)
       | 
       |  _A Case for the Pyret Programming Language_ -
       | https://news.ycombinator.com/item?id=11986977 - June 2016 (37
       | comments)
       | 
       |  _Start Coding in Pyret_ -
       | https://news.ycombinator.com/item?id=9070834 - Feb 2015 (22
       | comments)
       | 
       |  _Pyret: A new programming language from the creators of Racket_
       | - https://news.ycombinator.com/item?id=6701688 - Nov 2013 (283
       | comments)
        
       | cabalamat wrote:
       | Overall this looks quite nice. I like the way types can be
       | defined but if they are not they can be anything.
       | 
       | Are these types checked anywhere? I think they should be checked
       | at compile-time wherever possible, and optionally at run time too
       | (I say optionally as the checks might make it slow, so they could
       | be checked in development but perhaps not in production).
        
         | skrishnamurthi wrote:
         | They are indeed checked at compile-time if you use the optional
         | type checker. It's not on by default because there are still a
         | few odd corner-case bugs in it. But the Run button remembers
         | which state you are in, so once you switch to using the type-
         | checker, you'll always use it unless you stop using it.
         | 
         | What it _should_ do is a decision that should be made by the
         | individual curriculum /instructor.
        
         | justinpombrio wrote:
         | IIRC, they're checked at run-time but not compile-time. And to
         | avoid the speed issue (you're right: it really can get really
         | slow), it only checks the top-level type. E.g. `List<Number>`
         | just checks that it's a list.
        
           | cabalamat wrote:
           | > they're checked at run-time but not compile-time
           | 
           | Do they intend to add this? I think it would make a big
           | difference. It would make thje language more like Haskell,
           | where lots of bugs would be caught at compile time.
           | 
           | > it only checks the top-level type. E.g. `List<Number>` just
           | checks that it's a list.
           | 
           | That's fair enough because otherwise it might have to go
           | though potentially very big data structures.
           | 
           | Maybe there could be a command `strict_check(aDataStructure)`
           | which would only get executed when type checking is on and
           | would recurse into a data structure checking everything.
        
             | scns wrote:
             | It is used to to teach children. Spoken the name sounds
             | like pirate. No snark intended.
        
               | cabalamat wrote:
               | I'm not sure if this was intended as a reply to my
               | comment.
               | 
               | In any case, I would suggest that a language be powerful
               | and simple enough that it can do a wide range of tasks
               | including teaching children, GUI apps, web apps, AI
               | research, scripting, etc. Python does this and Pyret
               | should aspire to do it too.
        
               | scns wrote:
               | It totally was. Type checking is being worked on, they
               | were not happy with the performance of their first
               | implementation.
        
       | bialpio wrote:
       | I like the idea of attaching tests to the function itself -
       | oftentimes I'm finding myself combing through the unit tests for
       | various components to understand the expectations around how they
       | are meant to be used (especially when they are not documented
       | well enough), I feel this approach could help in this aspect (and
       | also with adding new test cases that could have been missed).
        
         | mdew wrote:
         | And in python you can use doctests (tests inside de docstrings
         | of functions)
        
           | bialpio wrote:
           | That's also pretty nice, although elevating those tests to be
           | first-class-citizens makes more sense to me. My approach is
           | that "code is truth, despite what the comment says", and
           | docstrings feel too much like comments, but I haven't used
           | Python professionally that much so I just may not be used to
           | those.
        
             | piperswe wrote:
             | I haven't used doctests in Python, but I have in Rust. It
             | really helps that any code blocks in a docstring is a
             | doctest by default, so they ensure that examples in your
             | documentation stay evergreen. It's nice to know that if
             | there's a code example in documentation, it will compile
             | and run properly and hasn't been broken.
        
               | Waterluvian wrote:
               | Practically speaking how useful are the Rust doctests?
               | 
               | I thought they looked like a genius idea but I don't get
               | how they work 95% of the time when examples don't come
               | with all the plumbing required to make valid state for a
               | function to actually work on.
        
               | justinpombrio wrote:
               | There's a feature for that: you prefix the plumbing with
               | `#`, and it runs in the doctest but doesn't render on the
               | doc page. https://doc.rust-
               | lang.org/rustdoc/documentation-tests.html#h...
        
               | Waterluvian wrote:
               | That would help. I'll have to experiment to better
               | understand if it all works well enough.
               | 
               | I'm thinking about Python unittest having setUp function
               | for preparing every test without repeating myself. Maybe
               | Rust has a similar way to define setup code for every
               | test.
        
           | adsharma wrote:
           | I'm looking to do something in this general area better than
           | doctests. Looking for collaborators.
           | 
           | http://adsharma.github.io/pysmt
        
         | scns wrote:
         | Elixir (Rust too IIRC) check code in doccomments for
         | correctness.
        
       | chajath wrote:
       | What pain point of Python as an education language is Pyret
       | trying to address? Union type might be vaguely useful, although
       | some of these use cases can be modelled as inheritance or typed
       | enums.
        
       | fnord77 wrote:
       | fun to-celsius(f):           (f - 32) * (5 / 9)         end
       | 
       | It looks like abbreviated python.
        
         | zucker42 wrote:
         | It's more functional than python. The data construct is similar
         | to variant types in OCaml.
        
           | scns wrote:
           | Yep, to me it looks like OCaml made prettier (scriptier?)
           | with ideas from Racket, Python and Ruby.
        
       | throw_m239339 wrote:
       | Never heard about it before, it looks well done.
       | 
       | Very interesting language.
       | 
       | First a great point about the homepage: it goes directly to
       | business, no marketing buzzwords, no stupid mascot, one glance at
       | that page and any developer gets a very good idea of what that
       | language does and doesn't.
       | 
       | Second yes, they are very interesting choices and functions.
       | 
       | However:
       | 
       | https://github.com/brownplt/pyret-lang
       | 
       | It's implemented in Javascript? This is a kind of no started for
       | the kind of app I do, personally. But as a stand alone language
       | which interpreter would be written in C/C++ and could be dropped
       | into an existing native app, it would be interesting.
        
         | skrishnamurthi wrote:
         | Well, actually, it's implemented in Pyret itself (-:.
         | 
         | But it currently compiles down to JavaScript. Our goal is to
         | create an awesome language for certain educational settings,
         | and many of our users (e.g., schools) are on restricted
         | machines that can't install desktop software. The browser is
         | the one platform they can easily access, and it also saves
         | teachers from turning into sysadmins (to install, upgrade,
         | etc.).
         | 
         | Hence our browser-based delivery. There is also a CLI. And _in
         | principle_ , someone could write a back-end that targets native
         | code, etc. We don't have the resources to do that right now
         | (but it's all Open Source).
        
       | smitty1e wrote:
       | +1 for the "lambda bones" logo.
        
         | [deleted]
        
         | scns wrote:
         | Her name is Bonnie. https://en.m.wikipedia.org/wiki/Anne_Bonny
        
       ___________________________________________________________________
       (page generated 2021-08-22 23:02 UTC)