Live data from Hacker News

FP-Go: Functional programming library for Golang

github.com

171–180 of 185 posts

Re: FP-Go: Functional programming library for Golang

#171
post #169

Earlier quoted context omitted.

> No, it is very much written from a consumer perspective. We're talking about from the producer perspective. This is just a lie. It's written about Go and doesn't split its perspectives, the producer should only ever return meaningful non-error values with an error if explicitly documented, and the consumer should only ever expect those when documented. > you point to a good example of where you can find un-meaningf…

> The slog package, brand new in 1.21, contains a MarshalText method At quick glance, I found three MarshalText implementations in the slog package. Which implementation are you referring to specifically? And, for what it is worth, none of them return useless values on error, so where do I find the fourth which does? > This, too, is simply a lie. Let's hope. I love nothing more than being wrong. That means I get to l…

You are now claiming that they are useful when you must discard them as useless when the error is non-nil. At least with you being caught in such a plain and clear lie I can be done with this.

>I love nothing more than being wrong.

That's odd, because you've contorted yourself into defending absurd positions based on personal definitions no one else shares, including the Go authors, just to avoid admitting you were wrong. The same Go authors responsible for both the proverbs, which you quote as gospel, and the style guide, which you claim doesn't apply when it's inconvenient because it directly contradicts your claims in plain english.

Re: FP-Go: Functional programming library for Golang

#172
post #171

Earlier quoted context omitted.

> The slog package, brand new in 1.21, contains a MarshalText method At quick glance, I found three MarshalText implementations in the slog package. Which implementation are you referring to specifically? And, for what it is worth, none of them return useless values on error, so where do I find the fourth which does? > This, too, is simply a lie. Let's hope. I love nothing more than being wrong. That means I get to l…

You are now claiming that they are useful when you must discard them as useless when the error is non-nil. At least with you being caught in such a plain and clear lie I can be done with this. > I love nothing more than being wrong. That's odd, because you've contorted yourself into defending absurd positions based on personal definitions no one else shares, including the Go authors, just to avoid admitting you were…

> You are now claiming that they are useful when you must discard them as useless when the error is non-nil.

Is it that you've confused implementation with interfaces? I would have to reject the values if received through the TextUnmarshaler interface, which defines MarshalText, as the implementation being called then becomes unknown, and therefore may not be idiomatic. If I was knowingly working with the three concrete types mentioned above then their function is documented.

> That's odd, because you've contorted yourself into defending absurd positions based on personal definitions no one else shares, including the Go authors, just to avoid admitting you were wrong

I mean, all you have to do is show some code which is reasonably considered idiomatic that does not return a useful value when in an error state and I'll be convinced; something you agreed was pertinent and useful when you brought up MarshalText.

The slog package is definitely reasonably considered idiomatic, so you are on the right track. Now you just need to be more specific at to which MarshalText method you are actually referring to. You called attention to it for good reason, no doubt. All we need, as there is more than one, is to know which one you meant specifically. It is a little odd you didn't do that in the first place, but I'm sure it was an accidental omission.

Re: FP-Go: Functional programming library for Golang

#173
post #163

Earlier quoted context omitted.

> means T is a meaningless default value Go Proverb #5: Make the zero value useful. > that should be ignored or a null pointer nil is the zero value of a pointer, so it should be made useful per the above, but it is also inherently useful even if you put no thought into it. It allows you to know that there is an absence of a value out of the box. And this is actually why the vast majority of (T, error) cases in idiom…

> Go Proverb #5: Make the zero value useful. Yeah, it's a nice quip, but that's all it is. It sounds nice on first read to someone who doesn't program much. But it is inaccurate and not followed by Go, and is explicitly against the Google style guide. The sophistry trying to paint a nil pointer as "useful" is just trying to defend a position you've dug yourself into in the process of this argument, so it doesn't real…

> The sophistry trying to paint a nil pointer as "useful" is just trying to defend a position you've dug yourself into in the process of this argument

You are right. I concede nil is not useful. Therefore, we agree that (T, error) cannot exist. As we see in the style guide: "Returning a nil error is the idiomatic way to signal a successful operation that could otherwise fail." This means there is no way to check the error condition. One might be tempted to write `if err != nil`, but because nil is not useful that obviously won't work. That would make nil a useful value, just as I once thought – incorrectly, as you helpfully made me realize – a nil T would be.

And as the Go style guide indicates that you cannot use the T value without first touching the error value, which is, for all practical purposes, impossible since the error value may not be useful, there is just no way this pattern can be used in any actual program.

> But it does match how (T, error) is actually used the majority of the time.

Right. As you have pointed out – of which I was reluctant to admit to, but you said it enough times that it must be true! – (T, error) cannot be used. Period. Its values do not convey the useful information required to be useable. Either does, then, indeed, match how (T, error) is used most of the time... which is to say not at all!

You mentioned something about MarshalText in the slog package showing how an idiomatic function with errors might actually be written, but then we realized that there are multiple implementations with the same name. Which one were you referring to?

Re: FP-Go: Functional programming library for Golang

#174
post #57
post #44

Earlier quoted context omitted.

Why, what's wrong with func TraverseParTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5,…

Exactly, I can’t wait to force this on my junior programmers and make them look stupid. cracks knuckles over keyboard

[deleted]

Re: FP-Go: Functional programming library for Golang

#175
post #163

Earlier quoted context omitted.

> Go Proverb #5: Make the zero value useful. Yeah, it's a nice quip, but that's all it is. It sounds nice on first read to someone who doesn't program much. But it is inaccurate and not followed by Go, and is explicitly against the Google style guide. The sophistry trying to paint a nil pointer as "useful" is just trying to defend a position you've dug yourself into in the process of this argument, so it doesn't real…

> The sophistry trying to paint a nil pointer as "useful" is just trying to defend a position you've dug yourself into in the process of this argument You are right. I concede nil is not useful. Therefore, we agree that (T, error) cannot exist. As we see in the style guide: "Returning a nil error is the idiomatic way to signal a successful operation that could otherwise fail." This means there is no way to check the…

>You are right. I concede nil is not useful.

You say this sarcastically, but it is actually true. A nil pointer is not useful. Once you have determined that a pointer is nil, you have confirmed that the function returning it at all was a waste of both space and time. Though it's actually only half true: nil pointers are worse than useless and they provide negative utility, because they allow invalid code to compile. A better design - which is also more efficient, even considering the overhead of tagged unions - is to not return the pointer/value at all if it would be useless. Other languages allow for this, even C does allow for it with manually tagged unions. Go is rather unique, especially among modern languages, in how it doesn't provide any mechanism for it, so people use what is available to emulate that.

For the rest of it, well, you've contorted yourself into some really interesting positions.

Re: FP-Go: Functional programming library for Golang

#176
post #175

Earlier quoted context omitted.

> The sophistry trying to paint a nil pointer as "useful" is just trying to defend a position you've dug yourself into in the process of this argument You are right. I concede nil is not useful. Therefore, we agree that (T, error) cannot exist. As we see in the style guide: "Returning a nil error is the idiomatic way to signal a successful operation that could otherwise fail." This means there is no way to check the…

> You are right. I concede nil is not useful. You say this sarcastically, but it is actually true. A nil pointer is not useful. Once you have determined that a pointer is nil, you have confirmed that the function returning it at all was a waste of both space and time. Though it's actually only half true: nil pointers are worse than useless and they provide negative utility, because they allow invalid code to compile.…

Exactly. (T, error) simply cannot be used in any real program. Like you say, if you try to use nil your program will crash, and error is asserted to be nil when there is no error, and you have to use that useless nil value in order to utilize T per the style guide, therefore your program will crash essentially all the time. It is impossible to write code that is valid if (T, error) is present.

It's not a question what is or isn't better. That's off-topic. It's just a question of how can we actually deal with the situation with the tools that Go gives us? MarhsalText no doubt contains the answers, but we aren't sure where to find it given the ambiguity. You went to all the trouble of looking it up to tell us about it, but now want to keep it a secret?

Re: FP-Go: Functional programming library for Golang

#177
post #97

I'm glad to see this idea getting some traction again. I haven't used Go much in the last few years, but I started playing around with a similar idea back in 2016 when I was working on a small compiler for a configuration management tool, and later put together a small stand-alone proof of concept library( https://github.com/rebeccaskinner/gofpher ) as part of a talk ( https://speakerdeck.com/rebeccaskinner/monadic-e…

Would be a lot more interesting with some usage examples or tests.

There exist at least some examples as part of the go docs, e.g. here https://pkg.go.dev/github.com/IBM/fp-go/either#pkg-examples or https://pkg.go.dev/github.com/IBM/fp-go@v1.0.19/array#pkg-ex... but there certainly could be more.

Are there any examples you'd be interested in in particular?

Re: FP-Go: Functional programming library for Golang

#178
post #55

Seriously, why? The only compelling argument for monadic effect systems I see is in languages with no easy-to-use and lightweight concurrency, and this is where Go shines. I thinks this is cool and all but I don't think it can ever be justified with this added complexity in Go. I have worked much with Cats Effect in Scala, which is nice but it adds some serious cognitive overhead.

One of the design aspects is to make a distinction between functions with and without side effects (pure). In a way to tell these apart by looking at the function signature without having to read the function body. The library uses a function signature without an input but with an output for this purpose. Aside from the trivial case of a constant function, such a signature can only mean that the function has side effects.

type IO[A any] func() A

If you consider this a valid approach, then the set of monadic helper functions make it easier to compose these effectful functions with pure functions.

This article https://betterprogramming.pub/investigating-the-i-o-monad-in... contains some more detailed reasoning.

Re: FP-Go: Functional programming library for Golang

#179
post #108
post #49

Earlier quoted context omitted.

data := F.Pipe3( T.MakeTuple2("https://jsonplaceholder.typicode.com/posts/1", "https://catfact.ninja/fact"), T.Map2(H.MakeGetRequest, H.MakeGetRequest), R.TraverseTuple2( readSinglePost, readSingleCatFact, ), R.ChainFirstIOK(IO.Logf[T.Tuple2[PostItem, CatFact]]("Log Result: %v")), ) This looks like a pain to modify if you're not intimately familiar with the fp-go library and are just trying to insert a debug statemen…

The real cheat of examples like this is using only existing functions. Once you add a closure with current Go syntax it goes to 11 on the hideous. There's some chat about adding some variant of (x, y => z) to Go, though even then you're adding some more symbols to an already symbol-heavy structure and it looks even worse when you're not using x y z but (username, accountId => a few lines of username and accountId bei…

I agree that the code will become unreadable as soon as you try to use inline functions (since there are no lambda expressions). However, the fp style (independent of this library) encourages to decompose the codebase into small and - if possible - pure functions. For testability. Once the code is structured that way, it's no longer a `cheat`, these pure functions can be used right away in function composition to create more complex structures.

Re: FP-Go: Functional programming library for Golang

#180
post #62
post #49

Earlier quoted context omitted.

data := F.Pipe3( T.MakeTuple2("https://jsonplaceholder.typicode.com/posts/1", "https://catfact.ninja/fact"), T.Map2(H.MakeGetRequest, H.MakeGetRequest), R.TraverseTuple2( readSinglePost, readSingleCatFact, ), R.ChainFirstIOK(IO.Logf[T.Tuple2[PostItem, CatFact]]("Log Result: %v")), ) This looks like a pain to modify if you're not intimately familiar with the fp-go library and are just trying to insert a debug statemen…

And, after all that, they don’t even handle the IO errors.

The example actually does handle all errors, because the values are of type `Either` and the composition functions take this into account. If you would like to handle a particular error sitation explicitly, e.g. to enrich it with context or to transform one error into another, you may use `MapLeft` or `Swap`.
Post reply on HN