Jeremy Bowers

jerf.org · Personal blog · on HN since 2008

Jeremy Bowers writes about Go, functional programming, Haskell, and software design, including a monad tutorial and a Go supervisor-tree library.

What HN saysCommenters recommend his monad tutorial for people tired of tutorials, his functional programming lessons for imperative code, and a post on analyzing failures instead of blaming people.
78HN people shared it
36linked it in comments
66stories submitted
1.9Kstory points
3 months agolast shared
2008people per year2026

Most-shared posts

  1. 1
  2. 2
    Suture – Supervisor Trees for Go
    8 people · 247 points · first shared 2014 · 38 comments on HN
  3. 3
    Sum Types in Go
    6 people · 66 points · first shared 2013 · 36 comments on HN
  4. 4
    Why Go Getting Generics Will Not Change Idiomatic Go
    5 people · 7 points · first shared 2021 · discussion on HN
  5. 5
    Why I'm Interested in Haskell
    5 people · 7 points · first shared 2012 · discussion on HN
  6. 6
    Goto Is Not a Horror
    4 people · 61 points · first shared 2024 · 50 comments on HN
  7. 7
    Duck typing is safe (2020)
    4 people · 60 points · first shared 2020 · 79 comments on HN
  8. 8
    Understanding GPT a Bit Better
    4 people · 4 points · first shared 2023 · 1 comments on HN
  9. 9
    The Environment Object Pattern in Go
    4 people · 2 points · first shared 2014 · discussion on HN
  10. 10
    Applying Purity to the Imperative World
    4 people · 2 points · first shared 2025 · 1 comments on HN
  11. 11
    Some programming language ideas
    3 people · 253 points · first shared 2025 · 237 comments on HN
  12. 12
    Avoiding Reflection (And Such) in Go
    3 people · 121 points · first shared 2015 · 36 comments on HN
  13. 13
    Why do we still write insecure software?
    3 people · 70 points · first shared 2015 · 35 comments on HN
  14. 14
    Engineers are not fans of technologies
    3 people · 29 points · first shared 2024 · 8 comments on HN
  15. 15
    Don't repeat yourself and the strong law of small numbers
    3 people · 16 points · first shared 2024 · discussion on HN

What HN people wrote when they linked it

jerf · 2026-06-17
I think you'll find most of the people creating the HTTP proxy servers and brand new AI harnesses and git or ssh config managers and all of the other things that we already have way too many versions of are not our best software engineers anyhow. I like to analyze things in terms of how much of the real world they've encountered [1], and one of the reasons I would just put my own solutions together is a lot of these manifested major projects with huge lists of "features" have either one user, or in many cases, zero, which is to say even the author isn't actually using it, and I might as well put together my 1-user project myself. [1]: https://jerf.org/iri/post/2026/what_value_code_in_ai_era/
breadchris · 2025-04-20
great blog post! also this website has a lot of incredible posts, if you like learning about functional programming, you should check out https://jerf.org/iri/blogbooks/functional-programming-lessons-in-imper…
justinpombrio · 2024-06-02
Jerf wrote a great monad tutorial for people who have read too many monad tutorials (like this one): https://www.jerf.org/iri/post/2958/
Cthulhu_ · 2023-09-20
It's a tradeoff; I too find one-liner list comprehensions like simple transforms or filters easier to read than the for loop equivalent. However, it's a dangerous tool that some people just can't be trusted with. Second, if you go full FP style, then you can't just hire a Go developer, they need additional training to become productive. Here's an example of functional programming within Go taken far: https://github.com/IBM/fp-go/blob/main/samples/http/http_test.go. It basically adds a DSL on top of Go, which goes against its principles of simplicity. There was another great resource that explains why functional programming in Go is a Bad Idea; one is function syntax (there's no shorthand (yet?)), the other is performance (no tail call optimization), and another is Go's formatter will make it very convoluted; I think it was this one: https://www.jerf.org/iri/post/2955/
morelisp · 2022-08-03
If you're interested in learning from the issue, ask "what's wrong with X?", not "who did X?" In which case I'd recommend jerf's post at http://www.jerf.org/iri/post/2955, or my comments at https://news.ycombinator.com/item?id=30804253, or even just reasoning a bit from first principles about how intermediate slices would perform given Go's memory/execution model.
skybrian · 2022-03-28
Sum types are great in functional languages, but people are talking about using sum types in languages that don't natively support them. This blog post warns about misuse: Abuse Of Some Sum Types In OO Languages http://www.jerf.org/iri/post/2960
JoelMcCracken · 2021-10-05
IMO, the best articles I know of on monads, which take two very different approaches: - http://www.jerf.org/iri/post/2958 - https://philipnilsson.github.io/Badness10k/escaping-hell-with-monads/
jupp0r · 2018-04-27
Supervision trees have nothing to do with Actors or CSP. I can recommend reading the original papers. Golang not well supporting supervision trees has more to do with the runtime not allowing to kill a goroutine. See http://www.jerf.org/iri/post/2930
andreareina · 2017-12-07
The docs[1] do say that the last of a particular type wins, though as I say in [2] it's not clear to me whether that's actually desirable, or if it's essentially an implementation detail (process the arguments in order and mutate the object) that got blessed because it's easier that way. I'd love to hear arguments for last-write-wins over immutable assignment. It seems you can't implement custom interfaces on the core data types[3], so a do-nothing interface isn't an option to emulate sum types and enforce type-safety (E switches on string to set the error message). At least the code[4] gives you a run-time error instead of silently ignoring unsupported types. [1] https://godoc.org/upspin.io/errors#E [2] https://news.ycombinator.com/item?id=15870334 [3] http://www.jerf.org/iri/post/2917 [4] https://upspin.googlesource.com/upspin/+/master/errors/errors.go#154
enduser · 2011-03-15
Using content negotiation, I can--if the server supports it--take the same URI (e.g. http://www.jerf.org/) and pass it to an image viewer to see your face, to my address book to fetch your contact info, etc. Anything else requires the client knowing how to mangle URIs (e.g. adding /avatar.jpg, /contact.vcf).
lmz · 2010-11-18
"If AOL, my current delegate, decides to get out of the OpenID business entirely, one minute with vim on my website allows me to move it somewhere else, again, all along," I doubt that. "http://jerf.org is a string that you type into the OpenID box ("endpoint URL"?), not the ID itself. I use Google Apps and set my site up using an X-XRDS-Location header so I can type in "http://id.example.com into the box, but the identity the site gets is something like "http://example.com/openid?id=123456789. This identity will probably change if I switch to using AOL.
riobard · 2010-11-18
Not if the provider implements delegation properly. The identity string returned should be http://jerf.org in this case. The catch, however, is that many providers screw the identity up. For example I set up a page at http://foo.com with necessary headers to delegate to my Google Account. Using the OpenID support on App Engine, I get the federated identity as http://foo.com/openid?id=[SOME RANDOM DIGITS] instead. The idea of OpenID and delegation is awesome. In reality the millions different implementations fked up the whole thing, not even to mention the control and reliability issues.
dematz · 2026-03-22
Idk, while system architecture diagrams look cool and feel informative, I generally don't feel like they actually help you get started working somewhere on a project. Mistake #3 in this article, putting too much in, is part of this. So https://www.jerf.org/iri/post/2025/on_layers_and_boxes_and_lines/#diag… is an interesting take: put links in your diagram, so it functions as a table of contents. This seems most useful for someone who needs to start working on a project. Similarly https://haskellforall.com/2026/02/browse-code-by-meaning asks how to show what's in a repo, but maybe file tree is not best and a diagram with links as table of contents is the answer. That said practically speaking, I'm not sure what tooling easily creates working links in a diagram that looks good in any context, for instance mermaid might render on github but not a text editor. Of course for other purposes maybe just go crazy with the diagram. I once had a coworker draw this super detailed master diagram, maybe 50-100 things on it, which I was told impressed senior government officials (after my manager recolored all the red to avoid connoting errors). But for the purpose of orienting developers a table of contents with links sounds better.
brightball · 2016-12-19
I was getting ready to post the exact same thing. The built in event loop is major. Go did a lot of modelling from Erlang, but made tradeoffs that kept it closer to a C-style programming model. It's a great language and the limits of its concurrency model aren't something that will really be apparent to you if you haven't learned Erlang/Elixir. For most people, it provides a concurrency model that's a cut above everything else out there. The main differences in Go and BEAM languages (Erlang/Elixir) are cooperative vs prescheduling, shared memory vs immutable message passing, general garbage collection vs heap per process, and lastly general runtime vs isolation. Cooperative scheduling means that the scheduler has to have control relinquished back to it (such as with I/O events), while prescheduling will take back control. Cooperative means that you can get better end-to-end performance for a benchmark but you run the risk of a code taking over the processor. Prescheduling will allow consistent performance for all operations in the run time without allowing anything to overtake it. That's one of the ways that it's possible to reliably run a database within the runtime alongside the rest of your code on BEAM. Shared memory with pointers is pretty standard and definitely provides some performance perks, especially when dealing with large data structures. The flip side means that native clustering doesn't work. With BEAM languages that lack shared memory and rely on message…
lmm · 2014-08-29
> HN and the internet being what it is, I'm sure someone can pop up here with some horror story about when it happened to them, but I would contend that it's still something so unusual as to not be worth planning for. Maybe just a twinge in the gut if you really did declare an interface with just a Shoot of no parameters and no return value, but... if nothing else, in the Go world, the odds of you having a Camera.Shoot() and a Gun.Shoot() method are low anyhow, and the odds of them conflicting even lower. First you have to declare an interface that both of them fully implement. If you have a .Reload method on your gun, but not your camera, you can't accidentally cross them. If you have a .Reload method on both, but the Gun takes an Ammunition argument and the Camera takes a Film argument, they can't cross. And from a pure software-engineering perspective, you have to a have a program in which you are using the same exact word for two completely different concepts, which can happen, but is bad practice and still takes some work. Depends how you're using your types. E.g. one pattern I often use is wrapping up a String as a type so that I don't confuse two different domain-specific Strings - so I'll have something like: public class PhoneNumber { final String value; } public class EmailAddress { final String value; } (In Scala this is even easier, with @@) This is a really useful distinction to draw (in many ways it's more important than when…
warmfuzzykitten · 2011-04-30
Having just now taken delivery of a new technical book - Learn You a Haskell for Great Good! - I'm guessing that rumors of their death, as Mark Twain said about his own, are greatly exaggerated. I bought it on the basis of an online review that would inform this discussion. http://www.jerf.org/iri/post/2910 In the review, Jeremy Bowers discusses his own experience trying to learn Haskell over the past few years from the random bits and pieces that float about the web and how the careful development of ideas in this book "blew what turned out to be my rickety assemblage of concepts apart and replaced them with a solid understanding of what is going on with them, and why." We tend to forget that learning is not the same as carrying around a giant reference book. It's a painstakingly linear process where leaps of understanding happen only when a solid foundation is in place. Books and the linear style of books will always be with us, but to compete with instant search writers must learn to teach.
sn9 · 2025-04-15
Note that this post is the end of a larger series of posts, collected in one page here: https://jerf.org/iri/blogbooks/functional-programming-lessons-in-imper…
your_fin · 2025-04-14
The author addresses this nicely in an earlier part of the blog book: https://jerf.org/iri/post/2025/fp_lessons_purity/
jprete · 2023-02-13
martinhath · 2022-06-26
> This is perhaps too big a burden on a user. Some might say they rather not have the compositionality unless it's guaranteed to be correct. I think this is it. Or rather, I think to some people, myself included, compositionality should imply correctness. If you /can/ compose things, but the result is wrong, can you really say that you've got composition? How useful it is really to be able to plug in your own types in other peoples libraries if you have to trace through the execution of that library, figure out which libraries they transitively use, to ensure that all of your instantiations are sound? How do you even test this properly? It's a really hard problem, and from what I can tell, Julia gives you no tools to deal with this. [0] is probably relevant here, although I'm not sure I share the positive outlook. [0]: http://www.jerf.org/iri/post/2954
Zababa · 2021-10-19
I like this one: http://www.jerf.org/iri/post/2958. It's basically made for people like you, by focusing heavily on the what and the why. It assumes a bit of OO background though (iterators, interfaces).
pcr910303 · 2021-05-27
(Not directly related, but) The article reminds of a recent article named 'Why Go Getting Generics Will Not Change Idiomatic Go'[0]. Using functional programming in Go... just doesn't look right. Generics are useful, but won't change the whole Go ecosystem into FP. Maybe some uses of Map might make sense, but... idiomatic code will look the same. [0]: http://www.jerf.org/iri/post/2955
nyir · 2018-08-28
While as a fan of one particular language I tend to agree, I found http://www.jerf.org/iri/post/2908 a somewhat convincing argument that perhaps my view isn't so well-rounded as I thought.
nsm · 2017-11-10
http://www.jerf.org/iri/post/2930 is a really nice blog post from an Erlang programmer attempting to bring supervisor trees to Go as https://github.com/thejerf/suture.
andrewfromx · 2016-04-07
specially with this stuff http://www.jerf.org/iri/post/2930 https://github.com/thejerf/suture golang for the win!
elithrar · 2014-07-28
> I discovered there are better and more idiomatic ways to do this type if thing without resorting to dependency injection. Agreed. Write a constructor[1] for your "app" or "context" type, and pass it around as needed. You both get to avoid globals and any magic dependency injection. As a bit of shameless self-promotion, I wrote an article about how to achieve this when writing HTTP handlers in Go: http://elithrar.github.io/article/custom-handlers-avoiding-globals/ - hint: create a struct type that accepts a pointer to your app struct and your handler type/http.Handler, or create your handlers as methods on your app type. [1]: http://www.jerf.org/iri/post/2929
gtani · 2013-03-07
Craziness is not zero sum game, but it's hard to convince people that complain about "expression problem", "modular abstractions", "better DI", all the phrases to capture part of the problem, to read Real world haskell or Scala in Depth, both demanding books. jerf did a good writeup, maybe a little overboard on clispscript, but besides that http://www.jerf.org/iri/post/2908
llimllib · 2009-01-07
Which, of course, begs a link to jerf's critique of this idea: http://www.jerf.org/resources/xblinjs/whyNotMozilla/index.html . Have things changed since then, or are his complaints still valid? I, for one, am too scared of the wicked complexity and large memory overhead to try developing a XUL-based app. But I've only done a Hello World.
louthy · 2026-01-05
In C# you can implement SelectMany for a type and that gives this: from id in ParseId(inputId) from user in FindUser(id) from posts in FindPostsByUserId(id) from res in DeactivateDecision(user, posts) select res; It is the equivalent to do-notation (was directly inspired by it). Here's an example from the language-ext Samples [1], it's a game of 21/pontoon. > I wrote what you might call an acid test for monad implementations a while back: https://jerf.org/iri/post/2928/ It's phrased in terms of tutorials but it works for implementations as well; you should be able to transliterate the example into your monad implementation, and it ought to look at least halfway decent if it's going to be usable. If I try to implement the test from your blog with Seq type in language-ext (using C#), then I get: Seq<(int, string)> minimal(bool b) => from x in b ? Seq(1, 2) : Seq(3, 4) from r in x % 2 == 0 ? from y in Seq("a", "b") select (x, y) : from y in Seq("y", "z") select (x, y) select r; It yields: [(1, y), (1, z), (2, a), (2, b)] [(3, y), (3, z), (4, a), (4, b)] Which I think passes your test. [1] https://github.com/louthy/language-ext/blob/main/Samples/CardGame/Game…
Tainnor · 2025-04-15
You started out by saying 99% of web code is IO, then casually dropped down to 70-80%, as if that was the same thing. 20-30% of a huge codebase is still a significant amount. I've never said IO is irrelevant to web applications. But that in my experience, those 20-30% or whatever can be important, complex and time intensive (the Word generation was actually one od the most time consuming parts of the last application I worked on) enough that fencing them off from the side effecting code in some way can pay off (one way to do this without going fully PFP is outlined here: https://www.jerf.org/iri/post/2025/fp_lessons_purity/#fp-pure-core---i… > First one looks like meta programming. IO. You are programming something else. I don't understand what you're saying. I was working on a document management system whose contents were stored in tree structures. These structures routinely had to be transformed into other structures. That's a very algorithmic task where the IO can be fenced off very easily (and should be fenced off if only for the sake of easier unit testing). This was literally one of the most common things happening in the codebase. > Chatbots are high IO. in the sense that every useful program has IO. Otherwise, there's a whole bunch of transformations and intent recognition and skill dispatch and what not that happens between the request and the response, and that can happen entirely in memory on one machine (it can also be offloaded…

Keyboard shortcuts

/Search
j kNext / previous blog
EnterOpen selected blog
vVisit the blog site
fFollow / unfollow
lSwitch grid / list view
dSwitch dark mode
g hHome
g pTop posts
g tTopics
g fFollowing
g lLiked
g yHistory
g qFAQ
EscBack / close