3
lorentz
3y

Is there anything like React Context or Unix envvars in any functional language?

Not global mutable state, but variables with a global identity that I can set to a value for the duration of a function call to influence the behavior of all deeply nested functions that reference the same variable without having to acknowledge them.

Comments
  • 2
    Sounds so much like observer pattern.
  • 1
    @bittersweet to the rescue
  • 1
    @vintprox It solves a similar problem as observer, but observer itself hardly makes sense in FP because it forces you to store a list of applicatives in a state and at that point you've essentially reproduced OO programming just slower and less intuitive.
  • 4
    https://wiki.haskell.org/Top_level_...

    Haskell aficionados would say: This type of architecture is a symptom of bad design.
  • 1
    But the common way would be to wrap state in monads, and pass this to every affected function.

    If you have a game state, or a DOM, or anything of that kind, it would be passed around. Often using lenses to modify state.

    This also makes a language like Haskell perform badly on these kinds of topics.
  • 3
    The whole point of functional is input - > output. You're only dependent on explicit input state. No side effects, it's not just about "immutability". Setting a global value, regardless of whether it's mutable, would then have a side effect.
  • 3
    @atheist

    Yup.

    And that makes FP extremely suitable for ensuring data integrity.

    And to a degree, The GHC compiler is amazing at optimizing, and most applications will be on par with C in terms of performance.

    But still -- When the application grows, you'll notice that memory usage is high.

    I worked on a Pharmaceutical system in Haskell, which simulated enzyme interactions. Accuracy and bug resistance was important. They didn't bat an eye if you asked for 1000 Quadro graphics cards and servers with a TB of RAM each.

    Purity is a tradeoff. Immutability often means copying things in memory.

    So if your data walks & quacks like a global object... you might need a global object. Or at least a struct.

    For me personally, a language like Rust creates a great middle ground in that regard. It throws both OOP and FP out of the window in favor of a more pragmatic approach, with a balance between type safety, developer ergonomics and performance.
  • 0
  • 0
    @bittersweet I don't see how a monad would solve my problems. What I really want is to avoid argument drilling by passing a (regular, constant) parameter "to whom it may concern", that is, to any function called directly or indirectly by the currently called function that references this value. In other words:

    - I shouldn't have to know which functions will use the value, or whether it will be used at all
    - The functions that reference the value should be able to do so without changing their caller interface.
    - The functions that don't use the value shouldn't have to acknowledge its existence, or even the fact that some value is being passed from an indirect caller to an indirect callee

    For an example I really can't think of anything better than React Context or environment variables wrt. processes as functions.

    I realize this isn't a typical FP use case, but it would be a very useful escape hatch that doesn't completely break the language.
  • 0
    @lbfalvy one approach that should be possible in any functional language would be to have a global function that takes no input and returns the same value every call. This requires the variable to be a compile time constant, but that's somewhat implicit in the immutability. Haskell has global variables also, but require them to be compile time constant. https://wiki.haskell.org/Global_var...
  • 1
    @lbfalvy

    React is just "mutable global state with extra steps" —which is not possible in pure FP.

    Most FP languages, even Haskell, support impure/unsafe operations, so of course it can be hacked in.

    But in general, you'll need to pass your global "context" to functions.
  • 0
    @bittersweet Fair enough, context isn't mutable state though because it always has the same value when control enters and leaves a given function/component. For it to be mutable you have to re-render the provider, basically make a new call.
  • 1
    @lbfalvy

    Yeah like I said, global mutable state with extra steps 😂

    Pure FP simply doesn't allow it, as a harsh method of protecting data.

    Rust gets around this (safely!) with the concepts of "ownership" and "borrowing" of data, which works even in complicated concurrency scenarios.
Add Comment