Live data from Hacker News

Generalizing 'jq' and Traversal Systems using optics and standard monads

chrispenner.ca

11–20 of 102 posts

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#11
post #9

Why do you need all this theory when you can use simple imperative languages? for staff in company.staff: for pet in staff.pets: if pet.type == 'cat': print(pet.name + " belongs to " + staff.name) I don't understand why functional languages are used at all.

Functions are composable. Your statement is not. If I would ask you to create a snippet that searches for cats, another one that searches for dogs and a third one that searches for staff that owns both a cat and a dog you will either duplicate a lot of code or end up with functions.

Now if you restrict yourself to not introduce any side effects, the interpreter can be proven correct, the execution can be analysed much better and you can have some neat safety guarantees.

That's why.

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#12
post #9

Why do you need all this theory when you can use simple imperative languages? for staff in company.staff: for pet in staff.pets: if pet.type == 'cat': print(pet.name + " belongs to " + staff.name) I don't understand why functional languages are used at all.

To me the biggest advantage is expression. You can package up a whole traversal or other optics into a single expression and then you can give it a name, refer to it, augment it. For example what if later you'd like to add another `if` into the inner loop? Would you duplicate the code? Would you add a callback to the original imperative code? The big idea here is that access to some subpart of a big object (like a path) can be abstracted into its own expression type and made composable, and the less important idea is that it can also be well-typed.

The second advantage is conciseness. I don't know if you've actually used jq, but if you have, I really don't know why anyone prefers a verbose for-loop-and-if-statement block over a single concise jq expression. Paul Graham expressed this idea better than I could have so read this: http://www.paulgraham.com/power.html

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#13
post #9

Why do you need all this theory when you can use simple imperative languages? for staff in company.staff: for pet in staff.pets: if pet.type == 'cat': print(pet.name + " belongs to " + staff.name) I don't understand why functional languages are used at all.

That's more difficult to type than something like `.company.staff | .pets | flatten | filter .type == "cat" | log(...)`

Maybe so, but much easier to read. Code is read 10x more often than written, especially in teams, so it makes sense to optimize for legibility rather than elegance in some "higher" mindset, or less keys pressed (because most of the time will be spent staring at the line you wrote than actually typing if you write a functional line like that.)

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#14

Earlier quoted context omitted.

I wonder how these "optics" compare to .NET's Language Integrated Queries (LINQ) (see https://en.wikipedia.org/wiki/Language_Integrated_Query )

LINQ is definitely a precursor, and has tons of fantastic ideas. It's unfortunate that Microsoft didn't continue to invest heavily into this as it's rarely mentioned nowadays.

I'm not sure I'd call LINQ a precursor when LINQ itself was based on haskell's monadic list comprehensions.

monadic list comprehensions aren't quite the same thing as optics, however.

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#15
post #11
post #9

Why do you need all this theory when you can use simple imperative languages? for staff in company.staff: for pet in staff.pets: if pet.type == 'cat': print(pet.name + " belongs to " + staff.name) I don't understand why functional languages are used at all.

Functions are composable. Your statement is not. If I would ask you to create a snippet that searches for cats, another one that searches for dogs and a third one that searches for staff that owns both a cat and a dog you will either duplicate a lot of code or end up with functions. Now if you restrict yourself to not introduce any side effects, the interpreter can be proven correct, the execution can be analysed muc…

What's wrong with functions? A function `printCatsBelongingToStaff()` is much easier to read than a line of functional code.

I don't understand what you mean by "analyzed much better" and "neat safety guarantees". Is my code hard to analyze or unsafe?

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#16
post #13

Earlier quoted context omitted.

That's more difficult to type than something like `.company.staff | .pets | flatten | filter .type == "cat" | log(...)`

Maybe so, but much easier to read . Code is read 10x more often than written, especially in teams, so it makes sense to optimize for legibility rather than elegance in some "higher" mindset, or less keys pressed (because most of the time will be spent staring at the line you wrote than actually typing if you write a functional line like that.)

That's a bad argument because you didn't specify who the audience is. Functional code is more readable to me (and many teams I've worked with), imperative code is more readable to you and that's fine. Go with your team's preference. And, most of time, what your team prefers can easily be changed with a few sessions to introduce them to a functional style.

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#17
post #13

Earlier quoted context omitted.

That's more difficult to type than something like `.company.staff | .pets | flatten | filter .type == "cat" | log(...)`

Maybe so, but much easier to read . Code is read 10x more often than written, especially in teams, so it makes sense to optimize for legibility rather than elegance in some "higher" mindset, or less keys pressed (because most of the time will be spent staring at the line you wrote than actually typing if you write a functional line like that.)

I totally disagree. I can read the short version pretty quickly and get an idea what it does - every word matters.

The original version with for loops just looks like a block of text. Spacing would help, but I would still need to look carefully to pick out the important bits.

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#19
post #13

Earlier quoted context omitted.

That's more difficult to type than something like `.company.staff | .pets | flatten | filter .type == "cat" | log(...)`

Maybe so, but much easier to read . Code is read 10x more often than written, especially in teams, so it makes sense to optimize for legibility rather than elegance in some "higher" mindset, or less keys pressed (because most of the time will be spent staring at the line you wrote than actually typing if you write a functional line like that.)

It's a tradeoff. The problem is that academia often comes from the angle of abstracting and generalizing everything, which is even more harmful than copy & pasting and using the simplest code possible (mostly because copy & paste + simplest code is still readable and can be improved upon, while academic style code usually is inaccessible).

You don't want to listen to any specific camp. The best is always in the middle and you are on the right track:

"Pick what is easy to read."

However there is a caveat, which is that functional style is only hard to read at the beginning. Have a look at how modern languages integrate functional programming (see java, C#, C++, etc.).

Java streams are a common example. They make most code much easier to read ONCE you are used to it, because they provide standardized behaviour that is side-effect free. When you write everything in plain syntax, the reader needs to abstract your code in his head, while when using streams, you just know what `filter`, `map`, `reduce`, etc. do and you only need to look at the small customizations. It's easier to read once you are used to it.

However there is a limit and this limit get hit quickly. A lot of people like to make their code as complicated and fancy as possible and reduce every possible line. This is definitely wrong. Code must be easy to understand and change. If you fail that, you are doing it wrong.

This also depends on your environment. If your co-workers don't understand the code you write, you have failed, no matter if your code is "nicer" or not. You either need to write simpler code or educate your co-workers to create common ground.

Re: Generalizing 'jq' and Traversal Systems using optics and standard monads

#20
post #9

Why do you need all this theory when you can use simple imperative languages? for staff in company.staff: for pet in staff.pets: if pet.type == 'cat': print(pet.name + " belongs to " + staff.name) I don't understand why functional languages are used at all.

That's more difficult to type than something like `.company.staff | .pets | flatten | filter .type == "cat" | log(...)`

Wait a second, you left out the most important part: What's in the `log(...)` function? How do you get the name of the pet and the name of the staff in that line if they have the same accessor `.name`?

That's my point. The fact that you didn't include it implies to me that it was too difficult to figure out, and a true implementation would be far more complicated, so it's not a fair comparison.

Post reply on HN