5 ms·
Boilerplate busting in functional languages
- chowells 2y agoThis severely underestimates the weirdness of the visitor pattern. It's far more complicated than monads.
- Smaug123 2y agoI claim the visitor pattern isn't that weird. The `visit` function is the natural way to move from continuation-passing style to direct style, being of type signature `forall 'ret . (MyObject -> 'ret) -> 'ret`.
- mmaniac 2y agoExplanations of monads are vastly more complicated than monads. Any Javascript programmer will recognise what .flatMap() is and does - you don't even need to know design patterns for that.
- Smaug123 2y ago> So the wise soul does without doing, teaches without talking. Ursula Le Guin translating the Tao Te Ching, verse 2.
- munchler 2y ago> In languages that don’t have typeclasses, you need to take special steps to ensure that you dispatch to the proper variant of the monad. You might want to take a look at F#, which has no typeclasses (yet) but does have excellent first-class support for monadic syntax via "computation expressions". https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
- williamcotton 2y agoHere's something I whipped up to show an example of a ResultWriter monad using computation expressions in F#. I'm sure there are some slightly better interfaces than this, and I wouldn't mind a code review if anyone is feeling helpful! https://gist.github.com/williamcotton/95ebc21965e393f4c99a597b0c6f36cf https://gist.github.com/williamcotton/95ebc21965e393f4c99a59...
- fire_lake 2y agoYou can probably use a more efficient data structure than a singly linked list for logs Maybe a “string list list”?
- Smaug123 2y agoBy the way, a classic: > A functional programmer is one who calls their variables `f` and `x`, and their design patterns "zygohistomorphic prepromorphism".
- throwup238 2y agoMay their proverbs be as inscrutable as their code, amen.
- hi-v-rocknroll 2y agoSounds like some Dunning-Kruger inability to grasp how to solve the problem working with the tools rather than imposing their ideas that don't fit. If you need a "global mutable variable" in BEAM land, then you could just use a genserver or ETS. It depends if the solution needs to be a cluster-aware singleton or not. In the case of business logic and Elixir, this is where you may need to write your own DSL to model domain logic (DDD). It makes it makes things more flexible and more maintainable than piling together mud and hoping it won't fall over and that someone else in the future will be able to reason about it and maintain it.
- ashton314 2y agoI say "global mutable variable" to introduce the problem, followed by "global mutable state" in the summary of the first solution. The evil isn't a variable, it's just global mutable state in general. In cases where you need state, ETS and GenServers are good solutions—we agree there. But are you suggesting that the right way to solve this problem would be to spin up a GenServer every time you need to run what should be a pure function? I'd almost rather use the process dictionary! What I'm saying is, this problem shouldn't need state to solve it, therefore any introduction of state is a hack that will be a headache to maintain, test, and reason about. > In the case of business logic and Elixir, this is where you may need to write your own DSL to model domain logic (DDD). It makes it makes things more flexible and more maintainable than piling together mud and hoping it won't fall over and that someone else in the future will be able to reason about it and maintain it. I don't know what you're referring to here. What problem would a DSL solve (and how?), and what do you consider to be the mud that's being piled on?
- hi-v-rocknroll 2y agoHow else are you going to get global atomic, possibly highly-available share nothing mutable state? Magic? GenServers aren't difficult. Use the patterns rather than wincing or complaining about the lack of nonexistent wishes if you're not going to build a simpler solution. Business rules are often represented as an ordering of constraints and triggers in models when using DDD & MVC. One example in another language would be trailblazer.[0] Mud is when gobs of fragile, low-level of code is slapped together just to solve today's problem where everything is a special case without testability, architecture, standardization, or concern for maintenance or extensibility. See also: [1] 0. https://github.com/trailblazer/trailblazer https://github.com/trailblazer/trailblazer 1. https://en.wikipedia.org/wiki/Business_rules_engine https://en.wikipedia.org/wiki/Business_rules_engine
- recursive 2y ago> This could work, but the fact that we are using global mutable state ... What? Why would you consider using global state for this? I'd do it like this. Mutability without globals. export function transform(ast) { const queries = []; walk(ast.root, queries); return { ast, queries }; } function walk(node, queries) { // recursively called on child nodes // can mutate node, and append to queries } > Surprise! This is exactly the writer monad! This whole post has been a monad tutorial in disguise! Aha. That explains why it stopped making sense about 6 paragraphs ago.
- mrkeen 2y agoThe label 'global mutable state' has a slightly broader reach in FP. Just because you don't see a 'static int' hanging out in the space between methods doesn't mean that you haven't given the whole world mutable access into your state. walk can mutate node. transform can invoke walk. transform is public.
- recursive 2y ago> Whenever we call our transform function, we would have to ensure that we clear out the old list of accumulated information. This is why I presumed this post is using the popular understanding of the term. Anyway, nodes are only public if the calling code makes them public by leaking a reference or something. > Don’t forget about all the other problems that global mutable state brings. There must be a better way. When this blog says "global mutable state", then it must be referring to what's commonly understood to be "mutable state". It seems to be an article of faith that there must be a better way. To my sensibility, that is the best way. The argument seems to rest on some sleight-of-hand regarding "global".
- mrkeen 2y agoRemember 20 years ago, when getters and setters were all the rage? Reaching in to access variables was bad, but if you used a getter instead, then that was somehow good because you were doing encapsulation? IDEs gained the ability to generate your getters and setters for you, C# had properties which streamlined things and made Java look boilerplatey in comparison, and Java got Lombok. But it was all bullshit. If making fields private is 'locking the door', then adding getters and setters is 'leaving the key on top of the doormat'. Show me a logic bug caused by a global variable, I'll slap some getters and setters onto it, give it back to you, and it will still have the same logic bug. What's my point? It's not that FP has some competing definition of 'global variables' that somehow makes FP look good and imperative look bad, it's that FP actually followed the idea through to its logical conclusion and generalised it as 'shared mutable state', rather than slapping "encapsulation" on it and calling it a day. > Anyway, nodes are only public if the calling code makes them public by leaking a reference or something. This is true. However people commonly leak things by putting 'export' in front of them. Otherwise how can callers access them?