Hacker News new | past | comments | ask | show | jobs | submit login
Pointless (ptls.dev)
222 points by hsartoris on April 10, 2020 | hide | past | favorite | 36 comments



This is pretty cool. After reading half the examples, I started wondering "wait what are you doing with the output variable", and then it clicked and I checked the docs, and yep, outputting to stdout is done by assignment to a magic `output` variable. A very interesting/novel approach to things.


Haskell is somewhat similar, too! I think some of this comes from C.

The goal of a Haskell compiler is to take your code and spit out an executable. That executable is in fact the value named “Main.main,” which must be of the in-Haskell type (translating to English) “a program which produces nothing.” In the source code you are constantly juggling values of type “a program which produces ____” and linking them together with the in-built methods, to get to this point, and the compiler just takes one of these things, based on a naming convention, and spits it out to the filesystem. And I think it got this convention because it was really handy how C similarly used a well-known name to specify its entry point into the source file.

The difference is then that Pointless does not have a type restriction on what “main” can be and instead of “saving to the filesystem” it dumps to stdout. Presumably with the right sort of metaprogramming attitude one could do what Haskell does in Pointless, maybe—when output is a program it could maybe spit out a compiled executable to stdout and you would redirect it to a disk location and set its executable permission manually.


Actually `main` in Haskell can be an IO action returning any type, eg this is a perfectly valid main:

    main :: IO Int
    main = print "10" >> pure 10
the return value is just ignored when it's actually invoked as an executable (but can be used if invoked eg. in the repl, or if main is also called from somewhere deeper in the code).


Classic BASIC implementation picked up on this idea. For instance some dialects had an INKEY$ variable which looks like a string, but magically reads console input.

GNU Bash has a magic variable RANDOM that produces random numbers. Assignments to it appear to be ignored.

In Algol, the name of the enclosing function acts as a variable to which you assign in order to produce the return value. For instance, see the assignment to B in the nested function here;

https://en.wikipedia.org/wiki/Man_or_boy_test


> GNU Bash has a magic variable RANDOM that produces random numbers. Assignments to it appear to be ignored.

Assignments are used to seed¹ the random number generator². This isn't limited to just bash/zsh/etc, it is intrinsic to the process of generating random numbers. Being aware of this is useful as it poses a significant footgun. The /dev/random docs³ provide a nice overview of how it is often handled on various systems at the OS level to deal with reboots.

An example of the fun that this can produce can be seen in a Debian bug⁴, running a script that uses subshells and RANDOM with bash will behave very differently when using zsh. In this instance you have to hope that subshells aren't being used to create unique logs as an example.

1. https://en.m.wikipedia.org/wiki/Random_seed

2. https://en.m.wikipedia.org/wiki/Random_number_generator

3. https://en.m.wikipedia.org/wiki//dev/random

4. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=828180


I remember from GW-BASIC there being, ERR, ERL, CSRLIN, and probably a few others. C64 BASIC V2.0 had ST and TI/TI$.

BASIC's version of $RANDOM is RND(x), and I remember that the sign of the argument was the most important thing. Negative values seeded the PRNG and any positive argument got you the next random number. Some later dialects had a RANDOMIZE statement.

The funny thing is BASIC also had a couple functions that took input variables, but didn't do anything with them, like POS() and FRE(). I think FRE's argument may have been significant on a couple BASICs.


Flashback! 7 year old me named my rabbit after the inkey variable.


Anyone remember the SNOBOL set of languages?


I used it in CS grad school in the early 70's. I have both books on it, including "The Macro Implementation of SNOBOL4."

I used it to write a go-moku (5-in-a-row) playing program in an AI course and got an A when it beat the professor.


Familiar but without hands-on experience. Read some reference manuals on it and code samples.

I recognized right away that the span and break pattern-matching operators of Snobol must be the inspiration behind C library names like strspn and strpbrk.


When I was in high school, I stumbled across the source code for cc on the UIC mainframe. Part of it was in either Snobol or Spitbol (I don't remember now) and I remember going to the library to get a book on the language to learn enough to be able to decipher the code.


Actually, something like this has been routinely done at the low level, especially when programming in assembly. (Also, trivially done in C++.)


Reminds me of LiveScript. Nowadays, you might be able to achieve something similar with JS + a bunch of Babel plugins, like pipeline operator and so.


Yes! LiveScript was so fun! I’m pretty sad none of the JS dialects from that time (CoffeeScript, ICS, Coco, LiveScript...) could hold a candle for how much TypeScript improves the experience; or that none could integrate it in a sensible fashion.


Saw |> in the example and came here to say the same thing! I used LiveScript for a while and it was very fun to use for personal projects.


I see shades of Oz [1], but that might just be my imagination.

[1]: http://mozart2.org/


How would you describe the difference between an Object and a Map in Pointless?

Having read the documentation, I don't see any difference other than whether non-string keys are allowed, and as a result the syntax for value access (`obj.key` vs `map["key"]`).

And one of the things I've been wondering about with regard to language design is why more languages don't take a Clojure-like approach of fully merging the concept of "object" and "map", since they seem to cover so much of the same ground.


Hello, I'm the author of this project: Pointless originally had a static type-system, which I later ditched (the type-system was pretty experimental, and I never got it working to my liking). So the object / map division is a holdover from that. I'll probably keep them separate for now to leave the option of static typing open, but I agree that it's a bit redundant for now. The only remaining technical differences are that maps can have other types like numbers and labels as keys, and objects can include function definitions.


It would be worth actually including that information about your type system in the docs. There's no mention of the language being statically or dynamically typed - which is a shame, because a scripting language with a static type system from the get-go would be novel in itself.


Stray thought while reading the documentation, inspired by how easy it is to convert a variable to a function: is there any reason to include a separate switch statement at all? It seems like you could use `if` there with a similar syntax:

  getSignZero(n) = if {
    n > 0 then Positive
    n < 0 then Negative
    else Zero
  }


Similar story as with objects - the switch statement originally existed to facilitate type-aware conditionals for statically checked algebraic data-types. At this point it's just syntactic sugar for a chain of conditionals. It might make sense to unify the two constructs - and I like the syntax you suggest


Or cond. Which is more like what you did. Not if, which is everywhere a binop. switch takes a block with seperate syntax, but cond just a list of expressions and statements.


thanks for the response!

to follow up on this, does this mean that Pointless actually allows inheritance and polymorphic dispatch? Because clearly functions are first class, so they could easily be values in a map just like they could live in an object.


Possibly because JS did that (it has been a thing since Self I think? Or maybe that was just the prototypal inheritance—I never can remember) and the confusion between the symbolic properties and the key properties kept coming up. Like, you have that x.abc is the same as x["abc"] but then things start to break because many dict objects have a .__proto__ or whatever and so they start to fail in interesting ways when you allow users to store their own strings in the keys and they overwrite something you were using later on.

JS now has a dedicated Map type to work as a proper dictionary.


> it has been a thing since Self I think? Or maybe that was just the prototypal inheritance

Just the inheritance.


These are some very clean examples. they pretty much read like piping commands and would be a good tool for teaching one or the other at the same time to someone new to both.


Wondering how pointless differed from Haskell, I looked up the syntax for composition and found

  compose(a, b) = x => a(b(x))
It's indeed more pointless than Haskell:-)

Btw, the `x' in that definition is the `point' from which the name originates.


I guess I'll be the first to mention how clever the name is.


Could you elaborate? I thought the name was a reference to a "point-free style" of piping commands. But maybe I am missing something more obvious?


Right, point-free style is a classic of functional programming, so to pick "Pointless" for a FP language is nice. One of those obvious-once-you-see-it things.


Yes, was hoping to see more point-free examples


And somehow, the first thing I think of is "you found that all-important pointless answer". :)


looks a lot like f#


Who else has otherwise instead of else? I don't get that


f# and .fsx/fsi scripting


I'm not super familiar with f#, but Pointless definitely takes inspiration from languages in the ML family, while only offering a small subset of their features. One of the questions I want to explore in this project is how programming language design can shape the learning process for beginners, centering on the idea that the features that a language chooses not to include are often key. I was pretty influenced by Mark Seemann's essay [0] on this idea.

[0] https://blog.ploeh.dk/2015/04/13/less-is-more-language-featu...




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: