Skip to content

Instantly share code, notes, and snippets.

@elendiastarman
Last active January 15, 2016 04:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elendiastarman/545733ee55c2ba14e31a to your computer and use it in GitHub Desktop.
Save elendiastarman/545733ee55c2ba14e31a to your computer and use it in GitHub Desktop.
PyAcidic Musings

#PyAcidic Musings

[toc]

##Succinctness is Power

I like the idea of "succinctness is power", as discussed in this blog post. For me, what I picked up on was that succinctness doesn't necessarily mean brevity, but rather, how much can you say with a simple word or phrase. For example, the quadratic formula

$$\frac{-b \pm \sqrt{b^2-4ac}}{2a}$$

is a very succinct way to express the solution of a quadratic equation. Imagine if it was in words. Given a formula where you take a number, square it, multiply it by a constant, add to that the same number multiplied by another constant, and add a third constant ($ax^2+bx+c$), and where you want to know what numbers make this formula equal to zero ($ax^2+bx+c=0$ for what values of $x$?), then you can find these numbers by taking the negation of the second constant ($-b$), either adding or subtracting the square root of the second constant squared ($b^2$) minus four times the product of the first and third constants ($4ac$), and dividing the whole thing by double the first constant ($2a$).

Believe it or not, mathematicians used to solve these sorts of polynomial expressions in words, and creating, standardizing, and using a concise notation for this made it vastly easier to solve these sorts of problems.

Golfing languages can be -- and often are -- surprisingly powerful because they assign many common operations to only one or two characters. Aside from the basics, the most useful common operators tend to be stuff like map. Speaking of map, lemme take a little detour.

map can be a surprisingly powerful command for those who haven't used it (and maybe for those who have, too). It typically takes two arguments: a function, and a iterable (sequence). map then applies that function to every item in the iterable, and returns the resulting sequence. This is powerful because instead of manually writing out the loop and doing the bookkeeping required to handle the original and resulting sequences, you can let the language do it for you.

Let's take the example of squaring every integer in a list, say, X = [1, 2, -5, 8, 3]. Here's the typical way to do it (in Python):

Y = []
for x in X:
    Y.append(x**2)

Here's how it could be done with map:

Y = list(map(lambda x:x**2, X))

If you haven't used Python before (or if you have, but not map), you might be wondering why I have to specifically convert it to a list. The reason is that map returns a map object, which is a kind of generator, an object that produces subsequent items of a sequence on demand. This is advantageous in many cases because it means that the whole sequence doesn't have to be evaluated at once.

However, if you want to do any list operations, like indexing or slicing, you have to convert the map object to a list first. Wouldn't it be nice if you didn't have to do that? If generators behaved like lists most of the time? For that matter, wouldn't it be nice to just have a squaring function, so you could do something like

\map(\square(,[1,2,-5,8,3])

You'll note that I don't specify what each item in the sequence is named. That's because I'm assuming that the function is applied to each element in the sequence, so I don't need to name them.

What if I had more than just a singular integer? What if X = [(1,2),(3,4)] and I wanted to sum the squares of each integer in each pair? Well, that'd be...

\map(+\square(_)\square(_),[(1,2),(3,4)])

I'll explain the +\square(_)\square(_) part in a bit. This section is about "succinctness is power". So, map is one powerful tool. There are others. But I don't want to stop at operations. I want to include data structures in there too. Wouldn't it be great to have an orderedList type that automatically inserts anything you append in the right place to keep it ordered? Or a balancedTree type that automatically does all of the balancing stuff whenever you insert or remove elements?

Could this be done to algorithms too? Depth-first search and breadth-first search are common searching algorithms, and all that's needed is a description of the search space, how it's connected, where the start and end points are, and the weights of the edges and/or a cost function. I could have versions that are specific to square grids, or use that as the default.

One major component of programmer productivity is how much work they have to put into laying out the structure of a program, including all of the necessary bookkeeping. One of my goals is to drastically cut down the amount of bookkeeping necessary.

##Prefix notation

We normally do (for example) math like this: (3 + 5) * 8. This is called infix notation because the operations are between their operands. There are two other kinds: postfix notation and prefix notation. In the former, the above expression could be written thus: 835+* or 35+8* and for the latter, just reverse these expressions. I'll break it down.

*8+35
*(8)(+35)
*(8)(+(3)(5))

Or, in tree form...

  8
 /
*   3
 \ /
  +
   \
    5

This tree is then evaluated from the leaves back to the root. So first, 3 and 5 are added, resulting in 8.

  8
 /
*
 \
  8

Then these are multiplied together to give 64.

One great advantage of prefix (and postfix) notation is that parentheses are never needed to group operations and operands.

##Concise and verbose versions

One of the things I plan to do with this language is to make it so the actual language is in fact just a series of byte codes that would be gibberish if treated as ASCII, but the vast majority of programming would use a more verbose version that is tokenized to produce the concise version. Like the function \square( might be assigned the byte value 196, or rather, 0xC4. Thus, programs will be stored with far fewer bytes than it takes to write them. The IDE I develop for this language will of course have a function that translates back and forth.

##Malleable typing

Another goal I have is that you can do operations on different types in a sensible way for most pairs of types. For instance, you can take two functions f(x) and g(x), and when you multiply them (*fg), the result is another function h(x) that evaluates f(x)*g(x). You can then do +*fg5 to get yet another function j(x) that evaluates f(x)*g(x)+5. See what I just did? I added a function and a constant!

+5"hello" would result in "5hello". If f(x) = *x"hello ", then +f" world" would, given 3 as an argument, result in "hello hello hello world". The idea of "duck typing" is that basically that "if it looks like a duck, walks like a duck, and quacks like a duck, it's a duck". Hence, in Python, you can do such things as True + True and get 2, because True is equivalent to 1 in almost every circumstance. I aim to take this even further, hence the moniker "malleable typing". Basically, if there's a way to do it that makes sense, it can be done.

For those that really want to make sure that ints are ints, I do plan on providing \enforceType() for variables and \enforceTypeOn and \enforceTypeOff toggles. The examples I've provided above would be errors unless the variables and literals are cast to the appropriate type, and these casting functions will also be provided.

##Types

  • Number
  • Boolean
  • Integer
  • Float
  • Complex
  • Iterable
  • String
  • List
  • Set
  • Generator
  • Function
  • Block
  • Class
  • More to be added?

Written with StackEdit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment