Live data from Hacker News

Left to Right Programming

graic.net

171–180 of 372 posts

Re: Left to Right Programming

#171

One of the things I dislike about function notation is that in f(g(h())) execution order is right-to-left. I like OO partly because execution order is writing order ( h().g().f() ) In Clojure I love the threading macro which accomplishes the same: (-> (h) (g) (f))

Nim and other languages addressed that by making . akin to a pipe operator. It takes the left and sends it to the right, as the first argument

Re: Left to Right Programming

#172
Based on Haskell do-notation, Firefox's unfortunately withdrawn array comprehensions, and C# LINQ, I've been thinking about this:

    [for b in c
     let d = f(b) 
     for e in g if h else m 
     where p(d, e): b, d, e]
as alternative syntax to Python's

    ((b, d, e)
     for b in c
     for d in [f(b)]
     for e in (g if h else m)
     if p(d, e))
This solves five problems in Python listcomp syntax:

1. The one this article is about, which is also a problem in SQL, as juancn points out.

2. The discontinuous scope problem: in Python

    [Ξ for x in Γ for y in Λ]
x is in scope in Ξ and Λ but obviously not Γ. This is confusing and inconsistent.

3. The ambiguity between conditional-expression ifs and listcomp-filtering trailing ifs, which Python solves by outlawing the former (unless you add extra parens). This is confusing when you get a syntax error on the else, but there is no non-confusing solution except using non-conflicting syntax.

4. let. In Python you can write `for d in [f(b)]` but this is inefficient and borders on obfuscated code.

5. Tuple parenthesization. If the elements generated by your iteration are tuples, as they very often are, Python needs parentheses: [(i, c) for i, c in enumerate(s) if c in s]. That's because `[i, c` looks like the beginning of a list whose first two items are i and c. Again, you could resolve these conflicting partial parses in different ways, but all of them are confusing.

Re: Left to Right Programming

#173
post #78

Earlier quoted context omitted.

I don't know if result = (df .pipe(fun1, arg1=1) .pipe(fun2, arg2=2) ) is much less readable than result fun1(., arg1=1) |> fun2(., arg2=2) but I guess the R thing also works beyond dataframes which is pretty cool

The pipe operator uses what comes before as the first argument of the function. This means in R it would be: result fun1(arg1=1) |> fun2(arg2=2) Python doesn't have a pipe operator, but if it did it would have similar syntax: result = df |> fun1(arg1=1) |> fun2(arg2=2) In existing Python, this might look something like: result = pipe(df, [ (fun1, 1), (fun2, 2) ]) (Implementing `pipe` would be fun, but I'll leave it a…

Python supports a syntax like your first example by implementing the appropriate magic method for the desired operator and starting the chain with that special object. For example, using just a single pipe: https://flexiple.com/python/python-pipeline-operator

The functions with extra arguments could be curried, or done ad-hoc like lambda v: fun1(v, arg1=1)

Re: Left to Right Programming

#174
post #139
post #106

Earlier quoted context omitted.

My main caveat here, is that often the person starting a select knows what they want to select before they know where to select it from. To that end, having autocomplete for the sources of columns is far far more useful than autocomplete for columns from a source. I will also hazard a guess that the total number of columns most people would need autocomplete for are rather limited? Such that you can almost certainly…

Seems nonsensical. Column names have no meaning without the table. Table is the object, columns are the properties. What language goes Property.Object? All popular languages have this wrong?

Anytime you store a single property for all objects in an array or hash table, so, Fortran, BASIC, APL, Numpy, R, awk, and sometimes Perl. Parallel arrays are out of style but certainly not unheard of. They're the hot new thing in games programming, under the name "entity-component-system".

Even C when `property` is computed rather than materialized. And CLOS even uses that syntax for method invocation.

The only language I can think of that uses field(record) syntax for record field access is AT&T-syntax assembly.

Re: Left to Right Programming

#176
post #39

SQL shows it's age by having exactly the same problem. Queries should start by the `FROM` clause, that way which entities are involved can be quickly resolved and a smart editor can aid you in writing a sensible query faster. The order should be FROM -> SELECT -> WHERE, since SELECT commonly gives names to columns, which WHERE will reference. You could even avoid crap like `SELECT * FROM table`, and just write `FROM…

A nitpick: select doesn't declare fields for where. select declare fields for having. it's the schema that declares fields that can be used in where.

Re: Left to Right Programming

#177
post #72

The consensus here seems to be that Python is missing a pipe operator. That was one of the things I quickly learned to appreciate when transitioning from Mathematica to R. It makes writing data science code, where the data are transformed by a series of different steps, so much more readable and intuitive. I know that Python is used for many more things than just data science, so I'd love to hear if in these other co…

The pipe operator in R (really, tidyverse R, which might as well be its own language) is one of its "killer apps" for me. Working with data is so, so pleasant and easy. I remember a textbook that showed two ways of "coding" a cookie recipe:

bake(divide(add(knead(mix(flour, water, sugar, butter)),eggs),12),450,12)

versus

mix(flour, water, sugar, butter) %>% knead() %>% add(eggs) %>% divide(12) %>% bake(temp=450, minutes=12)

So much easier!

Re: Left to Right Programming

#178
post #39

SQL shows it's age by having exactly the same problem. Queries should start by the `FROM` clause, that way which entities are involved can be quickly resolved and a smart editor can aid you in writing a sensible query faster. The order should be FROM -> SELECT -> WHERE, since SELECT commonly gives names to columns, which WHERE will reference. You could even avoid crap like `SELECT * FROM table`, and just write `FROM…

This was a historical decision because SQL is a declarative language. I was confused for too long, I want to admit, about the SQL order: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT As a self-taught developer, I didn't know what I was missing, but now the mechanics seem clear, and if somebody really needs to handle SELECT with given names, then he should probably use CTE: WITH src AS (SELECT * FR…

> This was a historical decision because SQL is a declarative language

It would be equally declarative if FROM came first.

Re: Left to Right Programming

#180
post #78

Earlier quoted context omitted.

I don't know if result = (df .pipe(fun1, arg1=1) .pipe(fun2, arg2=2) ) is much less readable than result fun1(., arg1=1) |> fun2(., arg2=2) but I guess the R thing also works beyond dataframes which is pretty cool

The pipe operator uses what comes before as the first argument of the function. This means in R it would be: result fun1(arg1=1) |> fun2(arg2=2) Python doesn't have a pipe operator, but if it did it would have similar syntax: result = df |> fun1(arg1=1) |> fun2(arg2=2) In existing Python, this might look something like: result = pipe(df, [ (fun1, 1), (fun2, 2) ]) (Implementing `pipe` would be fun, but I'll leave it a…

>Implementing `pipe` would be fun, but I'll leave it as an exercise for the reader.

I like exercise:

https://gist.github.com/stuarteberg/6bcbe3feb7fba4dc2574a989...

Post reply on HN