Live data from Hacker News

Algebraic Effects for React Developers

reesew.io

61–70 of 98 posts

Re: Algebraic Effects for React Developers

#61
I would find it much simpler if the computational model of a DOM update is spelled out explicitly. Because, essentially, we are trying to update the DOM from a single thread - buried in callbacks and need some nifty libraries around that.

Re-frame's domino model is super easy to understand. There's no need to think about 'algebraic effects' or anything like that. Your event handlers returns effects which is data. That's it.

The world moves forward via

    Event dispatch
    Event handling
    Effect handling
    Query
    View
    DOM
That's about enough complexity to deal with manipulation of a tree structure and getting some callbacks.

At least - given I've followed basically all JS frameworks-du-jour since jQuery- this is the simplest model that allows for complex UIs I encountered. It certainly is opinionated and not completely pure - by design - but oh so sweet to work with.

Re: Algebraic Effects for React Developers

#62
post #27

Earlier quoted context omitted.

I run into this daily. There isn’t a single JS error in our monitoring that has a useful stack trace. It would have to extend another 30 layers down to start going into actual application components or code. They all look the same going through different bits of React internals.

I click on my errors and they take me to the exact line of code that caused them.... basically the JS error throws the line number and file path and then my terminal setup makes it clickable. Usually it’s always the same error anyways. Something is undefined or typed wrong.

I click on my errors and they take me to the exact line of code that caused them.... basically the JS error throws the line number and file path and then my terminal setup makes it clickable.

This highlights one of the biggest issues with React: usually it works really well, but if you're unlucky enough that it doesn't then there's almost no way to work out why. I've been developing with React for about 4 years and I just don't upgrade things in the ecosystem unless I absolutely have to, because debugging the tooling is a massive pain.

This is also why it's very unhelpful to say that it works. Yes, it usually does, but not always and failing to understand that comes across as somewhat antagonistic.

Re: Algebraic Effects for React Developers

#63
post #61

I would find it much simpler if the computational model of a DOM update is spelled out explicitly. Because, essentially, we are trying to update the DOM from a single thread - buried in callbacks and need some nifty libraries around that. Re-frame's domino model is super easy to understand. There's no need to think about 'algebraic effects' or anything like that. Your event handlers returns effects which is data. Tha…

> There's no need to think about 'algebraic effects' or anything like that.

Re-frame itself would disagree with you -- although that may be because it does its job well enough that you've not needed to worry about algebraic effects.

> Which brings us to the most important point: re-frame is impressively buzzword compliant. It has reactivity, unidirectional data flow, pristinely pure functions, interceptors, coeffects, conveyor belts, algebraic effects, statechart-friendliness and claims an immaculate hammock conception.

Also, this page of documentation calls out effects and coeffects.

https://day8.github.io/re-frame/EffectfulHandlers/#effects-a...

I'm not quite fluent enough in Clojure to follow the examples, but it does look quite cool.

Re: Algebraic Effects for React Developers

#64

Earlier quoted context omitted.

Pure functional languages such as Haskell have some facilities to do things that are not 100% pure, such as I/O. Similarly, OCaml has effects, but functional programmers minimize their use of such impure facilities. Effects in OCaml are impure: "However, the effect system also allows for tracking side-effects more generally. It distinguishes impure functions, which perform side-effects, from pure functions, which do…

> In Haskell impure functions are fenced off from pure functions That's a great way of explaining it. But at the same time how can we say that Haskell is a "pure functional language" when Haskell programs consist of both pure and impure functions? Yes they are separated which in other words means you do have both of them. Is that really "pure" then? Or is that more like 'as pure as possible"?

According to this definition a pure programming language could not have any side effect (Not very useful). Maybe as pure as possible is the only interpretation that makes sense, then.

Re: Algebraic Effects for React Developers

#65

I started learning React for starting a large project a few months ago. I have not really liked the experience very much. One seems to still need to know all the JS/CSS/HTML I've been using for 10+ years but also a new stack on top of it, simultaneously. Hooks are one of the strangest features I've seen in a language yet. I doubt they will be a lasting paradigm outside of the React ecosystem. I like JSX a lot. The id…

The value of hooks became apparent to me after working with a very large react-redux application. It was so large and the forms had so many elements that the capture of data, testing, and subsequent state management in redux was enormous. It wasn't overly complicated from a technical perspective, but when there were forms with say 50-100 different inputs and dozens of state transitions, it was a mentally taxing exper…

> For me the introduction of hooks was amazing as it's allowed us to strip most of the redux state management in favour of managing state with hooks inside of functional components. We still use redux for global application state, but there are also hooks for interacting with that redux state too.

I stopped writing React around the time Hooks came out, but I used to use a similar pattern with higher order components. In particular, I preferred HOC for forms. From what you're saying it sounds like hooks replaced a lot of that HOC functionality. Are HOC still used at all?

Re: Algebraic Effects for React Developers

#66

I started learning React for starting a large project a few months ago. I have not really liked the experience very much. One seems to still need to know all the JS/CSS/HTML I've been using for 10+ years but also a new stack on top of it, simultaneously. Hooks are one of the strangest features I've seen in a language yet. I doubt they will be a lasting paradigm outside of the React ecosystem. I like JSX a lot. The id…

The value of hooks became apparent to me after working with a very large react-redux application. It was so large and the forms had so many elements that the capture of data, testing, and subsequent state management in redux was enormous. It wasn't overly complicated from a technical perspective, but when there were forms with say 50-100 different inputs and dozens of state transitions, it was a mentally taxing exper…

While I totally agree that hooks reduce code size a lot, and have used them to great effect, the feeling that hooks are weird has not faded.

I know exactly what they do, and usually help co-workers with weird edge cases, but I still have a feeling that we could do better.

Anyway wanted to mention that since redux is so ridiculously tiny, its simple to actually nest it. Components can have local state, and only transmit global state on business related changes.

Now with hooks and useState thats a bit more ergonomic, but you could do that way before hooks were introduced.

Re: Algebraic Effects for React Developers

#67
post #66

Earlier quoted context omitted.

The value of hooks became apparent to me after working with a very large react-redux application. It was so large and the forms had so many elements that the capture of data, testing, and subsequent state management in redux was enormous. It wasn't overly complicated from a technical perspective, but when there were forms with say 50-100 different inputs and dozens of state transitions, it was a mentally taxing exper…

While I totally agree that hooks reduce code size a lot, and have used them to great effect, the feeling that hooks are weird has not faded. I know exactly what they do, and usually help co-workers with weird edge cases, but I still have a feeling that we could do better. Anyway wanted to mention that since redux is so ridiculously tiny, its simple to actually nest it. Components can have local state, and only transm…

I know what you mean to some extent. I feel hooks are very powerful but I think they are only a refinement on a fundamental problem which is handling reactivity in your view layer is always going to have issues. I would guess you kind of hit on something similar by having your localized Redux states.

Something I'm looking at right now is Effector. It encourages many smaller stores and allows for handling of effects quite easily. The smaller individual stores avoid the performance issues that people bring up often with Redux and I feel the API is more fluent, avoiding some of those boilerplate concerns, some of which are admittedly addressed by Redux Toolkit.

I'm not sure how my time with Effector is going to play out but I suspect it is at least the right idea. I wouldn't be surprised if a similar library came out that was embraced more by the community

Re: Algebraic Effects for React Developers

#68
post #65

Earlier quoted context omitted.

The value of hooks became apparent to me after working with a very large react-redux application. It was so large and the forms had so many elements that the capture of data, testing, and subsequent state management in redux was enormous. It wasn't overly complicated from a technical perspective, but when there were forms with say 50-100 different inputs and dozens of state transitions, it was a mentally taxing exper…

> For me the introduction of hooks was amazing as it's allowed us to strip most of the redux state management in favour of managing state with hooks inside of functional components. We still use redux for global application state, but there are also hooks for interacting with that redux state too. I stopped writing React around the time Hooks came out, but I used to use a similar pattern with higher order components.…

HOC have mostly fallen out of favour due to hooks. Typing hooks is a little easier than using HOC because you don't have to determine the type of your props which could conceivably be a combination of multiple HOC and the actual props your component expects. With hooks your props are your props which you have a simple interface for and then the hooks can be typed based on their parameters and what they return like any other function.

HOC are the more lispy/dynamic way of doing it I would say and in Clojurescript using Reagent it has always been common to use that general pattern I feel.

Re: Algebraic Effects for React Developers

#69

I've read a bit about algebraic effects in the past (independent of React), but I think they are much harder to grok than hooks. I tried many times but I never really got it. Like Haskell has this way of making you think you've got it for a split second, then you try to do something and you realise you don't have a clue. The effect systems using free monads seem to keep applying a functor to itself an unlimited amoun…

> The effect systems using free monads seem to keep applying a functor to itself an unlimited amount of times and I really didn't get it.

I can't help with the "effect systems" side of this, but I might be able to elucidate some of the recursive functor thing for you.

Suppose you've got a binary tree structure. In something like Haskell, you might model it like so:

    data BinaryTree t where
      InternalNode :: (BinaryTree t, BinaryTree t) -> BinaryTree t
      LeafNode :: t -> BinaryTree t
(I could have written this in Java, but I can't bear writing subclasses to make up for a lack of sum types. It looks pretty much the same in Rust, plus Boxes. In C++, this would be `class Node { std::variant* , Node* >> data; }`... or something like that.)

When I put a bunch of these nodes together, I get a binary tree. But maybe I want to store these nodes in a database, and I need to store them as rows in a table, where a node's children are given by foreign keys into the same table. I could write a whole new type for this...

    data RowNode t where
      InternalRow :: (Integer, Integer) -> RowNode t
      LeafRow :: t -> RowNode t
... but now I've duplicated the structure just to change the references. What if we take the child references as another type parameter?

    data NodeF t child where
      Internal :: (child, child) -> NodeF t child
      Leaf :: t -> NodeF t child
    
    type RowNode t = NodeF t Integer
    
    data BinaryTree t where
      MkBinaryTree :: (NodeF t (BinaryTree t)) -> BinaryTree t
Now I get my recursive trees and my flat tables out of the same basic "tile". NodeF is a functor (although I haven't said why, yet), and BinaryTree applies it to itself recursively (using Box as pointer indirection).

The MkBinaryTree constructor isn't doing anything special. It's just wrapping the given node into a new type, like how pointer indirection is necessary in C++ or Rust to avoid infinite-sized types. Similarly, Haskell doesn't allow recursive type aliases.

That's really the key point behind the recursive functors. We're extracting the "child" type out as a type parameter, and plugging it back in recursively to get our unbounded-depth tree back. Everything after this point is about what free monads add to this, which might be less interesting -- but I've already written it now, so whoops...

Why is NodeF a functor? I can write a function that takes a `NodeF t child` and a function from `child` to `stepchild`, swap the children out using the function, and produce a new `NodeF t stepchild`. That's just "fmap" -- and that's why we stuck an `F` on the name "NodeF", as a kind of Hungarian notation.

    instance Functor (NodeF t) where
      fmap f (Internal x y) = (Internal (f x) (f y)
      fmap f (Leaf t) = (Leaf t)
Now, if I pull a random definition of `Free f` from the webs...

    -- adapted from https://stackoverflow.com/a/13357359/159876
    data Free f a where
      Pure :: a -> Free f a
      Roll :: (f (Free f a)) -> Free f a
... and inline our `NodeF t` functor into it...

    data FreeNodeF t child where
      Pure :: child -> Free t child
      Roll :: (NodeF t (FreeNodeF t child)) -> FreeNodeF t child
The "Roll" variant is essentially the same as our BinaryTree construction, in that we can construct arbitrary binary trees with concrete values. The "Pure" variant lets us end the tree, but ending in a "child" instead of a leaf value. It'll be helpful to think of this more as a "pause" than as a "stop".

If the `child` is itself a `FreeNodeF t grandchild`, then the whole structure is a `FreeNodeF t (FreeNodeF t grandchild)`, and the canonical thing monads let us do is flatten the nested structure into a `FreeNodeF t grandchild`. In other words, we roll the `Pure` subtree over into the other variant.

The "impure" computation our `FreeNodeF` describes is essentially a branching computation. At each step, we can take a value and replace it with a tree of other values. The next step is performed on each of the values in the new subtree, and so on. At any point, each path can terminate in a final `t` value; but other paths might still keep going.

Essentially, we've structured our computation itself into a binary tree. The upshot is that the free monad lets you structure your computation into any template given by an appropriate functor. The paths through your structure trace the steps over time taken by your program.

Re: Algebraic Effects for React Developers

#70

I started learning React for starting a large project a few months ago. I have not really liked the experience very much. One seems to still need to know all the JS/CSS/HTML I've been using for 10+ years but also a new stack on top of it, simultaneously. Hooks are one of the strangest features I've seen in a language yet. I doubt they will be a lasting paradigm outside of the React ecosystem. I like JSX a lot. The id…

Hooks have a very nice synergy with Typescript. useEffect can be tricky to get right in some cases but overall a prefer writing in pure components with hooks over classes.

Just a slight nitpick about components with hooks. They are neither pure nor functional. They are function components. We can still have pure components without hooks but function components are no longer pure by default. Its actually one of the downsides of the move to hooks. It used to be very obvious when you needed to worry about state and when you didn't. However the benefits of hooks outweigh that nicety in my opinion
Post reply on HN