Live data from Hacker News

How side effects work in FP

chadnauseam.com

51–60 of 107 posts

Re: How side effects work in FP

#51
> You're viewing my site on the centralized web. Check me out on the dweb ! (Warning: it's slow.)

It's really hard to take someone serious when they make big, untrue, statements saying the real web is "centralized" right on every page of their site, to peddle crypto scams.

https://chadnauseam.com/reasoning-quiz

> Neo-Nazis are holding a demonstration in a small town, waving swastikas around and shouting about Hitler. They seem to be pretty peaceful so far, so the First Amendment says you probably can’t get rid of them. However, their demonstration is near a main street and it could be a minor inconvenience to the traffic trying to go through.

>

> [ ] Allow the neo-Nazis to demonstrate.

>

> [ ] Break up the demonstration on the grounds of ‘blocking traffic’.

I am at a loss for words. Nazi sympathy under the guise of tolerance.

Re: How side effects work in FP

#52
post #22

Earlier quoted context omitted.

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 contr…

I do believe that monads are what made it possible to be referentially transparent not for just a subset, but the entire language. It's a good choice - it enforces equational reasoning, even for things like IO and "side effects". It is harder to write code like this, if you're not used to it, but i imagine that if you can, the code would be of higher quality.

Re: How side effects work in FP

#53
post #48

FP explanations like this annoy me: That is, this code: x = foo() y = bar(x) z = bar(x) Should mean the same thing as: y = bar(foo()) z = bar(foo()) Because it's obvious to anyone that has written any sort of complex program that those are not the same thing. foo() can be an expensive operation like an HTTP call. Or it might depend on a database which can change state underneath it. I assume FP has answers for these…

Actually in some FP languages like Haskell those two might be literally the same thing. When the compiler sees the second, it does the first (obviously over simplifying all over the place here, but that's the idea I think is being expressed).

Re: How side effects work in FP

#54
post #48

FP explanations like this annoy me: That is, this code: x = foo() y = bar(x) z = bar(x) Should mean the same thing as: y = bar(foo()) z = bar(foo()) Because it's obvious to anyone that has written any sort of complex program that those are not the same thing. foo() can be an expensive operation like an HTTP call. Or it might depend on a database which can change state underneath it. I assume FP has answers for these…

> Because it's obvious to anyone that has written any sort of complex program that those are not the same thing.

They are the same thing in Haskell (except for when forcing the thunks into eager values happens, due to the weirdness of laziness, but that has nothing to do with purity).

> I assume FP has answers for these things but the tutorials never cover them.

Except this one does:

> The

Re: How side effects work in FP

#55
post #48

FP explanations like this annoy me: That is, this code: x = foo() y = bar(x) z = bar(x) Should mean the same thing as: y = bar(foo()) z = bar(foo()) Because it's obvious to anyone that has written any sort of complex program that those are not the same thing. foo() can be an expensive operation like an HTTP call. Or it might depend on a database which can change state underneath it. I assume FP has answers for these…

Should mean the same thing as means has the same result value here. The operational semantics could be different, as you mention: even without side effects, computing x may be very expensive.

This isn’t even special to FP, it’s a basic problem when building a compiler, namely whether inlining/common subexpression elimination is beneficial.

To drive the point home, even in a language like Haskell these two examples might have a factor of two in execution time between them.

Re: How side effects work in FP

#57

The ligature makes the Haskell look even more magical, can't tell what I'd type to make that >>=== character.

It’s >>= but with a font very poorly chosen for a tutorial :-|

FWIW C and C++ also have this operator, it does bitwise right shift assignment there.

Re: How side effects work in FP

#58
post #48

FP explanations like this annoy me: That is, this code: x = foo() y = bar(x) z = bar(x) Should mean the same thing as: y = bar(foo()) z = bar(foo()) Because it's obvious to anyone that has written any sort of complex program that those are not the same thing. foo() can be an expensive operation like an HTTP call. Or it might depend on a database which can change state underneath it. I assume FP has answers for these…

> foo() can be an expensive operation like an HTTP call. Or it might depend on a database which can change state underneath it.

It can't, in Haskell, because it's a pure language. That's basically the definition of pure! But you still need effects, even in a "pure" language, and the whole point of the article is about how to support effects in a pure language.

Re: How side effects work in FP

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

Your example isn't entirely clear to me - do you mean that “I step forward” and “I try to shoot it” are instructions in sequence? What exactly do you mean with allowing the input to depend on the execution of the mutation instructions?

In any case, what I'm going for is that in both imperative and functional programming languages I would have a function/method like "handleInput" that takes an input and decides what to do with it. The difference would be that in a classical OOP setting handleInput would be a method of your GameState class [1] while in FP handleInput would look something like "Input -> (GameState -> GameState)", i.e. a function that takes an input value and returns a function that transforms the game state in some way (alternatively and equivalently, thanks to associativity/currying: a function that takes an input value and a current game state and returns a new game state).

[1] I know, this obviously is a very contrived example, it'd only work for very simple games. Game programming patterns are interesting but not the focus here.

Re: How side effects work in FP

#60
post #20

Something that I always found funny is that main clearly has to take something as input (otherwise it would not be able to produce different output between runs). So in GHC the main method (main :: IO()) internally takes a value of type RealWorld (theRealWorld) and returns the new RealWorld produced by running the program. I imagine by the time it's lowered to actual assembly they've dropped that, but I've never deal…

I am not at all an expert on GHC's codegen, but having glanced at that code before (mostly to get an intuition of what IO is under all that sugar), RealWorld doesn't even... exist. Realworld and its close friend, State# are tokens of sort. they're zero-sized and deeply magical (the GHC.Prim is quite enlightening to read). All the primops are defined as infinite loops... it's quite a sight to behold. As something totally unrelated to the above, a lot of the more internal GHC stuff (so the GHC.* modules, the stdlib/base, etc) are in my opinion readable and most of all, well commented, so it's quite fun to take a look sometimes.
Post reply on HN