Live data from Hacker News

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

chrispenner.ca

61–70 of 102 posts

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

#61

So overly complicated. The "state of the art" of FP now means heavy type systems and heavy machinery to deal with them. The 80/20 pareto of FP is just pure functions + composing those functions and it works in any language. Here is all of it in python: from __future__ import print_function import json struct = json.loads(open('staff.json','r').read()) staff = struct['staff'] salaries = struct['salaries'] def visit_pe…

For me, the remaining power of optics (what you call 20%):

1. let the compiler reason about my code to catch errors when the requirement changes (say, when some record fields change their names or types),

2. thus lower my cognitive load, and

3. allow me to reason about more important aspects of the project.

At work, the use of a powerful and expressive type system allowed me to work on multiple projects at once, achieving at least 2 times boost in productivity (definitely more than 20% gain).

Moreover, if optics is not well-known to everyone, I can just link to this blog post as a documentation, and give more examples if needed (I think people underestimate how coworkers could be productive without completely understanding everything).

It is hard to explain the experience of “pair-programming with the compiler”, but such complication is worthwhile for the productivity gain (and developer happiness).

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

#62

So overly complicated. The "state of the art" of FP now means heavy type systems and heavy machinery to deal with them. The 80/20 pareto of FP is just pure functions + composing those functions and it works in any language. Here is all of it in python: from __future__ import print_function import json struct = json.loads(open('staff.json','r').read()) staff = struct['staff'] salaries = struct['salaries'] def visit_pe…

This is exactly how we shipped our JQ-like product feature in 62 lines of Clojure. Just pure functions composed into a single predicate and and a decent grammar to interpret the input JQ.

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

#63
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.

Because of "composability", even if the highly coupled functions will likely never be reused.

And leaky "abstractions" that create more problems than they solve but look cooler than doing things the straightforward way.

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

#64
post #14

Earlier quoted context omitted.

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.

List comprehensions aren't quite the same thing; they are declarative but they describe an iterative method of creating lists through maps and filters, whereas optics are semantically oriented around traversals and projections.

The nice thing about comprehensions is that, depending upon how one looks at them, they can be declaratively defined yet iteratively implemented.

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

#65
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 perfectly fine functional code you just wrote. Type system trickery can also be FP but a lot (most of?) practical FP code is written in dynamic FP languages like Clojure and Erlang and Elixir, or just Python, TypeScript, etc.

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

#66

So overly complicated. The "state of the art" of FP now means heavy type systems and heavy machinery to deal with them. The 80/20 pareto of FP is just pure functions + composing those functions and it works in any language. Here is all of it in python: from __future__ import print_function import json struct = json.loads(open('staff.json','r').read()) staff = struct['staff'] salaries = struct['salaries'] def visit_pe…

This example has nothing to do with type systems. The same system exists e.g. for Clojure (see Specter).

The fundamental idea behind the approach in the article is the following:

Treat the path through a nested data structure as a first-class thing.

This gives helps us mainly in two scenarios:

1. Allowing for easy field-update-like code to exist for immutable data structures in addition to mutable data structures. This is especially valuable for updates.

2. Unify everything that can be "field-like" under a consistent field syntax.

In most class-based languages we can write something like

    myObject.field0.subfield1.subsubfield2
but `field0.subfield1.subsubfield2` isn't a first-class item that we can pass around and use. We can certainly write something like the following:

    def myPath(someObject):
        return someObject.field0.subfield1.subsubfield2
but (to the first point) if someObject is deeply immutable, we can't use `myPath` to actually update `subsubfield2` and instead have to cumbersomely write out the entire reconstruction of an immutable data structure at every level.

To the second point, even if someObjet were mutable, there are a variety of things that would be nice to have as field accesses, but aren't, simply because they don't fit into a class definition. As an example, consider the bits of an integer.

    # Imagine .permissions.bitMask.lastBit to be a path 
    # through user
    set(user, .permissions.bitMask.lastBit, 0)
is so much nicer than the corresponding bit shifting code.

If path access through data were a first-class concept, there's no reason that paths should be restricted to only fields in classes. You can fit the same interface to anything that supports the notion of "field-like" access.

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

#67
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.

Simple?

I know it's easy to forget how much .. stuff .. there is in an imperative language. You have the side-effect in print, and if you replace that with appending a string you're going to invoke the weird and wonderful assignment operator.

It's easy to forget how strange these things (state and side effects) are once you have mastered them in your craft.

The reason I love functional style with immutable data is because it is so dead simple and easy on my tired brain.

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

#68

Optics, as the OP calls it, is definitely an underestimated problem of modern computing. So much work goes in most languages into processing nested data structures, especially in this day and age of heterogeneous APIs, and a lot of it is actually not that difficult to generalize conceptually into most languages. A few weeks ago I wrote a PoC in Python and it was remarkably easy to make a lens for traversing data stru…

Is using the word optics for other things than projecting light with glass a new thing? I do not recall seeing this word used for other purposes much say 10-15 years ago. Not a native English speaker but have read English for at least 30 years.

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

#70
post #7

This is a really exciting area. See also the Cambria project [1] and the HN discussion from yesterday [2]. See [3,4] for a great introduction to category theory for programmers--we are all indebted to Milewski / Fong / Spivak / et al. for making this topic more accessible. [1] https://www.inkandswitch.com/cambria.html [2] https://news.ycombinator.com/item?id=24699615 [3] https://bartoszmilewski.com/2014/10/28/categor…

Whenever I see Milewski’s name I immediately think of this video: https://youtu.be/ADqLBc1vFwI

It’s a shame I don’t know that many people who’d enjoy it as much as I do!

Post reply on HN