Live data from Hacker News

How side effects work in FP

chadnauseam.com

31–40 of 107 posts

Re: How side effects work in FP

#31

> Equational Reasoning Probably the best reason to use FP imo. It just cuts out so much overhead when trying to read other people’s code.

A related advantage is expression-orientated code.

In ML languages, code forms a beautiful tree structure where you can see the binding definition of each binding by looking down and right.

    let x = 
      something
      really
      big 
      and 
      complicated
whereas in a language built around statements it will be scattered all over:

    let x = null;

    x = something();

    x = somethingElse(x);

    x = anotherThing(x);
In the first case the definition of x is in one indented block; you can read it and move on.

Re: How side effects work in FP

#32
I don't speak Rust well, but I can share my perspective from Clojure, where I tend to think in data. A program is a sequence of immutable functions taking input from the world and reducing that to instructions to mutate the world (aka side effects). The world here can also be some place that stores state. Ideally mutation is the last step of the pipeline, which takes the instructions and produces the side effects.

Or simply

input -> fn1 -> fn2 -> fnn -> mutate!

Where 'fn' are all immutable.

Re: How side effects work in FP

#33
post #14

Earlier quoted context omitted.

Not just similar. Promises are a monad. Though they don't strictly follow the monad laws as they are collapsing in JavaScript due to how Promise.resolve never allows a promise to resolve to a promise but only to the value of a promise.

I mean, as long as you have a flatMap/concatMap function JavaScript arrays are technically a monad too. But that is a practically meaningless thing to say. What we talk about when we have about monads is the highly generic interface coupled with the highly generic combinators. This is not something shared by arrays and promises. In other words, none of them are monads in any practically meaningful sense.

> I mean, as long as you have a flatMap/concatMap function JavaScript arrays are technically a monad too. But that is a practically meaningless thing to say.

It's not "practically meaningless"; it's depth-first-search logic programming (as per How to Replace Failure by a List of Successes https://rkrishnan.org/files/wadler-1985.pdf )

Re: How side effects work in FP

#34
post #24

Earlier quoted context omitted.

There is a reason for this, and it's not that Haskell is jumping through hoops unnecessarily. All those languages are strictly evaluated, which means that side effects are clearly localized in time and space, we know when and where they happen if we run the program. Haskell is lazy, and laziness doesn't go well together with ad-hoc side effects. Haskell evaluates expressions when the result is needed, and an expressi…

This sort of thing is where I detach from the idea that functional programming is the ultimate good as some advocates would push it: it's far too obvious that outside of narrow constraints, real hardware just isn't functional. No where was this more apparent in my career then when I was on a team of Scala-using FP programmers who were building part of a real hardware provisioning system (and the org structure tipped…

Heh, I'm currently experiencing the exact opposite in our Scala codebases. Unhandled exceptions everywhere, null pointers left-and-right, `if(myOptionalValue.isDefined) myOptionalValue.get` all over the place, etc.

I gave an internal talk about FP approaches like .map, .flatMap, etc. (as well as `Try[T]`). Although I didn't call it "FP", I called it "type-safe error handling" (i.e. `null` and `throw e` lie about their types, and are hence not type-safe)

Re: How side effects work in FP

#35
Oh, haven't seen a monad article in quite some time.

> Monads really are just a convenient way to build up action values

Except when they aren't, because lists/arrays (with map) and Maybe (with map) and .. are something totally different. And that's the problem with _all_ these monad tutorials/how-tos/...: the problem is, that monads (and functors) are not burritos or elephants but _both_. So they are hard to understand looking only at a single instance.

Btw. monads are not the only way FP deals with effects, see algebraic effects. https://github.com/yallop/effects-bibliography https://www.youtube.com/watch?v=DNp3ifNpgPM

Re: How side effects work in FP

#36

Well, that's the first time side effects in Haskell made sense to me. Well done. Not that I've ever seriously tried to learn Haskell, but in the past every time I've lazily come across an article about it it's always seemed like a bizarre confusing world, even though I know how functional programming (in the sense of purity) works. Now there's just one thing missing. We all know what this style of programming is. It'…

it's asynchronous programming with promises

Re: How side effects work in FP

#37

> Equational Reasoning Probably the best reason to use FP imo. It just cuts out so much overhead when trying to read other people’s code.

A related advantage is expression-orientated code. In ML languages, code forms a beautiful tree structure where you can see the binding definition of each binding by looking down and right. let x = something really big and complicated whereas in a language built around statements it will be scattered all over: let x = null; x = something(); x = somethingElse(x); x = anotherThing(x); In the first case the definition o…

I just did some PHP the other day and I stumbled on a structure I was happy to have forgotten:

something(x, result);

somethingElse(result, result2);

anotherThing(result2, result3);

with the occasional surprise mutation when you just have to do

something(x)

and x contains the result.

I also got caught recently with MomentJS with that one when doing mydate.add and discovering it also mutated the original instead of just returning the result.

I'm a very average programmer and far from a FP purist (I mostly use JS and Rails) and I'm surprised how much I now use some FP principles and how it feels very natural to me.

Re: How side effects work in FP

#38
post #22
post #18

Earlier quoted context omitted.

Somehow there is this school of thought that FP === Mirada/Haskell, go figure.

I guess they should describe FP as 'referentially transparent' or not. Haskell is referentially transparent, but you can't say the same for many other FP languages like erlang, or ocaml.

All the FP languages include a subset that is referentially transparent.

I do not consider the attempts of making the entire language referentially transparent and the exclusive use of lazy evaluation, like in Haskell, as being useful.

Obviously there are people who like these features and who use Haskell, but in any case whenever FP languages are mentioned they should not be reduced to those that have made the controversial Haskell choices.

Re: How side effects work in FP

#39

I don't speak Rust well, but I can share my perspective from Clojure, where I tend to think in data. A program is a sequence of immutable functions taking input from the world and reducing that to instructions to mutate the world (aka side effects). The world here can also be some place that stores state. Ideally mutation is the last step of the pipeline, which takes the instructions and produces the side effects. Or…

That model fits functional reasoning. It doesn’t fit all programs, though, as it doesn’t allow the input to depend on the _execution_ of the mutation instructions.

Example: input “I step forward”, output “monster appears”, next input “I try to shoot it”.

That second input wouldn’t be there if the output weren’t executed.

Re: How side effects work in FP

#40
post #39

I don't speak Rust well, but I can share my perspective from Clojure, where I tend to think in data. A program is a sequence of immutable functions taking input from the world and reducing that to instructions to mutate the world (aka side effects). The world here can also be some place that stores state. Ideally mutation is the last step of the pipeline, which takes the instructions and produces the side effects. Or…

That model fits functional reasoning. It doesn’t fit all programs, though, as it doesn’t allow the input to depend on the _execution_ of the mutation instructions. Example: input “I step forward”, output “monster appears”, next input “I try to shoot it”. That second input wouldn’t be there if the output weren’t executed.

Outputting and manipulating side-effects can be useful even in imperative code.

I had real performance problems a while back attempting to build a very large file, my code could only produce the write instructions out of order and the file was too big to hold in memory, so what I ended up doing was writing writing instructions in radix-grouped batches to a bunch of temporary files, and then reading and evaluating them to build the large file.

This seems counter-intuitive, as it more than doubles both the amount of data written to disk as well as adds a reading-step, but doing it this way means the data is written in a way the hardware can deal with a lot more efficiently. Sequential access to and from the instruction files (off a mechanical drive), and densely clustered writes to the big output file. (on an SSD, strictly sequential writes matters less than being in the same block)

This reduced the runtime from several hours to like 5 minutes.

Post reply on HN